gfx/ots/src/gsub.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) 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.
     5 #include "gsub.h"
     7 #include <limits>
     8 #include <vector>
    10 #include "layout.h"
    11 #include "maxp.h"
    13 // GSUB - The Glyph Substitution Table
    14 // http://www.microsoft.com/typography/otspec/gsub.htm
    16 #define TABLE_NAME "GSUB"
    18 namespace {
    20 // The GSUB header size
    21 const size_t kGsubHeaderSize = 4 + 3 * 2;
    23 enum GSUB_TYPE {
    24   GSUB_TYPE_SINGLE = 1,
    25   GSUB_TYPE_MULTIPLE = 2,
    26   GSUB_TYPE_ALTERNATE = 3,
    27   GSUB_TYPE_LIGATURE = 4,
    28   GSUB_TYPE_CONTEXT = 5,
    29   GSUB_TYPE_CHANGING_CONTEXT = 6,
    30   GSUB_TYPE_EXTENSION_SUBSTITUTION = 7,
    31   GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE = 8,
    32   GSUB_TYPE_RESERVED = 9
    33 };
    35 // Lookup type parsers.
    36 bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
    37                              const uint8_t *data, const size_t length);
    38 bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
    39                               const uint8_t *data, const size_t length);
    40 bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
    41                                 const uint8_t *data, const size_t length);
    42 bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
    43       const uint8_t *data, const size_t length);
    44 bool ParseContextSubstitution(const ots::OpenTypeFile *file,
    45                               const uint8_t *data, const size_t length);
    46 bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
    47                                       const uint8_t *data,
    48                                       const size_t length);
    49 bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
    50                                 const uint8_t *data, const size_t length);
    51 bool ParseReverseChainingContextSingleSubstitution(
    52     const ots::OpenTypeFile *file, const uint8_t *data, const size_t length);
    54 const ots::LookupSubtableParser::TypeParser kGsubTypeParsers[] = {
    55   {GSUB_TYPE_SINGLE, ParseSingleSubstitution},
    56   {GSUB_TYPE_MULTIPLE, ParseMutipleSubstitution},
    57   {GSUB_TYPE_ALTERNATE, ParseAlternateSubstitution},
    58   {GSUB_TYPE_LIGATURE, ParseLigatureSubstitution},
    59   {GSUB_TYPE_CONTEXT, ParseContextSubstitution},
    60   {GSUB_TYPE_CHANGING_CONTEXT, ParseChainingContextSubstitution},
    61   {GSUB_TYPE_EXTENSION_SUBSTITUTION, ParseExtensionSubstitution},
    62   {GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE,
    63     ParseReverseChainingContextSingleSubstitution}
    64 };
    66 const ots::LookupSubtableParser kGsubLookupSubtableParser = {
    67   arraysize(kGsubTypeParsers),
    68   GSUB_TYPE_EXTENSION_SUBSTITUTION, kGsubTypeParsers
    69 };
    71 // Lookup Type 1:
    72 // Single Substitution Subtable
    73 bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
    74                              const uint8_t *data, const size_t length) {
    75   ots::Buffer subtable(data, length);
    77   uint16_t format = 0;
    78   uint16_t offset_coverage = 0;
    80   if (!subtable.ReadU16(&format) ||
    81       !subtable.ReadU16(&offset_coverage)) {
    82     return OTS_FAILURE_MSG("Failed to read single subst table header");
    83   }
    85   const uint16_t num_glyphs = file->maxp->num_glyphs;
    86   if (format == 1) {
    87     // Parse SingleSubstFormat1
    88     int16_t delta_glyph_id = 0;
    89     if (!subtable.ReadS16(&delta_glyph_id)) {
    90       return OTS_FAILURE_MSG("Failed to read glyph shift from format 1 single subst table");
    91     }
    92     if (std::abs(delta_glyph_id) >= num_glyphs) {
    93       return OTS_FAILURE_MSG("bad glyph shift of %d in format 1 single subst table", delta_glyph_id);
    94     }
    95   } else if (format == 2) {
    96     // Parse SingleSubstFormat2
    97     uint16_t glyph_count = 0;
    98     if (!subtable.ReadU16(&glyph_count)) {
    99       return OTS_FAILURE_MSG("Failed to read glyph cound in format 2 single subst table");
   100     }
   101     if (glyph_count > num_glyphs) {
   102       return OTS_FAILURE_MSG("Bad glyph count %d > %d in format 2 single subst table", glyph_count, num_glyphs);
   103     }
   104     for (unsigned i = 0; i < glyph_count; ++i) {
   105       uint16_t substitute = 0;
   106       if (!subtable.ReadU16(&substitute)) {
   107         return OTS_FAILURE_MSG("Failed to read substitution %d in format 2 single subst table", i);
   108       }
   109       if (substitute >= num_glyphs) {
   110         return OTS_FAILURE_MSG("too large substitute: %u", substitute);
   111       }
   112     }
   113   } else {
   114     return OTS_FAILURE_MSG("Bad single subst table format %d", format);
   115   }
   117   if (offset_coverage < subtable.offset() || offset_coverage >= length) {
   118     return OTS_FAILURE_MSG("Bad coverage offset %x", offset_coverage);
   119   }
   120   if (!ots::ParseCoverageTable(file, data + offset_coverage,
   121                                length - offset_coverage, num_glyphs)) {
   122     return OTS_FAILURE_MSG("Failed to parse coverage table");
   123   }
   125   return true;
   126 }
   128 bool ParseSequenceTable(const ots::OpenTypeFile *file,
   129                         const uint8_t *data, const size_t length,
   130                         const uint16_t num_glyphs) {
   131   ots::Buffer subtable(data, length);
   133   uint16_t glyph_count = 0;
   134   if (!subtable.ReadU16(&glyph_count)) {
   135     return OTS_FAILURE_MSG("Failed to read glyph count in sequence table");
   136   }
   137   if (glyph_count > num_glyphs) {
   138     return OTS_FAILURE_MSG("bad glyph count %d > %d", glyph_count, num_glyphs);
   139   }
   140   for (unsigned i = 0; i < glyph_count; ++i) {
   141     uint16_t substitute = 0;
   142     if (!subtable.ReadU16(&substitute)) {
   143       return OTS_FAILURE_MSG("Failedt o read substitution %d in sequence table", i);
   144     }
   145     if (substitute >= num_glyphs) {
   146       return OTS_FAILURE_MSG("Bad subsitution (%d) %d > %d", i, substitute, num_glyphs);
   147     }
   148   }
   150   return true;
   151 }
   153 // Lookup Type 2:
   154 // Multiple Substitution Subtable
   155 bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
   156                               const uint8_t *data, const size_t length) {
   157   ots::Buffer subtable(data, length);
   159   uint16_t format = 0;
   160   uint16_t offset_coverage = 0;
   161   uint16_t sequence_count = 0;
   163   if (!subtable.ReadU16(&format) ||
   164       !subtable.ReadU16(&offset_coverage) ||
   165       !subtable.ReadU16(&sequence_count)) {
   166     return OTS_FAILURE_MSG("Can't read header of multiple subst table");
   167   }
   169   if (format != 1) {
   170     return OTS_FAILURE_MSG("Bad multiple subst table format %d", format);
   171   }
   173   const uint16_t num_glyphs = file->maxp->num_glyphs;
   174   const unsigned sequence_end = static_cast<unsigned>(6) +
   175       sequence_count * 2;
   176   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
   177     return OTS_FAILURE_MSG("Bad segence end %d, in multiple subst", sequence_end);
   178   }
   179   for (unsigned i = 0; i < sequence_count; ++i) {
   180     uint16_t offset_sequence = 0;
   181     if (!subtable.ReadU16(&offset_sequence)) {
   182       return OTS_FAILURE_MSG("Failed to read sequence offset for sequence %d", i);
   183     }
   184     if (offset_sequence < sequence_end || offset_sequence >= length) {
   185       return OTS_FAILURE_MSG("Bad sequence offset %d for sequence %d", offset_sequence, i);
   186     }
   187     if (!ParseSequenceTable(file, data + offset_sequence, length - offset_sequence,
   188                             num_glyphs)) {
   189       return OTS_FAILURE_MSG("Failed to parse sequence table %d", i);
   190     }
   191   }
   193   if (offset_coverage < sequence_end || offset_coverage >= length) {
   194     return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
   195   }
   196   if (!ots::ParseCoverageTable(file, data + offset_coverage,
   197                                length - offset_coverage, num_glyphs)) {
   198     return OTS_FAILURE_MSG("Failed to parse coverage table");
   199   }
   201   return true;
   202 }
   204 bool ParseAlternateSetTable(const ots::OpenTypeFile *file,
   205                             const uint8_t *data, const size_t length,
   206                             const uint16_t num_glyphs) {
   207   ots::Buffer subtable(data, length);
   209   uint16_t glyph_count = 0;
   210   if (!subtable.ReadU16(&glyph_count)) {
   211     return OTS_FAILURE_MSG("Failed to read alternate set header");
   212   }
   213   if (glyph_count > num_glyphs) {
   214     return OTS_FAILURE_MSG("Bad glyph count %d > %d in alternate set table", glyph_count, num_glyphs);
   215   }
   216   for (unsigned i = 0; i < glyph_count; ++i) {
   217     uint16_t alternate = 0;
   218     if (!subtable.ReadU16(&alternate)) {
   219       return OTS_FAILURE_MSG("Can't read alternate %d", i);
   220     }
   221     if (alternate >= num_glyphs) {
   222       return OTS_FAILURE_MSG("Too large alternate: %u", alternate);
   223     }
   224   }
   225   return true;
   226 }
   228 // Lookup Type 3:
   229 // Alternate Substitution Subtable
   230 bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
   231                                 const uint8_t *data, const size_t length) {
   232   ots::Buffer subtable(data, length);
   234   uint16_t format = 0;
   235   uint16_t offset_coverage = 0;
   236   uint16_t alternate_set_count = 0;
   238   if (!subtable.ReadU16(&format) ||
   239       !subtable.ReadU16(&offset_coverage) ||
   240       !subtable.ReadU16(&alternate_set_count)) {
   241     return OTS_FAILURE_MSG("Can't read alternate subst header");
   242   }
   244   if (format != 1) {
   245     return OTS_FAILURE_MSG("Bad alternate subst table format %d", format);
   246   }
   248   const uint16_t num_glyphs = file->maxp->num_glyphs;
   249   const unsigned alternate_set_end = static_cast<unsigned>(6) +
   250       alternate_set_count * 2;
   251   if (alternate_set_end > std::numeric_limits<uint16_t>::max()) {
   252     return OTS_FAILURE_MSG("Bad end of alternate set %d", alternate_set_end);
   253   }
   254   for (unsigned i = 0; i < alternate_set_count; ++i) {
   255     uint16_t offset_alternate_set = 0;
   256     if (!subtable.ReadU16(&offset_alternate_set)) {
   257       return OTS_FAILURE_MSG("Can't read alternate set offset for set %d", i);
   258     }
   259     if (offset_alternate_set < alternate_set_end ||
   260         offset_alternate_set >= length) {
   261       return OTS_FAILURE_MSG("Bad alternate set offset %d for set %d", offset_alternate_set, i);
   262     }
   263     if (!ParseAlternateSetTable(file, data + offset_alternate_set,
   264                                 length - offset_alternate_set,
   265                                 num_glyphs)) {
   266       return OTS_FAILURE_MSG("Failed to parse alternate set");
   267     }
   268   }
   270   if (offset_coverage < alternate_set_end || offset_coverage >= length) {
   271     return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
   272   }
   273   if (!ots::ParseCoverageTable(file, data + offset_coverage,
   274                                length - offset_coverage, num_glyphs)) {
   275     return OTS_FAILURE_MSG("Failed to parse coverage table");
   276   }
   278   return true;
   279 }
   281 bool ParseLigatureTable(const ots::OpenTypeFile *file,
   282                         const uint8_t *data, const size_t length,
   283                         const uint16_t num_glyphs) {
   284   ots::Buffer subtable(data, length);
   286   uint16_t lig_glyph = 0;
   287   uint16_t comp_count = 0;
   289   if (!subtable.ReadU16(&lig_glyph) ||
   290       !subtable.ReadU16(&comp_count)) {
   291     return OTS_FAILURE_MSG("Failed to read ligatuer table header");
   292   }
   294   if (lig_glyph >= num_glyphs) {
   295     return OTS_FAILURE_MSG("too large lig_glyph: %u", lig_glyph);
   296   }
   297   if (comp_count == 0 || comp_count > num_glyphs) {
   298     return OTS_FAILURE_MSG("Bad component count of %d", comp_count);
   299   }
   300   for (unsigned i = 0; i < comp_count - static_cast<unsigned>(1); ++i) {
   301     uint16_t component = 0;
   302     if (!subtable.ReadU16(&component)) {
   303       return OTS_FAILURE_MSG("Can't read ligature component %d", i);
   304     }
   305     if (component >= num_glyphs) {
   306       return OTS_FAILURE_MSG("Bad ligature component %d of %d", i, component);
   307     }
   308   }
   310   return true;
   311 }
   313 bool ParseLigatureSetTable(const ots::OpenTypeFile *file,
   314                            const uint8_t *data, const size_t length,
   315                            const uint16_t num_glyphs) {
   316   ots::Buffer subtable(data, length);
   318   uint16_t ligature_count = 0;
   320   if (!subtable.ReadU16(&ligature_count)) {
   321     return OTS_FAILURE_MSG("Can't read ligature count in ligature set");
   322   }
   324   const unsigned ligature_end = static_cast<unsigned>(2) + ligature_count * 2;
   325   if (ligature_end > std::numeric_limits<uint16_t>::max()) {
   326     return OTS_FAILURE_MSG("Bad end of ligature %d in ligature set", ligature_end);
   327   }
   328   for (unsigned i = 0; i < ligature_count; ++i) {
   329     uint16_t offset_ligature = 0;
   330     if (!subtable.ReadU16(&offset_ligature)) {
   331       return OTS_FAILURE_MSG("Failed to read ligature offset %d", i);
   332     }
   333     if (offset_ligature < ligature_end || offset_ligature >= length) {
   334       return OTS_FAILURE_MSG("Bad ligature offset %d for ligature %d", offset_ligature, i);
   335     }
   336     if (!ParseLigatureTable(file, data + offset_ligature, length - offset_ligature,
   337                             num_glyphs)) {
   338       return OTS_FAILURE_MSG("Failed to parse ligature %d", i);
   339     }
   340   }
   342   return true;
   343 }
   345 // Lookup Type 4:
   346 // Ligature Substitution Subtable
   347 bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
   348                                const uint8_t *data, const size_t length) {
   349   ots::Buffer subtable(data, length);
   351   uint16_t format = 0;
   352   uint16_t offset_coverage = 0;
   353   uint16_t lig_set_count = 0;
   355   if (!subtable.ReadU16(&format) ||
   356       !subtable.ReadU16(&offset_coverage) ||
   357       !subtable.ReadU16(&lig_set_count)) {
   358     return OTS_FAILURE_MSG("Failed to read ligature substitution header");
   359   }
   361   if (format != 1) {
   362     return OTS_FAILURE_MSG("Bad ligature substitution table format %d", format);
   363   }
   365   const uint16_t num_glyphs = file->maxp->num_glyphs;
   366   const unsigned ligature_set_end = static_cast<unsigned>(6) +
   367       lig_set_count * 2;
   368   if (ligature_set_end > std::numeric_limits<uint16_t>::max()) {
   369     return OTS_FAILURE_MSG("Bad end of ligature set %d in ligature substitution table", ligature_set_end);
   370   }
   371   for (unsigned i = 0; i < lig_set_count; ++i) {
   372     uint16_t offset_ligature_set = 0;
   373     if (!subtable.ReadU16(&offset_ligature_set)) {
   374       return OTS_FAILURE_MSG("Can't read ligature set offset %d", i);
   375     }
   376     if (offset_ligature_set < ligature_set_end ||
   377         offset_ligature_set >= length) {
   378       return OTS_FAILURE_MSG("Bad ligature set offset %d for set %d", offset_ligature_set, i);
   379     }
   380     if (!ParseLigatureSetTable(file, data + offset_ligature_set,
   381                                length - offset_ligature_set, num_glyphs)) {
   382       return OTS_FAILURE_MSG("Failed to parse ligature set %d", i);
   383     }
   384   }
   386   if (offset_coverage < ligature_set_end || offset_coverage >= length) {
   387     return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
   388   }
   389   if (!ots::ParseCoverageTable(file, data + offset_coverage,
   390                                length - offset_coverage, num_glyphs)) {
   391     return OTS_FAILURE_MSG("Failed to parse coverage table");
   392   }
   394   return true;
   395 }
   397 // Lookup Type 5:
   398 // Contextual Substitution Subtable
   399 bool ParseContextSubstitution(const ots::OpenTypeFile *file,
   400                               const uint8_t *data, const size_t length) {
   401   return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs,
   402                                    file->gsub->num_lookups);
   403 }
   405 // Lookup Type 6:
   406 // Chaining Contextual Substitution Subtable
   407 bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
   408                                       const uint8_t *data,
   409                                       const size_t length) {
   410   return ots::ParseChainingContextSubtable(file, data, length,
   411                                            file->maxp->num_glyphs,
   412                                            file->gsub->num_lookups);
   413 }
   415 // Lookup Type 7:
   416 // Extension Substition
   417 bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
   418                                 const uint8_t *data, const size_t length) {
   419   return ots::ParseExtensionSubtable(file, data, length,
   420                                      &kGsubLookupSubtableParser);
   421 }
   423 // Lookup Type 8:
   424 // Reverse Chaining Contexual Single Substitution Subtable
   425 bool ParseReverseChainingContextSingleSubstitution(
   426     const ots::OpenTypeFile *file, const uint8_t *data, const size_t length) {
   427   ots::Buffer subtable(data, length);
   429   uint16_t format = 0;
   430   uint16_t offset_coverage = 0;
   432   if (!subtable.ReadU16(&format) ||
   433       !subtable.ReadU16(&offset_coverage)) {
   434     return OTS_FAILURE_MSG("Failed to read reverse chaining header");
   435   }
   437   const uint16_t num_glyphs = file->maxp->num_glyphs;
   439   uint16_t backtrack_glyph_count = 0;
   440   if (!subtable.ReadU16(&backtrack_glyph_count)) {
   441     return OTS_FAILURE_MSG("Failed to read backtrack glyph count in reverse chaining table");
   442   }
   443   if (backtrack_glyph_count > num_glyphs) {
   444     return OTS_FAILURE_MSG("Bad backtrack glyph count of %d", backtrack_glyph_count);
   445   }
   446   std::vector<uint16_t> offsets_backtrack;
   447   offsets_backtrack.reserve(backtrack_glyph_count);
   448   for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
   449     uint16_t offset = 0;
   450     if (!subtable.ReadU16(&offset)) {
   451       return OTS_FAILURE_MSG("Failed to read backtrack offset %d", i);
   452     }
   453     offsets_backtrack.push_back(offset);
   454   }
   456   uint16_t lookahead_glyph_count = 0;
   457   if (!subtable.ReadU16(&lookahead_glyph_count)) {
   458     return OTS_FAILURE_MSG("Failed to read look ahead glyph count");
   459   }
   460   if (lookahead_glyph_count > num_glyphs) {
   461     return OTS_FAILURE_MSG("Bad look ahead glyph count %d", lookahead_glyph_count);
   462   }
   463   std::vector<uint16_t> offsets_lookahead;
   464   offsets_lookahead.reserve(lookahead_glyph_count);
   465   for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
   466     uint16_t offset = 0;
   467     if (!subtable.ReadU16(&offset)) {
   468       return OTS_FAILURE_MSG("Can't read look ahead offset %d", i);
   469     }
   470     offsets_lookahead.push_back(offset);
   471   }
   473   uint16_t glyph_count = 0;
   474   if (!subtable.ReadU16(&glyph_count)) {
   475     return OTS_FAILURE_MSG("Can't read glyph count in reverse chaining table");
   476   }
   477   if (glyph_count > num_glyphs) {
   478     return OTS_FAILURE_MSG("Bad glyph count of %d", glyph_count);
   479   }
   480   for (unsigned i = 0; i < glyph_count; ++i) {
   481     uint16_t substitute = 0;
   482     if (!subtable.ReadU16(&substitute)) {
   483       return OTS_FAILURE_MSG("Failed to read substitution %d reverse chaining table", i);
   484     }
   485     if (substitute >= num_glyphs) {
   486       return OTS_FAILURE_MSG("Bad substitute glyph %d in reverse chaining table substitution %d", substitute, i);
   487     }
   488   }
   490   const unsigned substitute_end = static_cast<unsigned>(10) +
   491       (backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2;
   492   if (substitute_end > std::numeric_limits<uint16_t>::max()) {
   493     return OTS_FAILURE_MSG("Bad substitute end offset in reverse chaining table");
   494   }
   496   if (offset_coverage < substitute_end || offset_coverage >= length) {
   497     return OTS_FAILURE_MSG("Bad coverage offset %d in reverse chaining table", offset_coverage);
   498   }
   499   if (!ots::ParseCoverageTable(file, data + offset_coverage,
   500                                length - offset_coverage, num_glyphs)) {
   501     return OTS_FAILURE_MSG("Failed to parse coverage table in reverse chaining table");
   502   }
   504   for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
   505     if (offsets_backtrack[i] < substitute_end ||
   506         offsets_backtrack[i] >= length) {
   507       return OTS_FAILURE_MSG("Bad backtrack offset %d for backtrack %d in reverse chaining table", offsets_backtrack[i], i);
   508     }
   509     if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i],
   510                                  length - offsets_backtrack[i], num_glyphs)) {
   511       return OTS_FAILURE_MSG("Failed to parse coverage table for backtrack %d in reverse chaining table", i);
   512     }
   513   }
   515   for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
   516     if (offsets_lookahead[i] < substitute_end ||
   517         offsets_lookahead[i] >= length) {
   518       return OTS_FAILURE_MSG("Bad lookahead offset %d for lookahead %d in reverse chaining table", offsets_lookahead[i], i);
   519     }
   520     if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i],
   521                                  length - offsets_lookahead[i], num_glyphs)) {
   522       return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in reverse chaining table", i);
   523     }
   524   }
   526   return true;
   527 }
   529 }  // namespace
   531 #define DROP_THIS_TABLE(msg_) \
   532   do { \
   533     file->gsub->data = 0; \
   534     file->gsub->length = 0; \
   535     OTS_FAILURE_MSG(msg_ ", table discarded"); \
   536   } while (0)
   538 namespace ots {
   540 // As far as I checked, following fonts contain invalid values in GSUB table.
   541 // OTS will drop their GSUB table.
   542 //
   543 // # too large substitute (value is 0xFFFF)
   544 // kaiu.ttf
   545 // mingliub2.ttf
   546 // mingliub1.ttf
   547 // mingliub0.ttf
   548 // GraublauWeb.otf
   549 // GraublauWebBold.otf
   550 //
   551 // # too large alternate (value is 0xFFFF)
   552 // ManchuFont.ttf
   553 //
   554 // # bad offset to lang sys table (NULL offset)
   555 // DejaVuMonoSansBold.ttf
   556 // DejaVuMonoSansBoldOblique.ttf
   557 // DejaVuMonoSansOblique.ttf
   558 // DejaVuSansMono-BoldOblique.ttf
   559 // DejaVuSansMono-Oblique.ttf
   560 // DejaVuSansMono-Bold.ttf
   561 //
   562 // # bad start coverage index
   563 // GenBasBI.ttf
   564 // GenBasI.ttf
   565 // AndBasR.ttf
   566 // GenBkBasI.ttf
   567 // CharisSILR.ttf
   568 // CharisSILBI.ttf
   569 // CharisSILI.ttf
   570 // CharisSILB.ttf
   571 // DoulosSILR.ttf
   572 // CharisSILBI.ttf
   573 // GenBkBasB.ttf
   574 // GenBkBasR.ttf
   575 // GenBkBasBI.ttf
   576 // GenBasB.ttf
   577 // GenBasR.ttf
   578 //
   579 // # glyph range is overlapping
   580 // KacstTitleL.ttf
   581 // KacstDecorative.ttf
   582 // KacstTitle.ttf
   583 // KacstArt.ttf
   584 // KacstPoster.ttf
   585 // KacstQurn.ttf
   586 // KacstDigital.ttf
   587 // KacstBook.ttf
   588 // KacstFarsi.ttf
   590 bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
   591   // Parsing gsub table requires |file->maxp->num_glyphs|
   592   if (!file->maxp) {
   593     return OTS_FAILURE_MSG("Missing maxp table in font, needed by GSUB");
   594   }
   596   Buffer table(data, length);
   598   OpenTypeGSUB *gsub = new OpenTypeGSUB;
   599   file->gsub = gsub;
   601   uint32_t version = 0;
   602   uint16_t offset_script_list = 0;
   603   uint16_t offset_feature_list = 0;
   604   uint16_t offset_lookup_list = 0;
   605   if (!table.ReadU32(&version) ||
   606       !table.ReadU16(&offset_script_list) ||
   607       !table.ReadU16(&offset_feature_list) ||
   608       !table.ReadU16(&offset_lookup_list)) {
   609     DROP_THIS_TABLE("Incomplete table");
   610     return true;
   611   }
   613   if (version != 0x00010000) {
   614     DROP_THIS_TABLE("Bad version");
   615     return true;
   616   }
   617   if ((offset_script_list < kGsubHeaderSize ||
   618        offset_script_list >= length) ||
   619       (offset_feature_list < kGsubHeaderSize ||
   620        offset_feature_list >= length) ||
   621       (offset_lookup_list < kGsubHeaderSize ||
   622        offset_lookup_list >= length)) {
   623     DROP_THIS_TABLE("Bad offset in table header");
   624     return true;
   625   }
   627   if (!ParseLookupListTable(file, data + offset_lookup_list,
   628                             length - offset_lookup_list,
   629                             &kGsubLookupSubtableParser,
   630                             &gsub->num_lookups)) {
   631     DROP_THIS_TABLE("Failed to parse lookup list table");
   632     return true;
   633   }
   635   uint16_t num_features = 0;
   636   if (!ParseFeatureListTable(file, data + offset_feature_list,
   637                              length - offset_feature_list, gsub->num_lookups,
   638                              &num_features)) {
   639     DROP_THIS_TABLE("Failed to parse feature list table");
   640     return true;
   641   }
   643   if (!ParseScriptListTable(file, data + offset_script_list,
   644                             length - offset_script_list, num_features)) {
   645     DROP_THIS_TABLE("Failed to parse script list table");
   646     return true;
   647   }
   649   gsub->data = data;
   650   gsub->length = length;
   651   return true;
   652 }
   654 bool ots_gsub_should_serialise(OpenTypeFile *file) {
   655   return file->gsub != NULL && file->gsub->data != NULL;
   656 }
   658 bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) {
   659   if (!out->Write(file->gsub->data, file->gsub->length)) {
   660     return OTS_FAILURE_MSG("Failed to write GSUB table");
   661   }
   663   return true;
   664 }
   666 void ots_gsub_free(OpenTypeFile *file) {
   667   delete file->gsub;
   668 }
   670 }  // namespace ots

mercurial