LCOV - code coverage report
Current view: directory - gfx/ots/src - glyf.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 140 0 0.0 %
Date: 2012-06-02 Functions: 6 0 0.0 %

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

Generated by: LCOV version 1.7