gfx/ots/src/glyf.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial