tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gsub.cc (18219B)


      1 // Copyright (c) 2011-2017 The OTS 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 "gsub.h"
      6 
      7 #include <limits>
      8 #include <vector>
      9 
     10 #include "layout.h"
     11 #include "maxp.h"
     12 
     13 // GSUB - The Glyph Substitution Table
     14 // http://www.microsoft.com/typography/otspec/gsub.htm
     15 
     16 #define TABLE_NAME "GSUB"
     17 
     18 namespace {
     19 
     20 enum GSUB_TYPE {
     21  GSUB_TYPE_SINGLE = 1,
     22  GSUB_TYPE_MULTIPLE = 2,
     23  GSUB_TYPE_ALTERNATE = 3,
     24  GSUB_TYPE_LIGATURE = 4,
     25  GSUB_TYPE_CONTEXT = 5,
     26  GSUB_TYPE_CHANGING_CONTEXT = 6,
     27  GSUB_TYPE_EXTENSION_SUBSTITUTION = 7,
     28  GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE = 8,
     29  GSUB_TYPE_RESERVED = 9
     30 };
     31 
     32 bool ParseSequenceTable(const ots::Font *font,
     33                        const uint8_t *data, const size_t length,
     34                        const uint16_t num_glyphs) {
     35  ots::Buffer subtable(data, length);
     36 
     37  uint16_t glyph_count = 0;
     38  if (!subtable.ReadU16(&glyph_count)) {
     39    return OTS_FAILURE_MSG("Failed to read glyph count in sequence table");
     40  }
     41  if (glyph_count > num_glyphs) {
     42    return OTS_FAILURE_MSG("bad glyph count %d > %d", glyph_count, num_glyphs);
     43  }
     44  for (unsigned i = 0; i < glyph_count; ++i) {
     45    uint16_t substitute = 0;
     46    if (!subtable.ReadU16(&substitute)) {
     47      return OTS_FAILURE_MSG("Failed to read substitution %d in sequence table", i);
     48    }
     49    if (substitute >= num_glyphs) {
     50      return OTS_FAILURE_MSG("Bad substitution (%d) %d > %d", i, substitute, num_glyphs);
     51    }
     52  }
     53 
     54  return true;
     55 }
     56 
     57 bool ParseAlternateSetTable(const ots::Font *font,
     58                            const uint8_t *data, const size_t length,
     59                            const uint16_t num_glyphs) {
     60  ots::Buffer subtable(data, length);
     61 
     62  uint16_t glyph_count = 0;
     63  if (!subtable.ReadU16(&glyph_count)) {
     64    return OTS_FAILURE_MSG("Failed to read alternate set header");
     65  }
     66  if (glyph_count > num_glyphs) {
     67    return OTS_FAILURE_MSG("Bad glyph count %d > %d in alternate set table", glyph_count, num_glyphs);
     68  }
     69  for (unsigned i = 0; i < glyph_count; ++i) {
     70    uint16_t alternate = 0;
     71    if (!subtable.ReadU16(&alternate)) {
     72      return OTS_FAILURE_MSG("Can't read alternate %d", i);
     73    }
     74    if (alternate >= num_glyphs) {
     75      return OTS_FAILURE_MSG("Too large alternate: %u", alternate);
     76    }
     77  }
     78  return true;
     79 }
     80 
     81 bool ParseLigatureTable(const ots::Font *font,
     82                        const uint8_t *data, const size_t length,
     83                        const uint16_t num_glyphs) {
     84  ots::Buffer subtable(data, length);
     85 
     86  uint16_t lig_glyph = 0;
     87  uint16_t comp_count = 0;
     88 
     89  if (!subtable.ReadU16(&lig_glyph) ||
     90      !subtable.ReadU16(&comp_count)) {
     91    return OTS_FAILURE_MSG("Failed to read ligature table header");
     92  }
     93 
     94  if (lig_glyph >= num_glyphs) {
     95    return OTS_FAILURE_MSG("too large lig_glyph: %u", lig_glyph);
     96  }
     97  if (comp_count == 0) {
     98    return OTS_FAILURE_MSG("Component count cannot be 0");
     99  }
    100  for (unsigned i = 0; i < comp_count - static_cast<unsigned>(1); ++i) {
    101    uint16_t component = 0;
    102    if (!subtable.ReadU16(&component)) {
    103      return OTS_FAILURE_MSG("Can't read ligature component %d", i);
    104    }
    105    if (component >= num_glyphs) {
    106      return OTS_FAILURE_MSG("Bad ligature component %d of %d", i, component);
    107    }
    108  }
    109 
    110  return true;
    111 }
    112 
    113 bool ParseLigatureSetTable(const ots::Font *font,
    114                           const uint8_t *data, const size_t length,
    115                           const uint16_t num_glyphs) {
    116  ots::Buffer subtable(data, length);
    117 
    118  uint16_t ligature_count = 0;
    119 
    120  if (!subtable.ReadU16(&ligature_count)) {
    121    return OTS_FAILURE_MSG("Can't read ligature count in ligature set");
    122  }
    123 
    124  const unsigned ligature_end = static_cast<unsigned>(2) + ligature_count * 2;
    125  if (ligature_end > std::numeric_limits<uint16_t>::max()) {
    126    return OTS_FAILURE_MSG("Bad end of ligature %d in ligature set", ligature_end);
    127  }
    128  for (unsigned i = 0; i < ligature_count; ++i) {
    129    uint16_t offset_ligature = 0;
    130    if (!subtable.ReadU16(&offset_ligature)) {
    131      return OTS_FAILURE_MSG("Failed to read ligature offset %d", i);
    132    }
    133    if (offset_ligature < ligature_end || offset_ligature >= length) {
    134      return OTS_FAILURE_MSG("Bad ligature offset %d for ligature %d", offset_ligature, i);
    135    }
    136    if (!ParseLigatureTable(font, data + offset_ligature, length - offset_ligature,
    137                            num_glyphs)) {
    138      return OTS_FAILURE_MSG("Failed to parse ligature %d", i);
    139    }
    140  }
    141 
    142  return true;
    143 }
    144 
    145 }  // namespace
    146 
    147 namespace ots {
    148 
    149 // Lookup Type 1:
    150 // Single Substitution Subtable
    151 bool OpenTypeGSUB::ParseSingleSubstitution(const uint8_t *data,
    152                                           const size_t length) {
    153  Font* font = GetFont();
    154  Buffer subtable(data, length);
    155 
    156  uint16_t format = 0;
    157  uint16_t offset_coverage = 0;
    158 
    159  if (!subtable.ReadU16(&format) ||
    160      !subtable.ReadU16(&offset_coverage)) {
    161    return Error("Failed to read single subst table header");
    162  }
    163 
    164  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
    165      font->GetTypedTable(OTS_TAG_MAXP));
    166  if (!maxp) {
    167    return Error("Required maxp table missing");
    168  }
    169  const uint16_t num_glyphs = maxp->num_glyphs;
    170  if (format == 1) {
    171    // Parse SingleSubstFormat1
    172    int16_t delta_glyph_id = 0;
    173    if (!subtable.ReadS16(&delta_glyph_id)) {
    174      return Error("Failed to read glyph shift from format 1 single subst table");
    175    }
    176    if (std::abs(delta_glyph_id) >= num_glyphs) {
    177      return Error("bad glyph shift of %d in format 1 single subst table", delta_glyph_id);
    178    }
    179  } else if (format == 2) {
    180    // Parse SingleSubstFormat2
    181    uint16_t glyph_count = 0;
    182    if (!subtable.ReadU16(&glyph_count)) {
    183      return Error("Failed to read glyph cound in format 2 single subst table");
    184    }
    185    if (glyph_count > num_glyphs) {
    186      return Error("Bad glyph count %d > %d in format 2 single subst table", glyph_count, num_glyphs);
    187    }
    188    for (unsigned i = 0; i < glyph_count; ++i) {
    189      uint16_t substitute = 0;
    190      if (!subtable.ReadU16(&substitute)) {
    191        return Error("Failed to read substitution %d in format 2 single subst table", i);
    192      }
    193      if (substitute >= num_glyphs) {
    194        return Error("too large substitute: %u", substitute);
    195      }
    196    }
    197  } else {
    198    return Error("Bad single subst table format %d", format);
    199  }
    200 
    201  if (offset_coverage < subtable.offset() || offset_coverage >= length) {
    202    return Error("Bad coverage offset %x", offset_coverage);
    203  }
    204  if (!ots::ParseCoverageTable(font, data + offset_coverage,
    205                               length - offset_coverage, num_glyphs)) {
    206    return Error("Failed to parse coverage table");
    207  }
    208 
    209  return true;
    210 }
    211 
    212 // Lookup Type 2:
    213 // Multiple Substitution Subtable
    214 bool OpenTypeGSUB::ParseMutipleSubstitution(const uint8_t *data,
    215                                            const size_t length) {
    216  Font* font = GetFont();
    217  Buffer subtable(data, length);
    218 
    219  uint16_t format = 0;
    220  uint16_t offset_coverage = 0;
    221  uint16_t sequence_count = 0;
    222 
    223  if (!subtable.ReadU16(&format) ||
    224      !subtable.ReadU16(&offset_coverage) ||
    225      !subtable.ReadU16(&sequence_count)) {
    226    return Error("Can't read header of multiple subst table");
    227  }
    228 
    229  if (format != 1) {
    230    return Error("Bad multiple subst table format %d", format);
    231  }
    232 
    233  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
    234      font->GetTypedTable(OTS_TAG_MAXP));
    235  if (!maxp) {
    236    return Error("Required maxp table missing");
    237  }
    238  const uint16_t num_glyphs = maxp->num_glyphs;
    239  const unsigned sequence_end = static_cast<unsigned>(6) +
    240      sequence_count * 2;
    241  if (sequence_end > std::numeric_limits<uint16_t>::max()) {
    242    return Error("Bad sequence end %d, in multiple subst", sequence_end);
    243  }
    244  for (unsigned i = 0; i < sequence_count; ++i) {
    245    uint16_t offset_sequence = 0;
    246    if (!subtable.ReadU16(&offset_sequence)) {
    247      return Error("Failed to read sequence offset for sequence %d", i);
    248    }
    249    if (offset_sequence < sequence_end || offset_sequence >= length) {
    250      return Error("Bad sequence offset %d for sequence %d", offset_sequence, i);
    251    }
    252    if (!ParseSequenceTable(font, data + offset_sequence, length - offset_sequence,
    253                            num_glyphs)) {
    254      return Error("Failed to parse sequence table %d", i);
    255    }
    256  }
    257 
    258  if (offset_coverage < sequence_end || offset_coverage >= length) {
    259    return Error("Bad coverage offset %d", offset_coverage);
    260  }
    261  if (!ots::ParseCoverageTable(font, data + offset_coverage,
    262                               length - offset_coverage, num_glyphs)) {
    263    return Error("Failed to parse coverage table");
    264  }
    265 
    266  return true;
    267 }
    268 
    269 // Lookup Type 3:
    270 // Alternate Substitution Subtable
    271 bool OpenTypeGSUB::ParseAlternateSubstitution(const uint8_t *data,
    272                                              const size_t length) {
    273  Font* font = GetFont();
    274  Buffer subtable(data, length);
    275 
    276  uint16_t format = 0;
    277  uint16_t offset_coverage = 0;
    278  uint16_t alternate_set_count = 0;
    279 
    280  if (!subtable.ReadU16(&format) ||
    281      !subtable.ReadU16(&offset_coverage) ||
    282      !subtable.ReadU16(&alternate_set_count)) {
    283    return Error("Can't read alternate subst header");
    284  }
    285 
    286  if (format != 1) {
    287    return Error("Bad alternate subst table format %d", format);
    288  }
    289 
    290  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
    291      font->GetTypedTable(OTS_TAG_MAXP));
    292  if (!maxp) {
    293    return Error("Required maxp table missing");
    294  }
    295  const uint16_t num_glyphs = maxp->num_glyphs;
    296  const unsigned alternate_set_end = static_cast<unsigned>(6) +
    297      alternate_set_count * 2;
    298  if (alternate_set_end > std::numeric_limits<uint16_t>::max()) {
    299    return Error("Bad end of alternate set %d", alternate_set_end);
    300  }
    301  for (unsigned i = 0; i < alternate_set_count; ++i) {
    302    uint16_t offset_alternate_set = 0;
    303    if (!subtable.ReadU16(&offset_alternate_set)) {
    304      return Error("Can't read alternate set offset for set %d", i);
    305    }
    306    if (offset_alternate_set < alternate_set_end ||
    307        offset_alternate_set >= length) {
    308      return Error("Bad alternate set offset %d for set %d", offset_alternate_set, i);
    309    }
    310    if (!ParseAlternateSetTable(font, data + offset_alternate_set,
    311                                length - offset_alternate_set,
    312                                num_glyphs)) {
    313      return Error("Failed to parse alternate set");
    314    }
    315  }
    316 
    317  if (offset_coverage < alternate_set_end || offset_coverage >= length) {
    318    return Error("Bad coverage offset %d", offset_coverage);
    319  }
    320  if (!ots::ParseCoverageTable(font, data + offset_coverage,
    321                               length - offset_coverage, num_glyphs)) {
    322    return Error("Failed to parse coverage table");
    323  }
    324 
    325  return true;
    326 }
    327 
    328 // Lookup Type 4:
    329 // Ligature Substitution Subtable
    330 bool OpenTypeGSUB::ParseLigatureSubstitution(const uint8_t *data,
    331                                             const size_t length) {
    332  Font* font = GetFont();
    333  Buffer subtable(data, length);
    334 
    335  uint16_t format = 0;
    336  uint16_t offset_coverage = 0;
    337  uint16_t lig_set_count = 0;
    338 
    339  if (!subtable.ReadU16(&format) ||
    340      !subtable.ReadU16(&offset_coverage) ||
    341      !subtable.ReadU16(&lig_set_count)) {
    342    return Error("Failed to read ligature substitution header");
    343  }
    344 
    345  if (format != 1) {
    346    return Error("Bad ligature substitution table format %d", format);
    347  }
    348 
    349  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
    350      font->GetTypedTable(OTS_TAG_MAXP));
    351  if (!maxp) {
    352    return Error("Required maxp table missing");
    353  }
    354  const uint16_t num_glyphs = maxp->num_glyphs;
    355  const unsigned ligature_set_end = static_cast<unsigned>(6) +
    356      lig_set_count * 2;
    357  if (ligature_set_end > std::numeric_limits<uint16_t>::max()) {
    358    return Error("Bad end of ligature set %d in ligature substitution table", ligature_set_end);
    359  }
    360  for (unsigned i = 0; i < lig_set_count; ++i) {
    361    uint16_t offset_ligature_set = 0;
    362    if (!subtable.ReadU16(&offset_ligature_set)) {
    363      return Error("Can't read ligature set offset %d", i);
    364    }
    365    if (offset_ligature_set < ligature_set_end ||
    366        offset_ligature_set >= length) {
    367      return Error("Bad ligature set offset %d for set %d", offset_ligature_set, i);
    368    }
    369    if (!ParseLigatureSetTable(font, data + offset_ligature_set,
    370                               length - offset_ligature_set, num_glyphs)) {
    371      return Error("Failed to parse ligature set %d", i);
    372    }
    373  }
    374 
    375  if (offset_coverage < ligature_set_end || offset_coverage >= length) {
    376    return Error("Bad coverage offset %d", offset_coverage);
    377  }
    378  if (!ots::ParseCoverageTable(font, data + offset_coverage,
    379                               length - offset_coverage, num_glyphs)) {
    380    return Error("Failed to parse coverage table");
    381  }
    382 
    383  return true;
    384 }
    385 
    386 // Lookup Type 5:
    387 // Contextual Substitution Subtable
    388 // OpenTypeLayoutTable::ParseContextSubtable()
    389 
    390 // Lookup Type 6:
    391 // Chaining Contextual Substitution Subtable
    392 // OpenTypeLayoutTable::ParseChainingContextSubtable
    393 
    394 // Lookup Type 7:
    395 // Extension Substition
    396 // OpenTypeLayoutTable::ParseExtensionSubtable
    397 
    398 // Lookup Type 8:
    399 // Reverse Chaining Contexual Single Substitution Subtable
    400 bool OpenTypeGSUB::ParseReverseChainingContextSingleSubstitution(const uint8_t *data,
    401                                                                 const size_t length) {
    402  Font* font = GetFont();
    403  Buffer subtable(data, length);
    404 
    405  uint16_t format = 0;
    406  uint16_t offset_coverage = 0;
    407 
    408  if (!subtable.ReadU16(&format) ||
    409      !subtable.ReadU16(&offset_coverage)) {
    410    return Error("Failed to read reverse chaining header");
    411  }
    412 
    413  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
    414      font->GetTypedTable(OTS_TAG_MAXP));
    415  if (!maxp) {
    416    return Error("Required maxp table missing");
    417  }
    418  const uint16_t num_glyphs = maxp->num_glyphs;
    419 
    420  uint16_t backtrack_glyph_count = 0;
    421  if (!subtable.ReadU16(&backtrack_glyph_count)) {
    422    return Error("Failed to read backtrack glyph count in reverse chaining table");
    423  }
    424  std::vector<uint16_t> offsets_backtrack;
    425  offsets_backtrack.reserve(backtrack_glyph_count);
    426  for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
    427    uint16_t offset = 0;
    428    if (!subtable.ReadU16(&offset)) {
    429      return Error("Failed to read backtrack offset %d", i);
    430    }
    431    offsets_backtrack.push_back(offset);
    432  }
    433 
    434  uint16_t lookahead_glyph_count = 0;
    435  if (!subtable.ReadU16(&lookahead_glyph_count)) {
    436    return Error("Failed to read look ahead glyph count");
    437  }
    438  std::vector<uint16_t> offsets_lookahead;
    439  offsets_lookahead.reserve(lookahead_glyph_count);
    440  for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
    441    uint16_t offset = 0;
    442    if (!subtable.ReadU16(&offset)) {
    443      return Error("Can't read look ahead offset %d", i);
    444    }
    445    offsets_lookahead.push_back(offset);
    446  }
    447 
    448  uint16_t glyph_count = 0;
    449  if (!subtable.ReadU16(&glyph_count)) {
    450    return Error("Can't read glyph count in reverse chaining table");
    451  }
    452  for (unsigned i = 0; i < glyph_count; ++i) {
    453    uint16_t substitute = 0;
    454    if (!subtable.ReadU16(&substitute)) {
    455      return Error("Failed to read substitution %d reverse chaining table", i);
    456    }
    457    if (substitute >= num_glyphs) {
    458      return Error("Bad substitute glyph %d in reverse chaining table substitution %d", substitute, i);
    459    }
    460  }
    461 
    462  const unsigned substitute_end = static_cast<unsigned>(10) +
    463      (backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2;
    464  if (substitute_end > std::numeric_limits<uint16_t>::max()) {
    465    return Error("Bad substitute end offset in reverse chaining table");
    466  }
    467 
    468  if (offset_coverage < substitute_end || offset_coverage >= length) {
    469    return Error("Bad coverage offset %d in reverse chaining table", offset_coverage);
    470  }
    471  if (!ots::ParseCoverageTable(font, data + offset_coverage,
    472                               length - offset_coverage, num_glyphs)) {
    473    return Error("Failed to parse coverage table in reverse chaining table");
    474  }
    475 
    476  for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
    477    if (offsets_backtrack[i] < substitute_end ||
    478        offsets_backtrack[i] >= length) {
    479      return Error("Bad backtrack offset %d for backtrack %d in reverse chaining table", offsets_backtrack[i], i);
    480    }
    481    if (!ots::ParseCoverageTable(font, data + offsets_backtrack[i],
    482                                 length - offsets_backtrack[i], num_glyphs)) {
    483      return Error("Failed to parse coverage table for backtrack %d in reverse chaining table", i);
    484    }
    485  }
    486 
    487  for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
    488    if (offsets_lookahead[i] < substitute_end ||
    489        offsets_lookahead[i] >= length) {
    490      return Error("Bad lookahead offset %d for lookahead %d in reverse chaining table", offsets_lookahead[i], i);
    491    }
    492    if (!ots::ParseCoverageTable(font, data + offsets_lookahead[i],
    493                                 length - offsets_lookahead[i], num_glyphs)) {
    494      return Error("Failed to parse lookahead coverage table %d in reverse chaining table", i);
    495    }
    496  }
    497 
    498  return true;
    499 }
    500 
    501 bool OpenTypeGSUB::ValidLookupSubtableType(const uint16_t lookup_type,
    502                                           bool extension) const {
    503  if (extension && lookup_type == GSUB_TYPE_EXTENSION_SUBSTITUTION)
    504    return false;
    505  return lookup_type >= GSUB_TYPE_SINGLE && lookup_type < GSUB_TYPE_RESERVED;
    506 }
    507 
    508 bool OpenTypeGSUB::ParseLookupSubtable(const uint8_t *data, const size_t length,
    509                                       const uint16_t lookup_type) {
    510  switch (lookup_type) {
    511    case GSUB_TYPE_SINGLE:
    512      return ParseSingleSubstitution(data, length);
    513    case GSUB_TYPE_MULTIPLE:
    514      return ParseMutipleSubstitution(data, length);
    515    case GSUB_TYPE_ALTERNATE:
    516      return ParseAlternateSubstitution(data, length);
    517    case GSUB_TYPE_LIGATURE:
    518      return ParseLigatureSubstitution(data, length);
    519    case GSUB_TYPE_CONTEXT:
    520      return ParseContextSubtable(data, length);
    521    case GSUB_TYPE_CHANGING_CONTEXT:
    522      return ParseChainingContextSubtable(data, length);
    523    case GSUB_TYPE_EXTENSION_SUBSTITUTION:
    524      return ParseExtensionSubtable(data, length);
    525    case GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE:
    526      return ParseReverseChainingContextSingleSubstitution(data, length);
    527  }
    528  return false;
    529 }
    530 
    531 }  // namespace ots
    532 
    533 #undef TABLE_NAME