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

       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 "gsub.h"
       6                 : 
       7                 : #include <limits>
       8                 : #include <vector>
       9                 : 
      10                 : #include "gdef.h"
      11                 : #include "gpos.h"
      12                 : #include "layout.h"
      13                 : #include "maxp.h"
      14                 : 
      15                 : // GSUB - The Glyph Substitution Table
      16                 : // http://www.microsoft.com/typography/otspec/gsub.htm
      17                 : 
      18                 : namespace {
      19                 : 
      20                 : // The GSUB header size
      21                 : const size_t kGsubHeaderSize = 8;
      22                 : 
      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                 : };
      34                 : 
      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);
      53                 : 
      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                 : };
      65                 : 
      66                 : // TODO(bashi): Port Chromium's arraysize macro and use it instead of sizeof().
      67                 : const ots::LookupSubtableParser kGsubLookupSubtableParser = {
      68                 :   sizeof(kGsubTypeParsers) / sizeof(kGsubTypeParsers[0]),
      69                 :   GSUB_TYPE_EXTENSION_SUBSTITUTION, kGsubTypeParsers
      70                 : };
      71                 : 
      72                 : // Lookup Type 1:
      73                 : // Single Substitution Subtable
      74               0 : bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
      75                 :                              const uint8_t *data, const size_t length) {
      76               0 :   ots::Buffer subtable(data, length);
      77                 : 
      78               0 :   uint16_t format = 0;
      79               0 :   uint16_t offset_coverage = 0;
      80                 : 
      81               0 :   if (!subtable.ReadU16(&format) ||
      82               0 :       !subtable.ReadU16(&offset_coverage)) {
      83               0 :     return OTS_FAILURE();
      84                 :   }
      85                 : 
      86               0 :   const uint16_t num_glyphs = file->maxp->num_glyphs;
      87               0 :   if (format == 1) {
      88                 :     // Parse SingleSubstFormat1
      89               0 :     int16_t delta_glyph_id = 0;
      90               0 :     if (!subtable.ReadS16(&delta_glyph_id)) {
      91               0 :       return OTS_FAILURE();
      92                 :     }
      93               0 :     if (std::abs(delta_glyph_id) >= num_glyphs) {
      94               0 :       return OTS_FAILURE();
      95                 :     }
      96               0 :   } else if (format == 2) {
      97                 :     // Parse SingleSubstFormat2
      98               0 :     uint16_t glyph_count = 0;
      99               0 :     if (!subtable.ReadU16(&glyph_count)) {
     100               0 :       return OTS_FAILURE();
     101                 :     }
     102               0 :     if (glyph_count > num_glyphs) {
     103               0 :       return OTS_FAILURE();
     104                 :     }
     105               0 :     for (unsigned i = 0; i < glyph_count; ++i) {
     106               0 :       uint16_t substitute = 0;
     107               0 :       if (!subtable.ReadU16(&substitute)) {
     108               0 :         return OTS_FAILURE();
     109                 :       }
     110               0 :       if (substitute >= num_glyphs) {
     111                 :         OTS_WARNING("too large substitute: %u", substitute);
     112               0 :         return OTS_FAILURE();
     113                 :       }
     114                 :     }
     115                 :   } else {
     116               0 :     return OTS_FAILURE();
     117                 :   }
     118                 : 
     119               0 :   if (offset_coverage < subtable.offset() || offset_coverage >= length) {
     120               0 :     return OTS_FAILURE();
     121                 :   }
     122               0 :   if (!ots::ParseCoverageTable(data + offset_coverage,
     123               0 :                                length - offset_coverage, num_glyphs)) {
     124               0 :     return OTS_FAILURE();
     125                 :   }
     126                 : 
     127               0 :   return true;
     128                 : }
     129                 : 
     130               0 : bool ParseSequenceTable(const uint8_t *data, const size_t length,
     131                 :                         const uint16_t num_glyphs) {
     132               0 :   ots::Buffer subtable(data, length);
     133                 : 
     134               0 :   uint16_t glyph_count = 0;
     135               0 :   if (!subtable.ReadU16(&glyph_count)) {
     136               0 :     return OTS_FAILURE();
     137                 :   }
     138               0 :   if (glyph_count > num_glyphs) {
     139               0 :     return OTS_FAILURE();
     140                 :   }
     141               0 :   for (unsigned i = 0; i < glyph_count; ++i) {
     142               0 :     uint16_t substitute = 0;
     143               0 :     if (!subtable.ReadU16(&substitute)) {
     144               0 :       return OTS_FAILURE();
     145                 :     }
     146               0 :     if (substitute >= num_glyphs) {
     147               0 :       return OTS_FAILURE();
     148                 :     }
     149                 :   }
     150                 : 
     151               0 :   return true;
     152                 : }
     153                 : 
     154                 : // Lookup Type 2:
     155                 : // Multiple Substitution Subtable
     156               0 : bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
     157                 :                               const uint8_t *data, const size_t length) {
     158               0 :   ots::Buffer subtable(data, length);
     159                 : 
     160               0 :   uint16_t format = 0;
     161               0 :   uint16_t offset_coverage = 0;
     162               0 :   uint16_t sequence_count = 0;
     163                 : 
     164               0 :   if (!subtable.ReadU16(&format) ||
     165               0 :       !subtable.ReadU16(&offset_coverage) ||
     166               0 :       !subtable.ReadU16(&sequence_count)) {
     167               0 :     return OTS_FAILURE();
     168                 :   }
     169                 : 
     170               0 :   if (format != 1) {
     171               0 :     return OTS_FAILURE();
     172                 :   }
     173                 : 
     174               0 :   const uint16_t num_glyphs = file->maxp->num_glyphs;
     175                 :   const unsigned sequence_end = static_cast<unsigned>(6) +
     176               0 :       sequence_count * 2;
     177               0 :   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
     178               0 :     return OTS_FAILURE();
     179                 :   }
     180               0 :   for (unsigned i = 0; i < sequence_count; ++i) {
     181               0 :     uint16_t offset_sequence = 0;
     182               0 :     if (!subtable.ReadU16(&offset_sequence)) {
     183               0 :       return OTS_FAILURE();
     184                 :     }
     185               0 :     if (offset_sequence < sequence_end || offset_sequence >= length) {
     186               0 :       return OTS_FAILURE();
     187                 :     }
     188               0 :     if (!ParseSequenceTable(data + offset_sequence, length - offset_sequence,
     189               0 :                             num_glyphs)) {
     190               0 :       return OTS_FAILURE();
     191                 :     }
     192                 :   }
     193                 : 
     194               0 :   if (offset_coverage < sequence_end || offset_coverage >= length) {
     195               0 :     return OTS_FAILURE();
     196                 :   }
     197               0 :   if (!ots::ParseCoverageTable(data + offset_coverage,
     198               0 :                                length - offset_coverage, num_glyphs)) {
     199               0 :     return OTS_FAILURE();
     200                 :   }
     201                 : 
     202               0 :   return true;
     203                 : }
     204                 : 
     205               0 : bool ParseAlternateSetTable(const uint8_t *data, const size_t length,
     206                 :                             const uint16_t num_glyphs) {
     207               0 :   ots::Buffer subtable(data, length);
     208                 : 
     209               0 :   uint16_t glyph_count = 0;
     210               0 :   if (!subtable.ReadU16(&glyph_count)) {
     211               0 :     return OTS_FAILURE();
     212                 :   }
     213               0 :   if (glyph_count > num_glyphs) {
     214               0 :     return OTS_FAILURE();
     215                 :   }
     216               0 :   for (unsigned i = 0; i < glyph_count; ++i) {
     217               0 :     uint16_t alternate = 0;
     218               0 :     if (!subtable.ReadU16(&alternate)) {
     219               0 :       return OTS_FAILURE();
     220                 :     }
     221               0 :     if (alternate >= num_glyphs) {
     222                 :       OTS_WARNING("too arge alternate: %u", alternate);
     223               0 :       return OTS_FAILURE();
     224                 :     }
     225                 :   }
     226               0 :   return true;
     227                 : }
     228                 : 
     229                 : // Lookup Type 3:
     230                 : // Alternate Substitution Subtable
     231               0 : bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
     232                 :                                 const uint8_t *data, const size_t length) {
     233               0 :   ots::Buffer subtable(data, length);
     234                 : 
     235               0 :   uint16_t format = 0;
     236               0 :   uint16_t offset_coverage = 0;
     237               0 :   uint16_t alternate_set_count = 0;
     238                 : 
     239               0 :   if (!subtable.ReadU16(&format) ||
     240               0 :       !subtable.ReadU16(&offset_coverage) ||
     241               0 :       !subtable.ReadU16(&alternate_set_count)) {
     242               0 :     return OTS_FAILURE();
     243                 :   }
     244                 : 
     245               0 :   if (format != 1) {
     246               0 :     return OTS_FAILURE();
     247                 :   }
     248                 : 
     249               0 :   const uint16_t num_glyphs = file->maxp->num_glyphs;
     250                 :   const unsigned alternate_set_end = static_cast<unsigned>(6) +
     251               0 :       alternate_set_count * 2;
     252               0 :   if (alternate_set_end > std::numeric_limits<uint16_t>::max()) {
     253               0 :     return OTS_FAILURE();
     254                 :   }
     255               0 :   for (unsigned i = 0; i < alternate_set_count; ++i) {
     256               0 :     uint16_t offset_alternate_set = 0;
     257               0 :     if (!subtable.ReadU16(&offset_alternate_set)) {
     258               0 :       return OTS_FAILURE();
     259                 :     }
     260               0 :     if (offset_alternate_set < alternate_set_end ||
     261                 :         offset_alternate_set >= length) {
     262               0 :       return OTS_FAILURE();
     263                 :     }
     264               0 :     if (!ParseAlternateSetTable(data + offset_alternate_set,
     265                 :                                 length - offset_alternate_set,
     266               0 :                                 num_glyphs)) {
     267               0 :       return OTS_FAILURE();
     268                 :     }
     269                 :   }
     270                 : 
     271               0 :   if (offset_coverage < alternate_set_end || offset_coverage >= length) {
     272               0 :     return OTS_FAILURE();
     273                 :   }
     274               0 :   if (!ots::ParseCoverageTable(data + offset_coverage,
     275               0 :                                length - offset_coverage, num_glyphs)) {
     276               0 :     return OTS_FAILURE();
     277                 :   }
     278                 : 
     279               0 :   return true;
     280                 : }
     281                 : 
     282               0 : bool ParseLigatureTable(const uint8_t *data, const size_t length,
     283                 :                         const uint16_t num_glyphs) {
     284               0 :   ots::Buffer subtable(data, length);
     285                 : 
     286               0 :   uint16_t lig_glyph = 0;
     287               0 :   uint16_t comp_count = 0;
     288                 : 
     289               0 :   if (!subtable.ReadU16(&lig_glyph) ||
     290               0 :       !subtable.ReadU16(&comp_count)) {
     291               0 :     return OTS_FAILURE();
     292                 :   }
     293                 : 
     294               0 :   if (lig_glyph >= num_glyphs) {
     295                 :     OTS_WARNING("too large lig_glyph: %u", lig_glyph);
     296               0 :     return OTS_FAILURE();
     297                 :   }
     298               0 :   if (comp_count == 0 || comp_count > num_glyphs) {
     299               0 :     return OTS_FAILURE();
     300                 :   }
     301               0 :   for (unsigned i = 0; i < comp_count - static_cast<unsigned>(1); ++i) {
     302               0 :     uint16_t component = 0;
     303               0 :     if (!subtable.ReadU16(&component)) {
     304               0 :       return OTS_FAILURE();
     305                 :     }
     306               0 :     if (component >= num_glyphs) {
     307               0 :       return OTS_FAILURE();
     308                 :     }
     309                 :   }
     310                 : 
     311               0 :   return true;
     312                 : }
     313                 : 
     314               0 : bool ParseLigatureSetTable(const uint8_t *data, const size_t length,
     315                 :                            const uint16_t num_glyphs) {
     316               0 :   ots::Buffer subtable(data, length);
     317                 : 
     318               0 :   uint16_t ligature_count = 0;
     319                 : 
     320               0 :   if (!subtable.ReadU16(&ligature_count)) {
     321               0 :     return OTS_FAILURE();
     322                 :   }
     323                 : 
     324               0 :   const unsigned ligature_end = static_cast<unsigned>(2) + ligature_count * 2;
     325               0 :   if (ligature_end > std::numeric_limits<uint16_t>::max()) {
     326               0 :     return OTS_FAILURE();
     327                 :   }
     328               0 :   for (unsigned i = 0; i < ligature_count; ++i) {
     329               0 :     uint16_t offset_ligature = 0;
     330               0 :     if (!subtable.ReadU16(&offset_ligature)) {
     331               0 :       return OTS_FAILURE();
     332                 :     }
     333               0 :     if (offset_ligature < ligature_end || offset_ligature >= length) {
     334               0 :       return OTS_FAILURE();
     335                 :     }
     336               0 :     if (!ParseLigatureTable(data + offset_ligature, length - offset_ligature,
     337               0 :                             num_glyphs)) {
     338               0 :       return OTS_FAILURE();
     339                 :     }
     340                 :   }
     341                 : 
     342               0 :   return true;
     343                 : }
     344                 : 
     345                 : // Lookup Type 4:
     346                 : // Ligature Substitution Subtable
     347               0 : bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
     348                 :                                const uint8_t *data, const size_t length) {
     349               0 :   ots::Buffer subtable(data, length);
     350                 : 
     351               0 :   uint16_t format = 0;
     352               0 :   uint16_t offset_coverage = 0;
     353               0 :   uint16_t lig_set_count = 0;
     354                 : 
     355               0 :   if (!subtable.ReadU16(&format) ||
     356               0 :       !subtable.ReadU16(&offset_coverage) ||
     357               0 :       !subtable.ReadU16(&lig_set_count)) {
     358               0 :     return OTS_FAILURE();
     359                 :   }
     360                 : 
     361               0 :   if (format != 1) {
     362               0 :     return OTS_FAILURE();
     363                 :   }
     364                 : 
     365               0 :   const uint16_t num_glyphs = file->maxp->num_glyphs;
     366                 :   const unsigned ligature_set_end = static_cast<unsigned>(6) +
     367               0 :       lig_set_count * 2;
     368               0 :   if (ligature_set_end > std::numeric_limits<uint16_t>::max()) {
     369               0 :     return OTS_FAILURE();
     370                 :   }
     371               0 :   for (unsigned i = 0; i < lig_set_count; ++i) {
     372               0 :     uint16_t offset_ligature_set = 0;
     373               0 :     if (!subtable.ReadU16(&offset_ligature_set)) {
     374               0 :       return OTS_FAILURE();
     375                 :     }
     376               0 :     if (offset_ligature_set < ligature_set_end ||
     377                 :         offset_ligature_set >= length) {
     378               0 :       return OTS_FAILURE();
     379                 :     }
     380               0 :     if (!ParseLigatureSetTable(data + offset_ligature_set,
     381               0 :                                length - offset_ligature_set, num_glyphs)) {
     382               0 :       return OTS_FAILURE();
     383                 :     }
     384                 :   }
     385                 : 
     386               0 :   if (offset_coverage < ligature_set_end || offset_coverage >= length) {
     387               0 :     return OTS_FAILURE();
     388                 :   }
     389               0 :   if (!ots::ParseCoverageTable(data + offset_coverage,
     390               0 :                                length - offset_coverage, num_glyphs)) {
     391               0 :     return OTS_FAILURE();
     392                 :   }
     393                 : 
     394               0 :   return true;
     395                 : }
     396                 : 
     397                 : // Lookup Type 5:
     398                 : // Contextual Substitution Subtable
     399               0 : bool ParseContextSubstitution(const ots::OpenTypeFile *file,
     400                 :                               const uint8_t *data, const size_t length) {
     401                 :   return ots::ParseContextSubtable(data, length, file->maxp->num_glyphs,
     402               0 :                                    file->gsub->num_lookups);
     403                 : }
     404                 : 
     405                 : // Lookup Type 6:
     406                 : // Chaining Contextual Substitution Subtable
     407               0 : bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
     408                 :                                       const uint8_t *data,
     409                 :                                       const size_t length) {
     410                 :   return ots::ParseChainingContextSubtable(data, length,
     411                 :                                            file->maxp->num_glyphs,
     412               0 :                                            file->gsub->num_lookups);
     413                 : }
     414                 : 
     415                 : // Lookup Type 7:
     416                 : // Extension Substition
     417               0 : bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
     418                 :                                 const uint8_t *data, const size_t length) {
     419                 :   return ots::ParseExtensionSubtable(file, data, length,
     420               0 :                                      &kGsubLookupSubtableParser);
     421                 : }
     422                 : 
     423                 : // Lookup Type 8:
     424                 : // Reverse Chaining Contexual Single Substitution Subtable
     425               0 : bool ParseReverseChainingContextSingleSubstitution(
     426                 :     const ots::OpenTypeFile *file, const uint8_t *data, const size_t length) {
     427               0 :   ots::Buffer subtable(data, length);
     428                 : 
     429               0 :   uint16_t format = 0;
     430               0 :   uint16_t offset_coverage = 0;
     431                 : 
     432               0 :   if (!subtable.ReadU16(&format) ||
     433               0 :       !subtable.ReadU16(&offset_coverage)) {
     434               0 :     return OTS_FAILURE();
     435                 :   }
     436                 : 
     437               0 :   const uint16_t num_glyphs = file->maxp->num_glyphs;
     438                 : 
     439               0 :   uint16_t backtrack_glyph_count = 0;
     440               0 :   if (!subtable.ReadU16(&backtrack_glyph_count)) {
     441               0 :     return OTS_FAILURE();
     442                 :   }
     443               0 :   if (backtrack_glyph_count > num_glyphs) {
     444               0 :     return OTS_FAILURE();
     445                 :   }
     446               0 :   std::vector<uint16_t> offsets_backtrack;
     447               0 :   offsets_backtrack.reserve(backtrack_glyph_count);
     448               0 :   for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
     449               0 :     uint16_t offset = 0;
     450               0 :     if (!subtable.ReadU16(&offset)) {
     451               0 :       return OTS_FAILURE();
     452                 :     }
     453               0 :     offsets_backtrack.push_back(offset);
     454                 :   }
     455                 : 
     456               0 :   uint16_t lookahead_glyph_count = 0;
     457               0 :   if (!subtable.ReadU16(&lookahead_glyph_count)) {
     458               0 :     return OTS_FAILURE();
     459                 :   }
     460               0 :   if (lookahead_glyph_count > num_glyphs) {
     461               0 :     return OTS_FAILURE();
     462                 :   }
     463               0 :   std::vector<uint16_t> offsets_lookahead;
     464               0 :   offsets_lookahead.reserve(lookahead_glyph_count);
     465               0 :   for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
     466               0 :     uint16_t offset = 0;
     467               0 :     if (!subtable.ReadU16(&offset)) {
     468               0 :       return OTS_FAILURE();
     469                 :     }
     470               0 :     offsets_lookahead.push_back(offset);
     471                 :   }
     472                 : 
     473               0 :   uint16_t glyph_count = 0;
     474               0 :   if (!subtable.ReadU16(&glyph_count)) {
     475               0 :     return OTS_FAILURE();
     476                 :   }
     477               0 :   if (glyph_count > num_glyphs) {
     478               0 :     return OTS_FAILURE();
     479                 :   }
     480               0 :   for (unsigned i = 0; i < glyph_count; ++i) {
     481               0 :     uint16_t substitute = 0;
     482               0 :     if (!subtable.ReadU16(&substitute)) {
     483               0 :       return OTS_FAILURE();
     484                 :     }
     485               0 :     if (substitute >= num_glyphs) {
     486               0 :       return OTS_FAILURE();
     487                 :     }
     488                 :   }
     489                 : 
     490                 :   const unsigned substitute_end = static_cast<unsigned>(10) +
     491               0 :       (backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2;
     492               0 :   if (substitute_end > std::numeric_limits<uint16_t>::max()) {
     493               0 :     return OTS_FAILURE();
     494                 :   }
     495                 : 
     496               0 :   if (offset_coverage < substitute_end || offset_coverage >= length) {
     497               0 :     return OTS_FAILURE();
     498                 :   }
     499               0 :   if (!ots::ParseCoverageTable(data + offset_coverage,
     500               0 :                                length - offset_coverage, num_glyphs)) {
     501               0 :     return OTS_FAILURE();
     502                 :   }
     503                 : 
     504               0 :   for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
     505               0 :     if (offsets_backtrack[i] < substitute_end ||
     506               0 :         offsets_backtrack[i] >= length) {
     507               0 :       return OTS_FAILURE();
     508                 :     }
     509               0 :     if (!ots::ParseCoverageTable(data + offsets_backtrack[i],
     510               0 :                                  length - offsets_backtrack[i], num_glyphs)) {
     511               0 :       return OTS_FAILURE();
     512                 :     }
     513                 :   }
     514                 : 
     515               0 :   for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
     516               0 :     if (offsets_lookahead[i] < substitute_end ||
     517               0 :         offsets_lookahead[i] >= length) {
     518               0 :       return OTS_FAILURE();
     519                 :     }
     520               0 :     if (!ots::ParseCoverageTable(data + offsets_lookahead[i],
     521               0 :                                  length - offsets_lookahead[i], num_glyphs)) {
     522               0 :       return OTS_FAILURE();
     523                 :     }
     524                 :   }
     525                 : 
     526               0 :   return true;
     527                 : }
     528                 : 
     529                 : }  // namespace
     530                 : 
     531                 : #define DROP_THIS_TABLE \
     532                 :   do { file->gsub->data = 0; file->gsub->length = 0; } while (0)
     533                 : 
     534                 : namespace ots {
     535                 : 
     536                 : // As far as I checked, following fonts contain invalid values in GSUB table.
     537                 : // OTS will drop their GSUB table.
     538                 : //
     539                 : // # too large substitute (value is 0xFFFF)
     540                 : // kaiu.ttf
     541                 : // mingliub2.ttf
     542                 : // mingliub1.ttf
     543                 : // mingliub0.ttf
     544                 : // GraublauWeb.otf
     545                 : // GraublauWebBold.otf
     546                 : //
     547                 : // # too large alternate (value is 0xFFFF)
     548                 : // ManchuFont.ttf
     549                 : //
     550                 : // # bad offset to lang sys table (NULL offset)
     551                 : // DejaVuMonoSansBold.ttf
     552                 : // DejaVuMonoSansBoldOblique.ttf
     553                 : // DejaVuMonoSansOblique.ttf
     554                 : // DejaVuSansMono-BoldOblique.ttf
     555                 : // DejaVuSansMono-Oblique.ttf
     556                 : // DejaVuSansMono-Bold.ttf
     557                 : //
     558                 : // # bad start coverage index
     559                 : // GenBasBI.ttf
     560                 : // GenBasI.ttf
     561                 : // AndBasR.ttf
     562                 : // GenBkBasI.ttf
     563                 : // CharisSILR.ttf
     564                 : // CharisSILBI.ttf
     565                 : // CharisSILI.ttf
     566                 : // CharisSILB.ttf
     567                 : // DoulosSILR.ttf
     568                 : // CharisSILBI.ttf
     569                 : // GenBkBasB.ttf
     570                 : // GenBkBasR.ttf
     571                 : // GenBkBasBI.ttf
     572                 : // GenBasB.ttf
     573                 : // GenBasR.ttf
     574                 : //
     575                 : // # glyph range is overlapping
     576                 : // KacstTitleL.ttf
     577                 : // KacstDecorative.ttf
     578                 : // KacstTitle.ttf
     579                 : // KacstArt.ttf
     580                 : // KacstPoster.ttf
     581                 : // KacstQurn.ttf
     582                 : // KacstDigital.ttf
     583                 : // KacstBook.ttf
     584                 : // KacstFarsi.ttf
     585                 : 
     586               0 : bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
     587                 :   // Parsing gsub table requires |file->maxp->num_glyphs|
     588               0 :   if (!file->maxp) {
     589               0 :     return OTS_FAILURE();
     590                 :   }
     591                 : 
     592               0 :   Buffer table(data, length);
     593                 : 
     594               0 :   OpenTypeGSUB *gsub = new OpenTypeGSUB;
     595               0 :   file->gsub = gsub;
     596                 : 
     597               0 :   uint32_t version = 0;
     598               0 :   uint16_t offset_script_list = 0;
     599               0 :   uint16_t offset_feature_list = 0;
     600               0 :   uint16_t offset_lookup_list = 0;
     601               0 :   if (!table.ReadU32(&version) ||
     602               0 :       !table.ReadU16(&offset_script_list) ||
     603               0 :       !table.ReadU16(&offset_feature_list) ||
     604               0 :       !table.ReadU16(&offset_lookup_list)) {
     605               0 :     return OTS_FAILURE();
     606                 :   }
     607                 : 
     608               0 :   if (version != 0x00010000) {
     609                 :     OTS_WARNING("bad GSUB version");
     610               0 :     DROP_THIS_TABLE;
     611               0 :     return true;
     612                 :   }
     613               0 :   if ((offset_script_list < kGsubHeaderSize ||
     614                 :        offset_script_list >= length) ||
     615                 :       (offset_feature_list < kGsubHeaderSize ||
     616                 :        offset_feature_list >= length) ||
     617                 :       (offset_lookup_list < kGsubHeaderSize ||
     618                 :        offset_lookup_list >= length)) {
     619                 :     OTS_WARNING("bad offset in GSUB header");
     620               0 :     DROP_THIS_TABLE;
     621               0 :     return true;
     622                 :   }
     623                 : 
     624               0 :   if (!ParseLookupListTable(file, data + offset_lookup_list,
     625                 :                             length - offset_lookup_list,
     626                 :                             &kGsubLookupSubtableParser,
     627               0 :                             &gsub->num_lookups)) {
     628                 :     OTS_WARNING("faild to parse lookup list table");
     629               0 :     DROP_THIS_TABLE;
     630               0 :     return true;
     631                 :   }
     632                 : 
     633               0 :   uint16_t num_features = 0;
     634               0 :   if (!ParseFeatureListTable(data + offset_feature_list,
     635                 :                              length - offset_feature_list, gsub->num_lookups,
     636               0 :                              &num_features)) {
     637                 :     OTS_WARNING("faild to parse feature list table");
     638               0 :     DROP_THIS_TABLE;
     639               0 :     return true;
     640                 :   }
     641                 : 
     642               0 :   if (!ParseScriptListTable(data + offset_script_list,
     643               0 :                             length - offset_script_list, num_features)) {
     644                 :     OTS_WARNING("faild to parse script list table");
     645               0 :     DROP_THIS_TABLE;
     646               0 :     return true;
     647                 :   }
     648                 : 
     649               0 :   gsub->data = data;
     650               0 :   gsub->length = length;
     651               0 :   return true;
     652                 : }
     653                 : 
     654               0 : bool ots_gsub_should_serialise(OpenTypeFile *file) {
     655                 :   const bool needed_tables_dropped =
     656                 :       (file->gdef && file->gdef->data == NULL) ||
     657               0 :       (file->gpos && file->gpos->data == NULL);
     658                 :   return file->gsub != NULL && file->gsub->data != NULL
     659               0 :       && !needed_tables_dropped;
     660                 : }
     661                 : 
     662               0 : bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) {
     663               0 :   if (!out->Write(file->gsub->data, file->gsub->length)) {
     664               0 :     return OTS_FAILURE();
     665                 :   }
     666                 : 
     667               0 :   return true;
     668                 : }
     669                 : 
     670               0 : void ots_gsub_free(OpenTypeFile *file) {
     671               0 :   delete file->gsub;
     672               0 : }
     673                 : 
     674                 : }  // namespace ots
     675                 : 

Generated by: LCOV version 1.7