LCOV - code coverage report
Current view: top level - gfx/ots/src - gsub.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 305 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "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             : // The GSUB header size
      21             : const size_t kGsubHeaderSize = 4 + 3 * 2;
      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::Font *font,
      37             :                              const uint8_t *data, const size_t length);
      38             : bool ParseMutipleSubstitution(const ots::Font *font,
      39             :                               const uint8_t *data, const size_t length);
      40             : bool ParseAlternateSubstitution(const ots::Font *font,
      41             :                                 const uint8_t *data, const size_t length);
      42             : bool ParseLigatureSubstitution(const ots::Font *font,
      43             :       const uint8_t *data, const size_t length);
      44             : bool ParseContextSubstitution(const ots::Font *font,
      45             :                               const uint8_t *data, const size_t length);
      46             : bool ParseChainingContextSubstitution(const ots::Font *font,
      47             :                                       const uint8_t *data,
      48             :                                       const size_t length);
      49             : bool ParseExtensionSubstitution(const ots::Font *font,
      50             :                                 const uint8_t *data, const size_t length);
      51             : bool ParseReverseChainingContextSingleSubstitution(
      52             :     const ots::Font *font, 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             : const ots::LookupSubtableParser kGsubLookupSubtableParser = {
      67             :   arraysize(kGsubTypeParsers),
      68             :   GSUB_TYPE_EXTENSION_SUBSTITUTION, kGsubTypeParsers
      69             : };
      70             : 
      71             : // Lookup Type 1:
      72             : // Single Substitution Subtable
      73           0 : bool ParseSingleSubstitution(const ots::Font *font,
      74             :                              const uint8_t *data, const size_t length) {
      75           0 :   ots::Buffer subtable(data, length);
      76             : 
      77           0 :   uint16_t format = 0;
      78           0 :   uint16_t offset_coverage = 0;
      79             : 
      80           0 :   if (!subtable.ReadU16(&format) ||
      81           0 :       !subtable.ReadU16(&offset_coverage)) {
      82           0 :     return OTS_FAILURE_MSG("Failed to read single subst table header");
      83             :   }
      84             : 
      85           0 :   const uint16_t num_glyphs = font->maxp->num_glyphs;
      86           0 :   if (format == 1) {
      87             :     // Parse SingleSubstFormat1
      88           0 :     int16_t delta_glyph_id = 0;
      89           0 :     if (!subtable.ReadS16(&delta_glyph_id)) {
      90           0 :       return OTS_FAILURE_MSG("Failed to read glyph shift from format 1 single subst table");
      91             :     }
      92           0 :     if (std::abs(delta_glyph_id) >= num_glyphs) {
      93           0 :       return OTS_FAILURE_MSG("bad glyph shift of %d in format 1 single subst table", delta_glyph_id);
      94             :     }
      95           0 :   } else if (format == 2) {
      96             :     // Parse SingleSubstFormat2
      97           0 :     uint16_t glyph_count = 0;
      98           0 :     if (!subtable.ReadU16(&glyph_count)) {
      99           0 :       return OTS_FAILURE_MSG("Failed to read glyph cound in format 2 single subst table");
     100             :     }
     101           0 :     if (glyph_count > num_glyphs) {
     102           0 :       return OTS_FAILURE_MSG("Bad glyph count %d > %d in format 2 single subst table", glyph_count, num_glyphs);
     103             :     }
     104           0 :     for (unsigned i = 0; i < glyph_count; ++i) {
     105           0 :       uint16_t substitute = 0;
     106           0 :       if (!subtable.ReadU16(&substitute)) {
     107           0 :         return OTS_FAILURE_MSG("Failed to read substitution %d in format 2 single subst table", i);
     108             :       }
     109           0 :       if (substitute >= num_glyphs) {
     110           0 :         return OTS_FAILURE_MSG("too large substitute: %u", substitute);
     111             :       }
     112             :     }
     113             :   } else {
     114           0 :     return OTS_FAILURE_MSG("Bad single subst table format %d", format);
     115             :   }
     116             : 
     117           0 :   if (offset_coverage < subtable.offset() || offset_coverage >= length) {
     118           0 :     return OTS_FAILURE_MSG("Bad coverage offset %x", offset_coverage);
     119             :   }
     120           0 :   if (!ots::ParseCoverageTable(font, data + offset_coverage,
     121             :                                length - offset_coverage, num_glyphs)) {
     122           0 :     return OTS_FAILURE_MSG("Failed to parse coverage table");
     123             :   }
     124             : 
     125           0 :   return true;
     126             : }
     127             : 
     128           0 : bool ParseSequenceTable(const ots::Font *font,
     129             :                         const uint8_t *data, const size_t length,
     130             :                         const uint16_t num_glyphs) {
     131           0 :   ots::Buffer subtable(data, length);
     132             : 
     133           0 :   uint16_t glyph_count = 0;
     134           0 :   if (!subtable.ReadU16(&glyph_count)) {
     135           0 :     return OTS_FAILURE_MSG("Failed to read glyph count in sequence table");
     136             :   }
     137           0 :   if (glyph_count > num_glyphs) {
     138           0 :     return OTS_FAILURE_MSG("bad glyph count %d > %d", glyph_count, num_glyphs);
     139             :   }
     140           0 :   for (unsigned i = 0; i < glyph_count; ++i) {
     141           0 :     uint16_t substitute = 0;
     142           0 :     if (!subtable.ReadU16(&substitute)) {
     143           0 :       return OTS_FAILURE_MSG("Failedt o read substitution %d in sequence table", i);
     144             :     }
     145           0 :     if (substitute >= num_glyphs) {
     146           0 :       return OTS_FAILURE_MSG("Bad subsitution (%d) %d > %d", i, substitute, num_glyphs);
     147             :     }
     148             :   }
     149             : 
     150           0 :   return true;
     151             : }
     152             : 
     153             : // Lookup Type 2:
     154             : // Multiple Substitution Subtable
     155           0 : bool ParseMutipleSubstitution(const ots::Font *font,
     156             :                               const uint8_t *data, const size_t length) {
     157           0 :   ots::Buffer subtable(data, length);
     158             : 
     159           0 :   uint16_t format = 0;
     160           0 :   uint16_t offset_coverage = 0;
     161           0 :   uint16_t sequence_count = 0;
     162             : 
     163           0 :   if (!subtable.ReadU16(&format) ||
     164           0 :       !subtable.ReadU16(&offset_coverage) ||
     165           0 :       !subtable.ReadU16(&sequence_count)) {
     166           0 :     return OTS_FAILURE_MSG("Can't read header of multiple subst table");
     167             :   }
     168             : 
     169           0 :   if (format != 1) {
     170           0 :     return OTS_FAILURE_MSG("Bad multiple subst table format %d", format);
     171             :   }
     172             : 
     173           0 :   const uint16_t num_glyphs = font->maxp->num_glyphs;
     174             :   const unsigned sequence_end = static_cast<unsigned>(6) +
     175           0 :       sequence_count * 2;
     176           0 :   if (sequence_end > std::numeric_limits<uint16_t>::max()) {
     177           0 :     return OTS_FAILURE_MSG("Bad segence end %d, in multiple subst", sequence_end);
     178             :   }
     179           0 :   for (unsigned i = 0; i < sequence_count; ++i) {
     180           0 :     uint16_t offset_sequence = 0;
     181           0 :     if (!subtable.ReadU16(&offset_sequence)) {
     182           0 :       return OTS_FAILURE_MSG("Failed to read sequence offset for sequence %d", i);
     183             :     }
     184           0 :     if (offset_sequence < sequence_end || offset_sequence >= length) {
     185           0 :       return OTS_FAILURE_MSG("Bad sequence offset %d for sequence %d", offset_sequence, i);
     186             :     }
     187           0 :     if (!ParseSequenceTable(font, data + offset_sequence, length - offset_sequence,
     188             :                             num_glyphs)) {
     189           0 :       return OTS_FAILURE_MSG("Failed to parse sequence table %d", i);
     190             :     }
     191             :   }
     192             : 
     193           0 :   if (offset_coverage < sequence_end || offset_coverage >= length) {
     194           0 :     return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
     195             :   }
     196           0 :   if (!ots::ParseCoverageTable(font, data + offset_coverage,
     197             :                                length - offset_coverage, num_glyphs)) {
     198           0 :     return OTS_FAILURE_MSG("Failed to parse coverage table");
     199             :   }
     200             : 
     201           0 :   return true;
     202             : }
     203             : 
     204           0 : bool ParseAlternateSetTable(const ots::Font *font,
     205             :                             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_MSG("Failed to read alternate set header");
     212             :   }
     213           0 :   if (glyph_count > num_glyphs) {
     214           0 :     return OTS_FAILURE_MSG("Bad glyph count %d > %d in alternate set table", glyph_count, num_glyphs);
     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_MSG("Can't read alternate %d", i);
     220             :     }
     221           0 :     if (alternate >= num_glyphs) {
     222           0 :       return OTS_FAILURE_MSG("Too large alternate: %u", alternate);
     223             :     }
     224             :   }
     225           0 :   return true;
     226             : }
     227             : 
     228             : // Lookup Type 3:
     229             : // Alternate Substitution Subtable
     230           0 : bool ParseAlternateSubstitution(const ots::Font *font,
     231             :                                 const uint8_t *data, const size_t length) {
     232           0 :   ots::Buffer subtable(data, length);
     233             : 
     234           0 :   uint16_t format = 0;
     235           0 :   uint16_t offset_coverage = 0;
     236           0 :   uint16_t alternate_set_count = 0;
     237             : 
     238           0 :   if (!subtable.ReadU16(&format) ||
     239           0 :       !subtable.ReadU16(&offset_coverage) ||
     240           0 :       !subtable.ReadU16(&alternate_set_count)) {
     241           0 :     return OTS_FAILURE_MSG("Can't read alternate subst header");
     242             :   }
     243             : 
     244           0 :   if (format != 1) {
     245           0 :     return OTS_FAILURE_MSG("Bad alternate subst table format %d", format);
     246             :   }
     247             : 
     248           0 :   const uint16_t num_glyphs = font->maxp->num_glyphs;
     249             :   const unsigned alternate_set_end = static_cast<unsigned>(6) +
     250           0 :       alternate_set_count * 2;
     251           0 :   if (alternate_set_end > std::numeric_limits<uint16_t>::max()) {
     252           0 :     return OTS_FAILURE_MSG("Bad end of alternate set %d", alternate_set_end);
     253             :   }
     254           0 :   for (unsigned i = 0; i < alternate_set_count; ++i) {
     255           0 :     uint16_t offset_alternate_set = 0;
     256           0 :     if (!subtable.ReadU16(&offset_alternate_set)) {
     257           0 :       return OTS_FAILURE_MSG("Can't read alternate set offset for set %d", i);
     258             :     }
     259           0 :     if (offset_alternate_set < alternate_set_end ||
     260           0 :         offset_alternate_set >= length) {
     261           0 :       return OTS_FAILURE_MSG("Bad alternate set offset %d for set %d", offset_alternate_set, i);
     262             :     }
     263           0 :     if (!ParseAlternateSetTable(font, data + offset_alternate_set,
     264             :                                 length - offset_alternate_set,
     265             :                                 num_glyphs)) {
     266           0 :       return OTS_FAILURE_MSG("Failed to parse alternate set");
     267             :     }
     268             :   }
     269             : 
     270           0 :   if (offset_coverage < alternate_set_end || offset_coverage >= length) {
     271           0 :     return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
     272             :   }
     273           0 :   if (!ots::ParseCoverageTable(font, data + offset_coverage,
     274             :                                length - offset_coverage, num_glyphs)) {
     275           0 :     return OTS_FAILURE_MSG("Failed to parse coverage table");
     276             :   }
     277             : 
     278           0 :   return true;
     279             : }
     280             : 
     281           0 : bool ParseLigatureTable(const ots::Font *font,
     282             :                         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_MSG("Failed to read ligatuer table header");
     292             :   }
     293             : 
     294           0 :   if (lig_glyph >= num_glyphs) {
     295           0 :     return OTS_FAILURE_MSG("too large lig_glyph: %u", lig_glyph);
     296             :   }
     297           0 :   if (comp_count == 0 || comp_count > num_glyphs) {
     298           0 :     return OTS_FAILURE_MSG("Bad component count of %d", comp_count);
     299             :   }
     300           0 :   for (unsigned i = 0; i < comp_count - static_cast<unsigned>(1); ++i) {
     301           0 :     uint16_t component = 0;
     302           0 :     if (!subtable.ReadU16(&component)) {
     303           0 :       return OTS_FAILURE_MSG("Can't read ligature component %d", i);
     304             :     }
     305           0 :     if (component >= num_glyphs) {
     306           0 :       return OTS_FAILURE_MSG("Bad ligature component %d of %d", i, component);
     307             :     }
     308             :   }
     309             : 
     310           0 :   return true;
     311             : }
     312             : 
     313           0 : bool ParseLigatureSetTable(const ots::Font *font,
     314             :                            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_MSG("Can't read ligature count in ligature set");
     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_MSG("Bad end of ligature %d in ligature set", ligature_end);
     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_MSG("Failed to read ligature offset %d", i);
     332             :     }
     333           0 :     if (offset_ligature < ligature_end || offset_ligature >= length) {
     334           0 :       return OTS_FAILURE_MSG("Bad ligature offset %d for ligature %d", offset_ligature, i);
     335             :     }
     336           0 :     if (!ParseLigatureTable(font, data + offset_ligature, length - offset_ligature,
     337             :                             num_glyphs)) {
     338           0 :       return OTS_FAILURE_MSG("Failed to parse ligature %d", i);
     339             :     }
     340             :   }
     341             : 
     342           0 :   return true;
     343             : }
     344             : 
     345             : // Lookup Type 4:
     346             : // Ligature Substitution Subtable
     347           0 : bool ParseLigatureSubstitution(const ots::Font *font,
     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_MSG("Failed to read ligature substitution header");
     359             :   }
     360             : 
     361           0 :   if (format != 1) {
     362           0 :     return OTS_FAILURE_MSG("Bad ligature substitution table format %d", format);
     363             :   }
     364             : 
     365           0 :   const uint16_t num_glyphs = font->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_MSG("Bad end of ligature set %d in ligature substitution table", ligature_set_end);
     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_MSG("Can't read ligature set offset %d", i);
     375             :     }
     376           0 :     if (offset_ligature_set < ligature_set_end ||
     377           0 :         offset_ligature_set >= length) {
     378           0 :       return OTS_FAILURE_MSG("Bad ligature set offset %d for set %d", offset_ligature_set, i);
     379             :     }
     380           0 :     if (!ParseLigatureSetTable(font, data + offset_ligature_set,
     381             :                                length - offset_ligature_set, num_glyphs)) {
     382           0 :       return OTS_FAILURE_MSG("Failed to parse ligature set %d", i);
     383             :     }
     384             :   }
     385             : 
     386           0 :   if (offset_coverage < ligature_set_end || offset_coverage >= length) {
     387           0 :     return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
     388             :   }
     389           0 :   if (!ots::ParseCoverageTable(font, data + offset_coverage,
     390             :                                length - offset_coverage, num_glyphs)) {
     391           0 :     return OTS_FAILURE_MSG("Failed to parse coverage table");
     392             :   }
     393             : 
     394           0 :   return true;
     395             : }
     396             : 
     397             : // Lookup Type 5:
     398             : // Contextual Substitution Subtable
     399           0 : bool ParseContextSubstitution(const ots::Font *font,
     400             :                               const uint8_t *data, const size_t length) {
     401           0 :   return ots::ParseContextSubtable(font, data, length, font->maxp->num_glyphs,
     402           0 :                                    font->gsub->num_lookups);
     403             : }
     404             : 
     405             : // Lookup Type 6:
     406             : // Chaining Contextual Substitution Subtable
     407           0 : bool ParseChainingContextSubstitution(const ots::Font *font,
     408             :                                       const uint8_t *data,
     409             :                                       const size_t length) {
     410           0 :   return ots::ParseChainingContextSubtable(font, data, length,
     411           0 :                                            font->maxp->num_glyphs,
     412           0 :                                            font->gsub->num_lookups);
     413             : }
     414             : 
     415             : // Lookup Type 7:
     416             : // Extension Substition
     417           0 : bool ParseExtensionSubstitution(const ots::Font *font,
     418             :                                 const uint8_t *data, const size_t length) {
     419             :   return ots::ParseExtensionSubtable(font, 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::Font *font, 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_MSG("Failed to read reverse chaining header");
     435             :   }
     436             : 
     437           0 :   const uint16_t num_glyphs = font->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_MSG("Failed to read backtrack glyph count in reverse chaining table");
     442             :   }
     443           0 :   if (backtrack_glyph_count > num_glyphs) {
     444           0 :     return OTS_FAILURE_MSG("Bad backtrack glyph count of %d", backtrack_glyph_count);
     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_MSG("Failed to read backtrack offset %d", i);
     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_MSG("Failed to read look ahead glyph count");
     459             :   }
     460           0 :   if (lookahead_glyph_count > num_glyphs) {
     461           0 :     return OTS_FAILURE_MSG("Bad look ahead glyph count %d", lookahead_glyph_count);
     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_MSG("Can't read look ahead offset %d", i);
     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_MSG("Can't read glyph count in reverse chaining table");
     476             :   }
     477           0 :   if (glyph_count > num_glyphs) {
     478           0 :     return OTS_FAILURE_MSG("Bad glyph count of %d", glyph_count);
     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_MSG("Failed to read substitution %d reverse chaining table", i);
     484             :     }
     485           0 :     if (substitute >= num_glyphs) {
     486           0 :       return OTS_FAILURE_MSG("Bad substitute glyph %d in reverse chaining table substitution %d", substitute, i);
     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_MSG("Bad substitute end offset in reverse chaining table");
     494             :   }
     495             : 
     496           0 :   if (offset_coverage < substitute_end || offset_coverage >= length) {
     497           0 :     return OTS_FAILURE_MSG("Bad coverage offset %d in reverse chaining table", offset_coverage);
     498             :   }
     499           0 :   if (!ots::ParseCoverageTable(font, data + offset_coverage,
     500             :                                length - offset_coverage, num_glyphs)) {
     501           0 :     return OTS_FAILURE_MSG("Failed to parse coverage table in reverse chaining table");
     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_MSG("Bad backtrack offset %d for backtrack %d in reverse chaining table", offsets_backtrack[i], i);
     508             :     }
     509           0 :     if (!ots::ParseCoverageTable(font, data + offsets_backtrack[i],
     510           0 :                                  length - offsets_backtrack[i], num_glyphs)) {
     511           0 :       return OTS_FAILURE_MSG("Failed to parse coverage table for backtrack %d in reverse chaining table", i);
     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_MSG("Bad lookahead offset %d for lookahead %d in reverse chaining table", offsets_lookahead[i], i);
     519             :     }
     520           0 :     if (!ots::ParseCoverageTable(font, data + offsets_lookahead[i],
     521           0 :                                  length - offsets_lookahead[i], num_glyphs)) {
     522           0 :       return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in reverse chaining table", i);
     523             :     }
     524             :   }
     525             : 
     526           0 :   return true;
     527             : }
     528             : 
     529             : }  // namespace
     530             : 
     531             : namespace ots {
     532             : 
     533             : // As far as I checked, following fonts contain invalid values in GSUB table.
     534             : // OTS will drop their GSUB table.
     535             : //
     536             : // # too large substitute (value is 0xFFFF)
     537             : // kaiu.ttf
     538             : // mingliub2.ttf
     539             : // mingliub1.ttf
     540             : // mingliub0.ttf
     541             : // GraublauWeb.otf
     542             : // GraublauWebBold.otf
     543             : //
     544             : // # too large alternate (value is 0xFFFF)
     545             : // ManchuFont.ttf
     546             : //
     547             : // # bad offset to lang sys table (NULL offset)
     548             : // DejaVuMonoSansBold.ttf
     549             : // DejaVuMonoSansBoldOblique.ttf
     550             : // DejaVuMonoSansOblique.ttf
     551             : // DejaVuSansMono-BoldOblique.ttf
     552             : // DejaVuSansMono-Oblique.ttf
     553             : // DejaVuSansMono-Bold.ttf
     554             : //
     555             : // # bad start coverage index
     556             : // GenBasBI.ttf
     557             : // GenBasI.ttf
     558             : // AndBasR.ttf
     559             : // GenBkBasI.ttf
     560             : // CharisSILR.ttf
     561             : // CharisSILBI.ttf
     562             : // CharisSILI.ttf
     563             : // CharisSILB.ttf
     564             : // DoulosSILR.ttf
     565             : // CharisSILBI.ttf
     566             : // GenBkBasB.ttf
     567             : // GenBkBasR.ttf
     568             : // GenBkBasBI.ttf
     569             : // GenBasB.ttf
     570             : // GenBasR.ttf
     571             : //
     572             : // # glyph range is overlapping
     573             : // KacstTitleL.ttf
     574             : // KacstDecorative.ttf
     575             : // KacstTitle.ttf
     576             : // KacstArt.ttf
     577             : // KacstPoster.ttf
     578             : // KacstQurn.ttf
     579             : // KacstDigital.ttf
     580             : // KacstBook.ttf
     581             : // KacstFarsi.ttf
     582             : 
     583           0 : bool ots_gsub_parse(Font *font, const uint8_t *data, size_t length) {
     584             :   // Parsing gsub table requires |font->maxp->num_glyphs|
     585           0 :   if (!font->maxp) {
     586           0 :     return OTS_FAILURE_MSG("Missing maxp table in font, needed by GSUB");
     587             :   }
     588             : 
     589           0 :   Buffer table(data, length);
     590             : 
     591           0 :   OpenTypeGSUB *gsub = new OpenTypeGSUB;
     592           0 :   font->gsub = gsub;
     593             : 
     594           0 :   uint32_t version = 0;
     595           0 :   uint16_t offset_script_list = 0;
     596           0 :   uint16_t offset_feature_list = 0;
     597           0 :   uint16_t offset_lookup_list = 0;
     598           0 :   if (!table.ReadU32(&version) ||
     599           0 :       !table.ReadU16(&offset_script_list) ||
     600           0 :       !table.ReadU16(&offset_feature_list) ||
     601           0 :       !table.ReadU16(&offset_lookup_list)) {
     602           0 :     return OTS_FAILURE_MSG("Incomplete table");
     603             :   }
     604             : 
     605           0 :   if (version != 0x00010000) {
     606           0 :     return OTS_FAILURE_MSG("Bad version");
     607             :   }
     608             : 
     609           0 :   if (offset_lookup_list) {
     610           0 :     if (offset_lookup_list < kGsubHeaderSize || offset_lookup_list >= length) {
     611           0 :       return OTS_FAILURE_MSG("Bad lookup list offset in table header");
     612             :     }
     613             : 
     614           0 :     if (!ParseLookupListTable(font, data + offset_lookup_list,
     615             :                               length - offset_lookup_list,
     616             :                               &kGsubLookupSubtableParser,
     617             :                               &gsub->num_lookups)) {
     618           0 :       return OTS_FAILURE_MSG("Failed to parse lookup list table");
     619             :     }
     620             :   }
     621             : 
     622           0 :   uint16_t num_features = 0;
     623           0 :   if (offset_feature_list) {
     624           0 :     if (offset_feature_list < kGsubHeaderSize || offset_feature_list >= length) {
     625           0 :       return OTS_FAILURE_MSG("Bad feature list offset in table header");
     626             :     }
     627             : 
     628           0 :     if (!ParseFeatureListTable(font, data + offset_feature_list,
     629           0 :                                length - offset_feature_list, gsub->num_lookups,
     630             :                                &num_features)) {
     631           0 :       return OTS_FAILURE_MSG("Failed to parse feature list table");
     632             :     }
     633             :   }
     634             : 
     635           0 :   if (offset_script_list) {
     636           0 :     if (offset_script_list < kGsubHeaderSize || offset_script_list >= length) {
     637           0 :       return OTS_FAILURE_MSG("Bad script list offset in table header");
     638             :     }
     639             : 
     640           0 :     if (!ParseScriptListTable(font, data + offset_script_list,
     641             :                               length - offset_script_list, num_features)) {
     642           0 :       return OTS_FAILURE_MSG("Failed to parse script list table");
     643             :     }
     644             :   }
     645             : 
     646           0 :   gsub->data = data;
     647           0 :   gsub->length = length;
     648           0 :   return true;
     649             : }
     650             : 
     651           0 : bool ots_gsub_should_serialise(Font *font) {
     652           0 :   return font->gsub != NULL && font->gsub->data != NULL;
     653             : }
     654             : 
     655           0 : bool ots_gsub_serialise(OTSStream *out, Font *font) {
     656           0 :   if (!out->Write(font->gsub->data, font->gsub->length)) {
     657           0 :     return OTS_FAILURE_MSG("Failed to write GSUB table");
     658             :   }
     659             : 
     660           0 :   return true;
     661             : }
     662             : 
     663           0 : void ots_gsub_reuse(Font *font, Font *other) {
     664           0 :   font->gsub = other->gsub;
     665           0 :   font->gsub_reused = true;
     666           0 : }
     667             : 
     668           0 : void ots_gsub_free(Font *font) {
     669           0 :   delete font->gsub;
     670           0 : }
     671             : 
     672             : }  // namespace ots
     673             : 
     674             : #undef TABLE_NAME

Generated by: LCOV version 1.13