Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2011 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 "gdef.h"
      6 
      7 #include <limits>
      8 #include <vector>
      9 
     10 #include "gpos.h"
     11 #include "gsub.h"
     12 #include "layout.h"
     13 #include "maxp.h"
     14 
     15 // GDEF - The Glyph Definition Table
     16 // http://www.microsoft.com/typography/otspec/gdef.htm
     17 
     18 namespace {
     19 
     20 // The maximum class value in class definition tables.
     21 const uint16_t kMaxClassDefValue = 0xFFFF;
     22 // The maximum class value in the glyph class definision table.
     23 const uint16_t kMaxGlyphClassDefValue = 4;
     24 // The maximum format number of caret value tables.
     25 // We don't support format 3 for now. See the comment in
     26 // ParseLigCaretListTable() for the reason.
     27 const uint16_t kMaxCaretValueFormat = 2;
     28 
     29 bool ParseGlyphClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
     30                              size_t length, const uint16_t num_glyphs) {
     31   return ots::ParseClassDefTable(data, length, num_glyphs,
     32                                  kMaxGlyphClassDefValue);
     33 }
     34 
     35 bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data,
     36                           size_t length, const uint16_t num_glyphs) {
     37   ots::Buffer subtable(data, length);
     38 
     39   uint16_t offset_coverage = 0;
     40   uint16_t glyph_count = 0;
     41   if (!subtable.ReadU16(&offset_coverage) ||
     42       !subtable.ReadU16(&glyph_count)) {
     43     return OTS_FAILURE();
     44   }
     45   const unsigned attach_points_end =
     46       2 * static_cast<unsigned>(glyph_count) + 4;
     47   if (attach_points_end > std::numeric_limits<uint16_t>::max()) {
     48     return OTS_FAILURE();
     49   }
     50   if (offset_coverage == 0 || offset_coverage >= length ||
     51       offset_coverage < attach_points_end) {
     52     return OTS_FAILURE();
     53   }
     54   if (glyph_count > num_glyphs) {
     55     OTS_WARNING("bad glyph count: %u", glyph_count);
     56     return OTS_FAILURE();
     57   }
     58 
     59   std::vector<uint16_t> attach_points;
     60   attach_points.resize(glyph_count);
     61   for (unsigned i = 0; i < glyph_count; ++i) {
     62     if (!subtable.ReadU16(&attach_points[i])) {
     63       return OTS_FAILURE();
     64     }
     65     if (attach_points[i] >= length ||
     66         attach_points[i] < attach_points_end) {
     67       return OTS_FAILURE();
     68     }
     69   }
     70 
     71   // Parse coverage table
     72   if (!ots::ParseCoverageTable(data + offset_coverage,
     73                                length - offset_coverage, num_glyphs)) {
     74     return OTS_FAILURE();
     75   }
     76 
     77   // Parse attach point table
     78   for (unsigned i = 0; i < attach_points.size(); ++i) {
     79     subtable.set_offset(attach_points[i]);
     80     uint16_t point_count = 0;
     81     if (!subtable.ReadU16(&point_count)) {
     82       return OTS_FAILURE();
     83     }
     84     if (point_count == 0) {
     85       return OTS_FAILURE();
     86     }
     87     uint16_t last_point_index = 0;
     88     uint16_t point_index = 0;
     89     for (unsigned j = 0; j < point_count; ++j) {
     90       if (!subtable.ReadU16(&point_index)) {
     91         return OTS_FAILURE();
     92       }
     93       // Contour point indeces are in increasing numerical order
     94       if (last_point_index != 0 && last_point_index >= point_index) {
     95         OTS_WARNING("bad contour indeces: %u >= %u",
     96                     last_point_index, point_index);
     97         return OTS_FAILURE();
     98       }
     99       last_point_index = point_index;
    100     }
    101   }
    102   return true;
    103 }
    104 
    105 bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
    106                             size_t length, const uint16_t num_glyphs) {
    107   ots::Buffer subtable(data, length);
    108   uint16_t offset_coverage = 0;
    109   uint16_t lig_glyph_count = 0;
    110   if (!subtable.ReadU16(&offset_coverage) ||
    111       !subtable.ReadU16(&lig_glyph_count)) {
    112     return OTS_FAILURE();
    113   }
    114   const unsigned lig_glyphs_end =
    115       2 * static_cast<unsigned>(lig_glyph_count) + 4;
    116   if (lig_glyphs_end > std::numeric_limits<uint16_t>::max()) {
    117     return OTS_FAILURE();
    118   }
    119   if (offset_coverage == 0 || offset_coverage >= length ||
    120       offset_coverage < lig_glyphs_end) {
    121     return OTS_FAILURE();
    122   }
    123   if (lig_glyph_count > num_glyphs) {
    124     OTS_WARNING("bad ligature glyph count: %u", lig_glyph_count);
    125     return OTS_FAILURE();
    126   }
    127 
    128   std::vector<uint16_t> lig_glyphs;
    129   lig_glyphs.resize(lig_glyph_count);
    130   for (unsigned i = 0; i < lig_glyph_count; ++i) {
    131     if (!subtable.ReadU16(&lig_glyphs[i])) {
    132       return OTS_FAILURE();
    133     }
    134     if (lig_glyphs[i] >= length || lig_glyphs[i] < lig_glyphs_end) {
    135       return OTS_FAILURE();
    136     }
    137   }
    138 
    139   // Parse coverage table
    140   if (!ots::ParseCoverageTable(data + offset_coverage,
    141                                length - offset_coverage, num_glyphs)) {
    142     return OTS_FAILURE();
    143   }
    144 
    145   // Parse ligature glyph table
    146   for (unsigned i = 0; i < lig_glyphs.size(); ++i) {
    147     subtable.set_offset(lig_glyphs[i]);
    148     uint16_t caret_count = 0;
    149     if (!subtable.ReadU16(&caret_count)) {
    150       return OTS_FAILURE();
    151     }
    152     if (caret_count == 0) {
    153       OTS_WARNING("bad caret value count: %u", caret_count);
    154       return OTS_FAILURE();
    155     }
    156 
    157     std::vector<uint16_t> caret_values;
    158     caret_values.resize(caret_count);
    159     uint16_t last_offset_caret = 0;
    160     unsigned caret_values_end = 2 * static_cast<unsigned>(caret_count) + 2;
    161     for (unsigned j = 0; j < caret_count; ++j) {
    162       if (!subtable.ReadU16(&caret_values[j])) {
    163         return OTS_FAILURE();
    164       }
    165       if (caret_values[j] >= length || caret_values[j] < caret_values_end) {
    166         return OTS_FAILURE();
    167       }
    168       // Caret offsets are in increasing coordinate order
    169       if (last_offset_caret != 0 && last_offset_caret >= caret_values[j]) {
    170         OTS_WARNING("offset isn't in increasing coordinate order: %u >= %u",
    171                     last_offset_caret, caret_values[j]);
    172         return OTS_FAILURE();
    173       }
    174       last_offset_caret = caret_values[j];
    175     }
    176 
    177     // Parse caret values table
    178     for (unsigned j = 0; j < caret_count; ++j) {
    179       subtable.set_offset(lig_glyphs[i] + caret_values[j]);
    180       uint16_t caret_format = 0;
    181       if (!subtable.ReadU16(&caret_format)) {
    182         return OTS_FAILURE();
    183       }
    184       // TODO(bashi): We only support caret value format 1 and 2 for now
    185       // because there are no fonts which contain caret value format 3
    186       // as far as we investigated.
    187       if (caret_format == 0 || caret_format > kMaxCaretValueFormat) {
    188         OTS_WARNING("bad caret value format: %u", caret_format);
    189         return OTS_FAILURE();
    190       }
    191       // CaretValueFormats contain a 2-byte field which could be
    192       // arbitrary value.
    193       if (!subtable.Skip(2)) {
    194         return OTS_FAILURE();
    195       }
    196     }
    197   }
    198   return true;
    199 }
    200 
    201 bool ParseMarkAttachClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
    202                                   size_t length, const uint16_t num_glyphs) {
    203   return ots::ParseClassDefTable(data, length, num_glyphs, kMaxClassDefValue);
    204 }
    205 
    206 bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data,
    207                                 size_t length, const uint16_t num_glyphs) {
    208   ots::Buffer subtable(data, length);
    209   uint16_t format = 0;
    210   uint16_t mark_set_count = 0;
    211   if (!subtable.ReadU16(&format) ||
    212       !subtable.ReadU16(&mark_set_count)) {
    213     return OTS_FAILURE();
    214   }
    215   if (format != 1) {
    216     OTS_WARNING("bad mark glyph set table format: %u", format);
    217     return OTS_FAILURE();
    218   }
    219 
    220   const unsigned mark_sets_end = 2 * static_cast<unsigned>(mark_set_count) + 4;
    221   if (mark_sets_end > std::numeric_limits<uint16_t>::max()) {
    222     return OTS_FAILURE();
    223   }
    224   for (unsigned i = 0; i < mark_set_count; ++i) {
    225     uint32_t offset_coverage = 0;
    226     if (!subtable.ReadU32(&offset_coverage)) {
    227       return OTS_FAILURE();
    228     }
    229     if (offset_coverage >= length ||
    230         offset_coverage < mark_sets_end) {
    231       return OTS_FAILURE();
    232     }
    233     if (!ots::ParseCoverageTable(data + offset_coverage,
    234                                  length - offset_coverage, num_glyphs)) {
    235       return OTS_FAILURE();
    236     }
    237   }
    238   file->gdef->num_mark_glyph_sets = mark_set_count;
    239   return true;
    240 }
    241 
    242 }  // namespace
    243 
    244 #define DROP_THIS_TABLE \
    245   do { file->gdef->data = 0; file->gdef->length = 0; } while (0)
    246 
    247 namespace ots {
    248 
    249 bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
    250   // Grab the number of glyphs in the file from the maxp table to check
    251   // GlyphIDs in GDEF table.
    252   if (!file->maxp) {
    253     return OTS_FAILURE();
    254   }
    255   const uint16_t num_glyphs = file->maxp->num_glyphs;
    256 
    257   Buffer table(data, length);
    258 
    259   OpenTypeGDEF *gdef = new OpenTypeGDEF;
    260   file->gdef = gdef;
    261 
    262   uint32_t version = 0;
    263   if (!table.ReadU32(&version)) {
    264     return OTS_FAILURE();
    265   }
    266   if (version < 0x00010000 || version == 0x00010001) {
    267     OTS_WARNING("bad GDEF version");
    268     DROP_THIS_TABLE;
    269     return true;
    270   }
    271 
    272   if (version >= 0x00010002) {
    273     gdef->version_2 = true;
    274   }
    275 
    276   uint16_t offset_glyph_class_def = 0;
    277   uint16_t offset_attach_list = 0;
    278   uint16_t offset_lig_caret_list = 0;
    279   uint16_t offset_mark_attach_class_def = 0;
    280   if (!table.ReadU16(&offset_glyph_class_def) ||
    281       !table.ReadU16(&offset_attach_list) ||
    282       !table.ReadU16(&offset_lig_caret_list) ||
    283       !table.ReadU16(&offset_mark_attach_class_def)) {
    284     return OTS_FAILURE();
    285   }
    286   uint16_t offset_mark_glyph_sets_def = 0;
    287   if (gdef->version_2) {
    288     if (!table.ReadU16(&offset_mark_glyph_sets_def)) {
    289       return OTS_FAILURE();
    290     }
    291   }
    292 
    293   unsigned gdef_header_end = 8;
    294   if (gdef->version_2)
    295     gdef_header_end += 2;
    296 
    297   // Parse subtables
    298   if (offset_glyph_class_def) {
    299     if (offset_glyph_class_def >= length ||
    300         offset_glyph_class_def < gdef_header_end) {
    301       return OTS_FAILURE();
    302     }
    303     if (!ParseGlyphClassDefTable(file, data + offset_glyph_class_def,
    304                                  length - offset_glyph_class_def,
    305                                  num_glyphs)) {
    306       DROP_THIS_TABLE;
    307       return true;
    308     }
    309     gdef->has_glyph_class_def = true;
    310   }
    311 
    312   if (offset_attach_list) {
    313     if (offset_attach_list >= length ||
    314         offset_attach_list < gdef_header_end) {
    315       return OTS_FAILURE();
    316     }
    317     if (!ParseAttachListTable(file, data + offset_attach_list,
    318                               length - offset_attach_list,
    319                               num_glyphs)) {
    320       DROP_THIS_TABLE;
    321       return true;
    322     }
    323   }
    324 
    325   if (offset_lig_caret_list) {
    326     if (offset_lig_caret_list >= length ||
    327         offset_lig_caret_list < gdef_header_end) {
    328       return OTS_FAILURE();
    329     }
    330     if (!ParseLigCaretListTable(file, data + offset_lig_caret_list,
    331                               length - offset_lig_caret_list,
    332                               num_glyphs)) {
    333       DROP_THIS_TABLE;
    334       return true;
    335     }
    336   }
    337 
    338   if (offset_mark_attach_class_def) {
    339     if (offset_mark_attach_class_def >= length ||
    340         offset_mark_attach_class_def < gdef_header_end) {
    341       return OTS_FAILURE();
    342     }
    343     if (!ParseMarkAttachClassDefTable(file,
    344                                       data + offset_mark_attach_class_def,
    345                                       length - offset_mark_attach_class_def,
    346                                       num_glyphs)) {
    347       DROP_THIS_TABLE;
    348       return true;
    349     }
    350     gdef->has_mark_attachment_class_def = true;
    351   }
    352 
    353   if (offset_mark_glyph_sets_def) {
    354     if (offset_mark_glyph_sets_def >= length ||
    355         offset_mark_glyph_sets_def < gdef_header_end) {
    356       return OTS_FAILURE();
    357     }
    358     if (!ParseMarkGlyphSetsDefTable(file,
    359                                     data + offset_mark_glyph_sets_def,
    360                                     length - offset_mark_glyph_sets_def,
    361                                     num_glyphs)) {
    362       DROP_THIS_TABLE;
    363       return true;
    364     }
    365     gdef->has_mark_glyph_sets_def = true;
    366   }
    367   gdef->data = data;
    368   gdef->length = length;
    369   return true;
    370 }
    371 
    372 bool ots_gdef_should_serialise(OpenTypeFile *file) {
    373   const bool needed_tables_dropped =
    374       (file->gsub && file->gsub->data == NULL) ||
    375       (file->gpos && file->gpos->data == NULL);
    376   return file->gdef != NULL && file->gdef->data != NULL &&
    377       !needed_tables_dropped;
    378 }
    379 
    380 bool ots_gdef_serialise(OTSStream *out, OpenTypeFile *file) {
    381   if (!out->Write(file->gdef->data, file->gdef->length)) {
    382     return OTS_FAILURE();
    383   }
    384 
    385   return true;
    386 }
    387 
    388 void ots_gdef_free(OpenTypeFile *file) {
    389   delete file->gdef;
    390 }
    391 
    392 }  // namespace ots
    393 
    394