LCOV - app.info - gfx/ots/src/gsub.cc

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-04-21 | 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