LCOV - code coverage report
Current view: top level - gfx/ots/src - glyf.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 155 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2009 The Chromium Authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "glyf.h"
       6             : 
       7             : #include <algorithm>
       8             : #include <limits>
       9             : 
      10             : #include "head.h"
      11             : #include "loca.h"
      12             : #include "maxp.h"
      13             : 
      14             : // glyf - Glyph Data
      15             : // http://www.microsoft.com/typography/otspec/glyf.htm
      16             : 
      17             : #define TABLE_NAME "glyf"
      18             : 
      19             : namespace {
      20             : 
      21           0 : bool ParseFlagsForSimpleGlyph(ots::Font *font,
      22             :                               ots::Buffer *table,
      23             :                               uint32_t gly_length,
      24             :                               uint32_t num_flags,
      25             :                               uint32_t *flags_count_logical,
      26             :                               uint32_t *flags_count_physical,
      27             :                               uint32_t *xy_coordinates_length) {
      28           0 :   uint8_t flag = 0;
      29           0 :   if (!table->ReadU8(&flag)) {
      30           0 :     return OTS_FAILURE_MSG("Can't read flag");
      31             :   }
      32             : 
      33           0 :   uint32_t delta = 0;
      34           0 :   if (flag & (1u << 1)) {  // x-Short
      35           0 :     ++delta;
      36           0 :   } else if (!(flag & (1u << 4))) {
      37           0 :     delta += 2;
      38             :   }
      39             : 
      40           0 :   if (flag & (1u << 2)) {  // y-Short
      41           0 :     ++delta;
      42           0 :   } else if (!(flag & (1u << 5))) {
      43           0 :     delta += 2;
      44             :   }
      45             : 
      46           0 :   if (flag & (1u << 3)) {  // repeat
      47           0 :     if (*flags_count_logical + 1 >= num_flags) {
      48           0 :       return OTS_FAILURE_MSG("Count too high (%d + 1 >= %d)", *flags_count_logical, num_flags);
      49             :     }
      50           0 :     uint8_t repeat = 0;
      51           0 :     if (!table->ReadU8(&repeat)) {
      52           0 :       return OTS_FAILURE_MSG("Can't read repeat value");
      53             :     }
      54           0 :     if (repeat == 0) {
      55           0 :       return OTS_FAILURE_MSG("Zero repeat");
      56             :     }
      57           0 :     delta += (delta * repeat);
      58             : 
      59           0 :     *flags_count_logical += repeat;
      60           0 :     if (*flags_count_logical >= num_flags) {
      61           0 :       return OTS_FAILURE_MSG("Count too high (%d >= %d)", *flags_count_logical, num_flags);
      62             :     }
      63           0 :     ++(*flags_count_physical);
      64             :   }
      65             : 
      66           0 :   if ((flag & (1u << 6)) || (flag & (1u << 7))) {  // reserved flags
      67           0 :     return OTS_FAILURE_MSG("Bad glyph flag value (%d), reserved flags must be set to zero", flag);
      68             :   }
      69             : 
      70           0 :   *xy_coordinates_length += delta;
      71           0 :   if (gly_length < *xy_coordinates_length) {
      72           0 :     return OTS_FAILURE_MSG("Glyph coordinates length too low (%d < %d)", gly_length, *xy_coordinates_length);
      73             :   }
      74             : 
      75           0 :   return true;
      76             : }
      77             : 
      78           0 : bool ParseSimpleGlyph(ots::Font *font, const uint8_t *data,
      79             :                       ots::Buffer *table, int16_t num_contours,
      80             :                       uint32_t gly_offset, uint32_t gly_length,
      81             :                       uint32_t *new_size) {
      82           0 :   ots::OpenTypeGLYF *glyf = font->glyf;
      83             : 
      84             :   // read the end-points array
      85           0 :   uint16_t num_flags = 0;
      86           0 :   for (int i = 0; i < num_contours; ++i) {
      87           0 :     uint16_t tmp_index = 0;
      88           0 :     if (!table->ReadU16(&tmp_index)) {
      89           0 :       return OTS_FAILURE_MSG("Can't read contour index %d", i);
      90             :     }
      91           0 :     if (tmp_index == 0xffffu) {
      92           0 :       return OTS_FAILURE_MSG("Bad contour index %d", i);
      93             :     }
      94             :     // check if the indices are monotonically increasing
      95           0 :     if (i && (tmp_index + 1 <= num_flags)) {
      96           0 :       return OTS_FAILURE_MSG("Decreasing contour index %d + 1 <= %d", tmp_index, num_flags);
      97             :     }
      98           0 :     num_flags = tmp_index + 1;
      99             :   }
     100             : 
     101           0 :   uint16_t bytecode_length = 0;
     102           0 :   if (!table->ReadU16(&bytecode_length)) {
     103           0 :     return OTS_FAILURE_MSG("Can't read bytecode length");
     104             :   }
     105           0 :   if ((font->maxp->version_1) &&
     106           0 :       (font->maxp->max_size_glyf_instructions < bytecode_length)) {
     107           0 :     return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length);
     108             :   }
     109             : 
     110           0 :   const uint32_t gly_header_length = 10 + num_contours * 2 + 2;
     111           0 :   if (gly_length < (gly_header_length + bytecode_length)) {
     112           0 :     return OTS_FAILURE_MSG("Glyph header length too high %d", gly_header_length);
     113             :   }
     114             : 
     115           0 :   glyf->iov.push_back(std::make_pair(
     116           0 :       data + gly_offset,
     117           0 :       static_cast<size_t>(gly_header_length + bytecode_length)));
     118             : 
     119           0 :   if (!table->Skip(bytecode_length)) {
     120           0 :     return OTS_FAILURE_MSG("Can't skip bytecode of length %d", bytecode_length);
     121             :   }
     122             : 
     123           0 :   uint32_t flags_count_physical = 0;  // on memory
     124           0 :   uint32_t xy_coordinates_length = 0;
     125           0 :   for (uint32_t flags_count_logical = 0;
     126           0 :        flags_count_logical < num_flags;
     127             :        ++flags_count_logical, ++flags_count_physical) {
     128           0 :     if (!ParseFlagsForSimpleGlyph(font,
     129             :                                   table,
     130             :                                   gly_length,
     131             :                                   num_flags,
     132             :                                   &flags_count_logical,
     133             :                                   &flags_count_physical,
     134             :                                   &xy_coordinates_length)) {
     135           0 :       return OTS_FAILURE_MSG("Failed to parse glyph flags %d", flags_count_logical);
     136             :     }
     137             :   }
     138             : 
     139           0 :   if (gly_length < (gly_header_length + bytecode_length +
     140           0 :                     flags_count_physical + xy_coordinates_length)) {
     141           0 :     return OTS_FAILURE_MSG("Glyph too short %d", gly_length);
     142             :   }
     143             : 
     144           0 :   if (gly_length - (gly_header_length + bytecode_length +
     145           0 :                     flags_count_physical + xy_coordinates_length) > 3) {
     146             :     // We allow 0-3 bytes difference since gly_length is 4-bytes aligned,
     147             :     // zero-padded length.
     148           0 :     return OTS_FAILURE_MSG("Invalid glyph length %d", gly_length);
     149             :   }
     150             : 
     151           0 :   glyf->iov.push_back(std::make_pair(
     152           0 :       data + gly_offset + gly_header_length + bytecode_length,
     153           0 :       static_cast<size_t>(flags_count_physical + xy_coordinates_length)));
     154             : 
     155             :   *new_size
     156           0 :       = gly_header_length + flags_count_physical + xy_coordinates_length + bytecode_length;
     157             : 
     158           0 :   return true;
     159             : }
     160             : 
     161             : }  // namespace
     162             : 
     163             : namespace ots {
     164             : 
     165           0 : bool ots_glyf_parse(Font *font, const uint8_t *data, size_t length) {
     166           0 :   Buffer table(data, length);
     167             : 
     168           0 :   if (!font->maxp || !font->loca || !font->head) {
     169           0 :     return OTS_FAILURE_MSG("Missing maxp or loca or head table needed by glyf table");
     170             :   }
     171             : 
     172           0 :   OpenTypeGLYF *glyf = new OpenTypeGLYF;
     173           0 :   font->glyf = glyf;
     174             : 
     175           0 :   const unsigned num_glyphs = font->maxp->num_glyphs;
     176           0 :   std::vector<uint32_t> &offsets = font->loca->offsets;
     177             : 
     178           0 :   if (offsets.size() != num_glyphs + 1) {
     179           0 :     return OTS_FAILURE_MSG("Invalide glyph offsets size %ld != %d", offsets.size(), num_glyphs + 1);
     180             :   }
     181             : 
     182           0 :   std::vector<uint32_t> resulting_offsets(num_glyphs + 1);
     183           0 :   uint32_t current_offset = 0;
     184             : 
     185           0 :   for (unsigned i = 0; i < num_glyphs; ++i) {
     186           0 :     const unsigned gly_offset = offsets[i];
     187             :     // The LOCA parser checks that these values are monotonic
     188           0 :     const unsigned gly_length = offsets[i + 1] - offsets[i];
     189           0 :     if (!gly_length) {
     190             :       // this glyph has no outline (e.g. the space charactor)
     191           0 :       resulting_offsets[i] = current_offset;
     192           0 :       continue;
     193             :     }
     194             : 
     195           0 :     if (gly_offset >= length) {
     196           0 :       return OTS_FAILURE_MSG("Glyph %d offset %d too high %ld", i, gly_offset, length);
     197             :     }
     198             :     // Since these are unsigned types, the compiler is not allowed to assume
     199             :     // that they never overflow.
     200           0 :     if (gly_offset + gly_length < gly_offset) {
     201           0 :       return OTS_FAILURE_MSG("Glyph %d length (%d < 0)!", i, gly_length);
     202             :     }
     203           0 :     if (gly_offset + gly_length > length) {
     204           0 :       return OTS_FAILURE_MSG("Glyph %d length %d too high", i, gly_length);
     205             :     }
     206             : 
     207           0 :     table.set_offset(gly_offset);
     208             :     int16_t num_contours, xmin, ymin, xmax, ymax;
     209           0 :     if (!table.ReadS16(&num_contours) ||
     210           0 :         !table.ReadS16(&xmin) ||
     211           0 :         !table.ReadS16(&ymin) ||
     212           0 :         !table.ReadS16(&xmax) ||
     213           0 :         !table.ReadS16(&ymax)) {
     214           0 :       return OTS_FAILURE_MSG("Can't read glyph %d header", i);
     215             :     }
     216             : 
     217           0 :     if (num_contours <= -2) {
     218             :       // -2, -3, -4, ... are reserved for future use.
     219           0 :       return OTS_FAILURE_MSG("Bad number of contours %d in glyph %d", num_contours, i);
     220             :     }
     221             : 
     222             :     // workaround for fonts in http://www.princexml.com/fonts/
     223           0 :     if ((xmin == 32767) &&
     224           0 :         (xmax == -32767) &&
     225           0 :         (ymin == 32767) &&
     226           0 :         (ymax == -32767)) {
     227           0 :       OTS_WARNING("bad xmin/xmax/ymin/ymax values");
     228           0 :       xmin = xmax = ymin = ymax = 0;
     229             :     }
     230             : 
     231           0 :     if (xmin > xmax || ymin > ymax) {
     232           0 :       return OTS_FAILURE_MSG("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin, ymin, xmax, ymax, i);
     233             :     }
     234             : 
     235           0 :     unsigned new_size = 0;
     236           0 :     if (num_contours >= 0) {
     237             :       // this is a simple glyph and might contain bytecode
     238           0 :       if (!ParseSimpleGlyph(font, data, &table,
     239             :                             num_contours, gly_offset, gly_length, &new_size)) {
     240           0 :         return OTS_FAILURE_MSG("Failed to parse glyph %d", i);
     241             :       }
     242             :     } else {
     243             :       // it's a composite glyph without any bytecode. Enqueue the whole thing
     244           0 :       glyf->iov.push_back(std::make_pair(data + gly_offset,
     245           0 :                                          static_cast<size_t>(gly_length)));
     246           0 :       new_size = gly_length;
     247             :     }
     248             : 
     249           0 :     resulting_offsets[i] = current_offset;
     250             :     // glyphs must be four byte aligned
     251             :     // TODO(yusukes): investigate whether this padding is really necessary.
     252             :     //                Which part of the spec requires this?
     253           0 :     const unsigned padding = (4 - (new_size & 3)) % 4;
     254           0 :     if (padding) {
     255           0 :       glyf->iov.push_back(std::make_pair(
     256           0 :           reinterpret_cast<const uint8_t*>("\x00\x00\x00\x00"),
     257           0 :           static_cast<size_t>(padding)));
     258           0 :       new_size += padding;
     259             :     }
     260           0 :     current_offset += new_size;
     261             :   }
     262           0 :   resulting_offsets[num_glyphs] = current_offset;
     263             : 
     264           0 :   const uint16_t max16 = std::numeric_limits<uint16_t>::max();
     265           0 :   if ((*std::max_element(resulting_offsets.begin(),
     266           0 :                          resulting_offsets.end()) >= (max16 * 2u)) &&
     267           0 :       (font->head->index_to_loc_format != 1)) {
     268           0 :     OTS_WARNING("2-bytes indexing is not possible (due to the padding above)");
     269           0 :     font->head->index_to_loc_format = 1;
     270             :   }
     271             : 
     272           0 :   font->loca->offsets = resulting_offsets;
     273           0 :   return true;
     274             : }
     275             : 
     276           0 : bool ots_glyf_should_serialise(Font *font) {
     277           0 :   return font->glyf != NULL;
     278             : }
     279             : 
     280           0 : bool ots_glyf_serialise(OTSStream *out, Font *font) {
     281           0 :   const OpenTypeGLYF *glyf = font->glyf;
     282             : 
     283           0 :   for (unsigned i = 0; i < glyf->iov.size(); ++i) {
     284           0 :     if (!out->Write(glyf->iov[i].first, glyf->iov[i].second)) {
     285           0 :       return OTS_FAILURE_MSG("Falied to write glyph %d", i);
     286             :     }
     287             :   }
     288             : 
     289           0 :   return true;
     290             : }
     291             : 
     292           0 : void ots_glyf_reuse(Font *font, Font *other) {
     293           0 :   font->glyf = other->glyf;
     294           0 :   font->glyf_reused = true;
     295           0 : }
     296             : 
     297           0 : void ots_glyf_free(Font *font) {
     298           0 :   delete font->glyf;
     299           0 : }
     300             : 
     301             : }  // namespace ots
     302             : 
     303             : #undef TABLE_NAME

Generated by: LCOV version 1.13