1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/ots/src/gsub.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,671 @@ 1.4 +// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "gsub.h" 1.9 + 1.10 +#include <limits> 1.11 +#include <vector> 1.12 + 1.13 +#include "layout.h" 1.14 +#include "maxp.h" 1.15 + 1.16 +// GSUB - The Glyph Substitution Table 1.17 +// http://www.microsoft.com/typography/otspec/gsub.htm 1.18 + 1.19 +#define TABLE_NAME "GSUB" 1.20 + 1.21 +namespace { 1.22 + 1.23 +// The GSUB header size 1.24 +const size_t kGsubHeaderSize = 4 + 3 * 2; 1.25 + 1.26 +enum GSUB_TYPE { 1.27 + GSUB_TYPE_SINGLE = 1, 1.28 + GSUB_TYPE_MULTIPLE = 2, 1.29 + GSUB_TYPE_ALTERNATE = 3, 1.30 + GSUB_TYPE_LIGATURE = 4, 1.31 + GSUB_TYPE_CONTEXT = 5, 1.32 + GSUB_TYPE_CHANGING_CONTEXT = 6, 1.33 + GSUB_TYPE_EXTENSION_SUBSTITUTION = 7, 1.34 + GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE = 8, 1.35 + GSUB_TYPE_RESERVED = 9 1.36 +}; 1.37 + 1.38 +// Lookup type parsers. 1.39 +bool ParseSingleSubstitution(const ots::OpenTypeFile *file, 1.40 + const uint8_t *data, const size_t length); 1.41 +bool ParseMutipleSubstitution(const ots::OpenTypeFile *file, 1.42 + const uint8_t *data, const size_t length); 1.43 +bool ParseAlternateSubstitution(const ots::OpenTypeFile *file, 1.44 + const uint8_t *data, const size_t length); 1.45 +bool ParseLigatureSubstitution(const ots::OpenTypeFile *file, 1.46 + const uint8_t *data, const size_t length); 1.47 +bool ParseContextSubstitution(const ots::OpenTypeFile *file, 1.48 + const uint8_t *data, const size_t length); 1.49 +bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file, 1.50 + const uint8_t *data, 1.51 + const size_t length); 1.52 +bool ParseExtensionSubstitution(const ots::OpenTypeFile *file, 1.53 + const uint8_t *data, const size_t length); 1.54 +bool ParseReverseChainingContextSingleSubstitution( 1.55 + const ots::OpenTypeFile *file, const uint8_t *data, const size_t length); 1.56 + 1.57 +const ots::LookupSubtableParser::TypeParser kGsubTypeParsers[] = { 1.58 + {GSUB_TYPE_SINGLE, ParseSingleSubstitution}, 1.59 + {GSUB_TYPE_MULTIPLE, ParseMutipleSubstitution}, 1.60 + {GSUB_TYPE_ALTERNATE, ParseAlternateSubstitution}, 1.61 + {GSUB_TYPE_LIGATURE, ParseLigatureSubstitution}, 1.62 + {GSUB_TYPE_CONTEXT, ParseContextSubstitution}, 1.63 + {GSUB_TYPE_CHANGING_CONTEXT, ParseChainingContextSubstitution}, 1.64 + {GSUB_TYPE_EXTENSION_SUBSTITUTION, ParseExtensionSubstitution}, 1.65 + {GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE, 1.66 + ParseReverseChainingContextSingleSubstitution} 1.67 +}; 1.68 + 1.69 +const ots::LookupSubtableParser kGsubLookupSubtableParser = { 1.70 + arraysize(kGsubTypeParsers), 1.71 + GSUB_TYPE_EXTENSION_SUBSTITUTION, kGsubTypeParsers 1.72 +}; 1.73 + 1.74 +// Lookup Type 1: 1.75 +// Single Substitution Subtable 1.76 +bool ParseSingleSubstitution(const ots::OpenTypeFile *file, 1.77 + const uint8_t *data, const size_t length) { 1.78 + ots::Buffer subtable(data, length); 1.79 + 1.80 + uint16_t format = 0; 1.81 + uint16_t offset_coverage = 0; 1.82 + 1.83 + if (!subtable.ReadU16(&format) || 1.84 + !subtable.ReadU16(&offset_coverage)) { 1.85 + return OTS_FAILURE_MSG("Failed to read single subst table header"); 1.86 + } 1.87 + 1.88 + const uint16_t num_glyphs = file->maxp->num_glyphs; 1.89 + if (format == 1) { 1.90 + // Parse SingleSubstFormat1 1.91 + int16_t delta_glyph_id = 0; 1.92 + if (!subtable.ReadS16(&delta_glyph_id)) { 1.93 + return OTS_FAILURE_MSG("Failed to read glyph shift from format 1 single subst table"); 1.94 + } 1.95 + if (std::abs(delta_glyph_id) >= num_glyphs) { 1.96 + return OTS_FAILURE_MSG("bad glyph shift of %d in format 1 single subst table", delta_glyph_id); 1.97 + } 1.98 + } else if (format == 2) { 1.99 + // Parse SingleSubstFormat2 1.100 + uint16_t glyph_count = 0; 1.101 + if (!subtable.ReadU16(&glyph_count)) { 1.102 + return OTS_FAILURE_MSG("Failed to read glyph cound in format 2 single subst table"); 1.103 + } 1.104 + if (glyph_count > num_glyphs) { 1.105 + return OTS_FAILURE_MSG("Bad glyph count %d > %d in format 2 single subst table", glyph_count, num_glyphs); 1.106 + } 1.107 + for (unsigned i = 0; i < glyph_count; ++i) { 1.108 + uint16_t substitute = 0; 1.109 + if (!subtable.ReadU16(&substitute)) { 1.110 + return OTS_FAILURE_MSG("Failed to read substitution %d in format 2 single subst table", i); 1.111 + } 1.112 + if (substitute >= num_glyphs) { 1.113 + return OTS_FAILURE_MSG("too large substitute: %u", substitute); 1.114 + } 1.115 + } 1.116 + } else { 1.117 + return OTS_FAILURE_MSG("Bad single subst table format %d", format); 1.118 + } 1.119 + 1.120 + if (offset_coverage < subtable.offset() || offset_coverage >= length) { 1.121 + return OTS_FAILURE_MSG("Bad coverage offset %x", offset_coverage); 1.122 + } 1.123 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.124 + length - offset_coverage, num_glyphs)) { 1.125 + return OTS_FAILURE_MSG("Failed to parse coverage table"); 1.126 + } 1.127 + 1.128 + return true; 1.129 +} 1.130 + 1.131 +bool ParseSequenceTable(const ots::OpenTypeFile *file, 1.132 + const uint8_t *data, const size_t length, 1.133 + const uint16_t num_glyphs) { 1.134 + ots::Buffer subtable(data, length); 1.135 + 1.136 + uint16_t glyph_count = 0; 1.137 + if (!subtable.ReadU16(&glyph_count)) { 1.138 + return OTS_FAILURE_MSG("Failed to read glyph count in sequence table"); 1.139 + } 1.140 + if (glyph_count > num_glyphs) { 1.141 + return OTS_FAILURE_MSG("bad glyph count %d > %d", glyph_count, num_glyphs); 1.142 + } 1.143 + for (unsigned i = 0; i < glyph_count; ++i) { 1.144 + uint16_t substitute = 0; 1.145 + if (!subtable.ReadU16(&substitute)) { 1.146 + return OTS_FAILURE_MSG("Failedt o read substitution %d in sequence table", i); 1.147 + } 1.148 + if (substitute >= num_glyphs) { 1.149 + return OTS_FAILURE_MSG("Bad subsitution (%d) %d > %d", i, substitute, num_glyphs); 1.150 + } 1.151 + } 1.152 + 1.153 + return true; 1.154 +} 1.155 + 1.156 +// Lookup Type 2: 1.157 +// Multiple Substitution Subtable 1.158 +bool ParseMutipleSubstitution(const ots::OpenTypeFile *file, 1.159 + const uint8_t *data, const size_t length) { 1.160 + ots::Buffer subtable(data, length); 1.161 + 1.162 + uint16_t format = 0; 1.163 + uint16_t offset_coverage = 0; 1.164 + uint16_t sequence_count = 0; 1.165 + 1.166 + if (!subtable.ReadU16(&format) || 1.167 + !subtable.ReadU16(&offset_coverage) || 1.168 + !subtable.ReadU16(&sequence_count)) { 1.169 + return OTS_FAILURE_MSG("Can't read header of multiple subst table"); 1.170 + } 1.171 + 1.172 + if (format != 1) { 1.173 + return OTS_FAILURE_MSG("Bad multiple subst table format %d", format); 1.174 + } 1.175 + 1.176 + const uint16_t num_glyphs = file->maxp->num_glyphs; 1.177 + const unsigned sequence_end = static_cast<unsigned>(6) + 1.178 + sequence_count * 2; 1.179 + if (sequence_end > std::numeric_limits<uint16_t>::max()) { 1.180 + return OTS_FAILURE_MSG("Bad segence end %d, in multiple subst", sequence_end); 1.181 + } 1.182 + for (unsigned i = 0; i < sequence_count; ++i) { 1.183 + uint16_t offset_sequence = 0; 1.184 + if (!subtable.ReadU16(&offset_sequence)) { 1.185 + return OTS_FAILURE_MSG("Failed to read sequence offset for sequence %d", i); 1.186 + } 1.187 + if (offset_sequence < sequence_end || offset_sequence >= length) { 1.188 + return OTS_FAILURE_MSG("Bad sequence offset %d for sequence %d", offset_sequence, i); 1.189 + } 1.190 + if (!ParseSequenceTable(file, data + offset_sequence, length - offset_sequence, 1.191 + num_glyphs)) { 1.192 + return OTS_FAILURE_MSG("Failed to parse sequence table %d", i); 1.193 + } 1.194 + } 1.195 + 1.196 + if (offset_coverage < sequence_end || offset_coverage >= length) { 1.197 + return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage); 1.198 + } 1.199 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.200 + length - offset_coverage, num_glyphs)) { 1.201 + return OTS_FAILURE_MSG("Failed to parse coverage table"); 1.202 + } 1.203 + 1.204 + return true; 1.205 +} 1.206 + 1.207 +bool ParseAlternateSetTable(const ots::OpenTypeFile *file, 1.208 + const uint8_t *data, const size_t length, 1.209 + const uint16_t num_glyphs) { 1.210 + ots::Buffer subtable(data, length); 1.211 + 1.212 + uint16_t glyph_count = 0; 1.213 + if (!subtable.ReadU16(&glyph_count)) { 1.214 + return OTS_FAILURE_MSG("Failed to read alternate set header"); 1.215 + } 1.216 + if (glyph_count > num_glyphs) { 1.217 + return OTS_FAILURE_MSG("Bad glyph count %d > %d in alternate set table", glyph_count, num_glyphs); 1.218 + } 1.219 + for (unsigned i = 0; i < glyph_count; ++i) { 1.220 + uint16_t alternate = 0; 1.221 + if (!subtable.ReadU16(&alternate)) { 1.222 + return OTS_FAILURE_MSG("Can't read alternate %d", i); 1.223 + } 1.224 + if (alternate >= num_glyphs) { 1.225 + return OTS_FAILURE_MSG("Too large alternate: %u", alternate); 1.226 + } 1.227 + } 1.228 + return true; 1.229 +} 1.230 + 1.231 +// Lookup Type 3: 1.232 +// Alternate Substitution Subtable 1.233 +bool ParseAlternateSubstitution(const ots::OpenTypeFile *file, 1.234 + const uint8_t *data, const size_t length) { 1.235 + ots::Buffer subtable(data, length); 1.236 + 1.237 + uint16_t format = 0; 1.238 + uint16_t offset_coverage = 0; 1.239 + uint16_t alternate_set_count = 0; 1.240 + 1.241 + if (!subtable.ReadU16(&format) || 1.242 + !subtable.ReadU16(&offset_coverage) || 1.243 + !subtable.ReadU16(&alternate_set_count)) { 1.244 + return OTS_FAILURE_MSG("Can't read alternate subst header"); 1.245 + } 1.246 + 1.247 + if (format != 1) { 1.248 + return OTS_FAILURE_MSG("Bad alternate subst table format %d", format); 1.249 + } 1.250 + 1.251 + const uint16_t num_glyphs = file->maxp->num_glyphs; 1.252 + const unsigned alternate_set_end = static_cast<unsigned>(6) + 1.253 + alternate_set_count * 2; 1.254 + if (alternate_set_end > std::numeric_limits<uint16_t>::max()) { 1.255 + return OTS_FAILURE_MSG("Bad end of alternate set %d", alternate_set_end); 1.256 + } 1.257 + for (unsigned i = 0; i < alternate_set_count; ++i) { 1.258 + uint16_t offset_alternate_set = 0; 1.259 + if (!subtable.ReadU16(&offset_alternate_set)) { 1.260 + return OTS_FAILURE_MSG("Can't read alternate set offset for set %d", i); 1.261 + } 1.262 + if (offset_alternate_set < alternate_set_end || 1.263 + offset_alternate_set >= length) { 1.264 + return OTS_FAILURE_MSG("Bad alternate set offset %d for set %d", offset_alternate_set, i); 1.265 + } 1.266 + if (!ParseAlternateSetTable(file, data + offset_alternate_set, 1.267 + length - offset_alternate_set, 1.268 + num_glyphs)) { 1.269 + return OTS_FAILURE_MSG("Failed to parse alternate set"); 1.270 + } 1.271 + } 1.272 + 1.273 + if (offset_coverage < alternate_set_end || offset_coverage >= length) { 1.274 + return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage); 1.275 + } 1.276 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.277 + length - offset_coverage, num_glyphs)) { 1.278 + return OTS_FAILURE_MSG("Failed to parse coverage table"); 1.279 + } 1.280 + 1.281 + return true; 1.282 +} 1.283 + 1.284 +bool ParseLigatureTable(const ots::OpenTypeFile *file, 1.285 + const uint8_t *data, const size_t length, 1.286 + const uint16_t num_glyphs) { 1.287 + ots::Buffer subtable(data, length); 1.288 + 1.289 + uint16_t lig_glyph = 0; 1.290 + uint16_t comp_count = 0; 1.291 + 1.292 + if (!subtable.ReadU16(&lig_glyph) || 1.293 + !subtable.ReadU16(&comp_count)) { 1.294 + return OTS_FAILURE_MSG("Failed to read ligatuer table header"); 1.295 + } 1.296 + 1.297 + if (lig_glyph >= num_glyphs) { 1.298 + return OTS_FAILURE_MSG("too large lig_glyph: %u", lig_glyph); 1.299 + } 1.300 + if (comp_count == 0 || comp_count > num_glyphs) { 1.301 + return OTS_FAILURE_MSG("Bad component count of %d", comp_count); 1.302 + } 1.303 + for (unsigned i = 0; i < comp_count - static_cast<unsigned>(1); ++i) { 1.304 + uint16_t component = 0; 1.305 + if (!subtable.ReadU16(&component)) { 1.306 + return OTS_FAILURE_MSG("Can't read ligature component %d", i); 1.307 + } 1.308 + if (component >= num_glyphs) { 1.309 + return OTS_FAILURE_MSG("Bad ligature component %d of %d", i, component); 1.310 + } 1.311 + } 1.312 + 1.313 + return true; 1.314 +} 1.315 + 1.316 +bool ParseLigatureSetTable(const ots::OpenTypeFile *file, 1.317 + const uint8_t *data, const size_t length, 1.318 + const uint16_t num_glyphs) { 1.319 + ots::Buffer subtable(data, length); 1.320 + 1.321 + uint16_t ligature_count = 0; 1.322 + 1.323 + if (!subtable.ReadU16(&ligature_count)) { 1.324 + return OTS_FAILURE_MSG("Can't read ligature count in ligature set"); 1.325 + } 1.326 + 1.327 + const unsigned ligature_end = static_cast<unsigned>(2) + ligature_count * 2; 1.328 + if (ligature_end > std::numeric_limits<uint16_t>::max()) { 1.329 + return OTS_FAILURE_MSG("Bad end of ligature %d in ligature set", ligature_end); 1.330 + } 1.331 + for (unsigned i = 0; i < ligature_count; ++i) { 1.332 + uint16_t offset_ligature = 0; 1.333 + if (!subtable.ReadU16(&offset_ligature)) { 1.334 + return OTS_FAILURE_MSG("Failed to read ligature offset %d", i); 1.335 + } 1.336 + if (offset_ligature < ligature_end || offset_ligature >= length) { 1.337 + return OTS_FAILURE_MSG("Bad ligature offset %d for ligature %d", offset_ligature, i); 1.338 + } 1.339 + if (!ParseLigatureTable(file, data + offset_ligature, length - offset_ligature, 1.340 + num_glyphs)) { 1.341 + return OTS_FAILURE_MSG("Failed to parse ligature %d", i); 1.342 + } 1.343 + } 1.344 + 1.345 + return true; 1.346 +} 1.347 + 1.348 +// Lookup Type 4: 1.349 +// Ligature Substitution Subtable 1.350 +bool ParseLigatureSubstitution(const ots::OpenTypeFile *file, 1.351 + const uint8_t *data, const size_t length) { 1.352 + ots::Buffer subtable(data, length); 1.353 + 1.354 + uint16_t format = 0; 1.355 + uint16_t offset_coverage = 0; 1.356 + uint16_t lig_set_count = 0; 1.357 + 1.358 + if (!subtable.ReadU16(&format) || 1.359 + !subtable.ReadU16(&offset_coverage) || 1.360 + !subtable.ReadU16(&lig_set_count)) { 1.361 + return OTS_FAILURE_MSG("Failed to read ligature substitution header"); 1.362 + } 1.363 + 1.364 + if (format != 1) { 1.365 + return OTS_FAILURE_MSG("Bad ligature substitution table format %d", format); 1.366 + } 1.367 + 1.368 + const uint16_t num_glyphs = file->maxp->num_glyphs; 1.369 + const unsigned ligature_set_end = static_cast<unsigned>(6) + 1.370 + lig_set_count * 2; 1.371 + if (ligature_set_end > std::numeric_limits<uint16_t>::max()) { 1.372 + return OTS_FAILURE_MSG("Bad end of ligature set %d in ligature substitution table", ligature_set_end); 1.373 + } 1.374 + for (unsigned i = 0; i < lig_set_count; ++i) { 1.375 + uint16_t offset_ligature_set = 0; 1.376 + if (!subtable.ReadU16(&offset_ligature_set)) { 1.377 + return OTS_FAILURE_MSG("Can't read ligature set offset %d", i); 1.378 + } 1.379 + if (offset_ligature_set < ligature_set_end || 1.380 + offset_ligature_set >= length) { 1.381 + return OTS_FAILURE_MSG("Bad ligature set offset %d for set %d", offset_ligature_set, i); 1.382 + } 1.383 + if (!ParseLigatureSetTable(file, data + offset_ligature_set, 1.384 + length - offset_ligature_set, num_glyphs)) { 1.385 + return OTS_FAILURE_MSG("Failed to parse ligature set %d", i); 1.386 + } 1.387 + } 1.388 + 1.389 + if (offset_coverage < ligature_set_end || offset_coverage >= length) { 1.390 + return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage); 1.391 + } 1.392 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.393 + length - offset_coverage, num_glyphs)) { 1.394 + return OTS_FAILURE_MSG("Failed to parse coverage table"); 1.395 + } 1.396 + 1.397 + return true; 1.398 +} 1.399 + 1.400 +// Lookup Type 5: 1.401 +// Contextual Substitution Subtable 1.402 +bool ParseContextSubstitution(const ots::OpenTypeFile *file, 1.403 + const uint8_t *data, const size_t length) { 1.404 + return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs, 1.405 + file->gsub->num_lookups); 1.406 +} 1.407 + 1.408 +// Lookup Type 6: 1.409 +// Chaining Contextual Substitution Subtable 1.410 +bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file, 1.411 + const uint8_t *data, 1.412 + const size_t length) { 1.413 + return ots::ParseChainingContextSubtable(file, data, length, 1.414 + file->maxp->num_glyphs, 1.415 + file->gsub->num_lookups); 1.416 +} 1.417 + 1.418 +// Lookup Type 7: 1.419 +// Extension Substition 1.420 +bool ParseExtensionSubstitution(const ots::OpenTypeFile *file, 1.421 + const uint8_t *data, const size_t length) { 1.422 + return ots::ParseExtensionSubtable(file, data, length, 1.423 + &kGsubLookupSubtableParser); 1.424 +} 1.425 + 1.426 +// Lookup Type 8: 1.427 +// Reverse Chaining Contexual Single Substitution Subtable 1.428 +bool ParseReverseChainingContextSingleSubstitution( 1.429 + const ots::OpenTypeFile *file, const uint8_t *data, const size_t length) { 1.430 + ots::Buffer subtable(data, length); 1.431 + 1.432 + uint16_t format = 0; 1.433 + uint16_t offset_coverage = 0; 1.434 + 1.435 + if (!subtable.ReadU16(&format) || 1.436 + !subtable.ReadU16(&offset_coverage)) { 1.437 + return OTS_FAILURE_MSG("Failed to read reverse chaining header"); 1.438 + } 1.439 + 1.440 + const uint16_t num_glyphs = file->maxp->num_glyphs; 1.441 + 1.442 + uint16_t backtrack_glyph_count = 0; 1.443 + if (!subtable.ReadU16(&backtrack_glyph_count)) { 1.444 + return OTS_FAILURE_MSG("Failed to read backtrack glyph count in reverse chaining table"); 1.445 + } 1.446 + if (backtrack_glyph_count > num_glyphs) { 1.447 + return OTS_FAILURE_MSG("Bad backtrack glyph count of %d", backtrack_glyph_count); 1.448 + } 1.449 + std::vector<uint16_t> offsets_backtrack; 1.450 + offsets_backtrack.reserve(backtrack_glyph_count); 1.451 + for (unsigned i = 0; i < backtrack_glyph_count; ++i) { 1.452 + uint16_t offset = 0; 1.453 + if (!subtable.ReadU16(&offset)) { 1.454 + return OTS_FAILURE_MSG("Failed to read backtrack offset %d", i); 1.455 + } 1.456 + offsets_backtrack.push_back(offset); 1.457 + } 1.458 + 1.459 + uint16_t lookahead_glyph_count = 0; 1.460 + if (!subtable.ReadU16(&lookahead_glyph_count)) { 1.461 + return OTS_FAILURE_MSG("Failed to read look ahead glyph count"); 1.462 + } 1.463 + if (lookahead_glyph_count > num_glyphs) { 1.464 + return OTS_FAILURE_MSG("Bad look ahead glyph count %d", lookahead_glyph_count); 1.465 + } 1.466 + std::vector<uint16_t> offsets_lookahead; 1.467 + offsets_lookahead.reserve(lookahead_glyph_count); 1.468 + for (unsigned i = 0; i < lookahead_glyph_count; ++i) { 1.469 + uint16_t offset = 0; 1.470 + if (!subtable.ReadU16(&offset)) { 1.471 + return OTS_FAILURE_MSG("Can't read look ahead offset %d", i); 1.472 + } 1.473 + offsets_lookahead.push_back(offset); 1.474 + } 1.475 + 1.476 + uint16_t glyph_count = 0; 1.477 + if (!subtable.ReadU16(&glyph_count)) { 1.478 + return OTS_FAILURE_MSG("Can't read glyph count in reverse chaining table"); 1.479 + } 1.480 + if (glyph_count > num_glyphs) { 1.481 + return OTS_FAILURE_MSG("Bad glyph count of %d", glyph_count); 1.482 + } 1.483 + for (unsigned i = 0; i < glyph_count; ++i) { 1.484 + uint16_t substitute = 0; 1.485 + if (!subtable.ReadU16(&substitute)) { 1.486 + return OTS_FAILURE_MSG("Failed to read substitution %d reverse chaining table", i); 1.487 + } 1.488 + if (substitute >= num_glyphs) { 1.489 + return OTS_FAILURE_MSG("Bad substitute glyph %d in reverse chaining table substitution %d", substitute, i); 1.490 + } 1.491 + } 1.492 + 1.493 + const unsigned substitute_end = static_cast<unsigned>(10) + 1.494 + (backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2; 1.495 + if (substitute_end > std::numeric_limits<uint16_t>::max()) { 1.496 + return OTS_FAILURE_MSG("Bad substitute end offset in reverse chaining table"); 1.497 + } 1.498 + 1.499 + if (offset_coverage < substitute_end || offset_coverage >= length) { 1.500 + return OTS_FAILURE_MSG("Bad coverage offset %d in reverse chaining table", offset_coverage); 1.501 + } 1.502 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.503 + length - offset_coverage, num_glyphs)) { 1.504 + return OTS_FAILURE_MSG("Failed to parse coverage table in reverse chaining table"); 1.505 + } 1.506 + 1.507 + for (unsigned i = 0; i < backtrack_glyph_count; ++i) { 1.508 + if (offsets_backtrack[i] < substitute_end || 1.509 + offsets_backtrack[i] >= length) { 1.510 + return OTS_FAILURE_MSG("Bad backtrack offset %d for backtrack %d in reverse chaining table", offsets_backtrack[i], i); 1.511 + } 1.512 + if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i], 1.513 + length - offsets_backtrack[i], num_glyphs)) { 1.514 + return OTS_FAILURE_MSG("Failed to parse coverage table for backtrack %d in reverse chaining table", i); 1.515 + } 1.516 + } 1.517 + 1.518 + for (unsigned i = 0; i < lookahead_glyph_count; ++i) { 1.519 + if (offsets_lookahead[i] < substitute_end || 1.520 + offsets_lookahead[i] >= length) { 1.521 + return OTS_FAILURE_MSG("Bad lookahead offset %d for lookahead %d in reverse chaining table", offsets_lookahead[i], i); 1.522 + } 1.523 + if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i], 1.524 + length - offsets_lookahead[i], num_glyphs)) { 1.525 + return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in reverse chaining table", i); 1.526 + } 1.527 + } 1.528 + 1.529 + return true; 1.530 +} 1.531 + 1.532 +} // namespace 1.533 + 1.534 +#define DROP_THIS_TABLE(msg_) \ 1.535 + do { \ 1.536 + file->gsub->data = 0; \ 1.537 + file->gsub->length = 0; \ 1.538 + OTS_FAILURE_MSG(msg_ ", table discarded"); \ 1.539 + } while (0) 1.540 + 1.541 +namespace ots { 1.542 + 1.543 +// As far as I checked, following fonts contain invalid values in GSUB table. 1.544 +// OTS will drop their GSUB table. 1.545 +// 1.546 +// # too large substitute (value is 0xFFFF) 1.547 +// kaiu.ttf 1.548 +// mingliub2.ttf 1.549 +// mingliub1.ttf 1.550 +// mingliub0.ttf 1.551 +// GraublauWeb.otf 1.552 +// GraublauWebBold.otf 1.553 +// 1.554 +// # too large alternate (value is 0xFFFF) 1.555 +// ManchuFont.ttf 1.556 +// 1.557 +// # bad offset to lang sys table (NULL offset) 1.558 +// DejaVuMonoSansBold.ttf 1.559 +// DejaVuMonoSansBoldOblique.ttf 1.560 +// DejaVuMonoSansOblique.ttf 1.561 +// DejaVuSansMono-BoldOblique.ttf 1.562 +// DejaVuSansMono-Oblique.ttf 1.563 +// DejaVuSansMono-Bold.ttf 1.564 +// 1.565 +// # bad start coverage index 1.566 +// GenBasBI.ttf 1.567 +// GenBasI.ttf 1.568 +// AndBasR.ttf 1.569 +// GenBkBasI.ttf 1.570 +// CharisSILR.ttf 1.571 +// CharisSILBI.ttf 1.572 +// CharisSILI.ttf 1.573 +// CharisSILB.ttf 1.574 +// DoulosSILR.ttf 1.575 +// CharisSILBI.ttf 1.576 +// GenBkBasB.ttf 1.577 +// GenBkBasR.ttf 1.578 +// GenBkBasBI.ttf 1.579 +// GenBasB.ttf 1.580 +// GenBasR.ttf 1.581 +// 1.582 +// # glyph range is overlapping 1.583 +// KacstTitleL.ttf 1.584 +// KacstDecorative.ttf 1.585 +// KacstTitle.ttf 1.586 +// KacstArt.ttf 1.587 +// KacstPoster.ttf 1.588 +// KacstQurn.ttf 1.589 +// KacstDigital.ttf 1.590 +// KacstBook.ttf 1.591 +// KacstFarsi.ttf 1.592 + 1.593 +bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { 1.594 + // Parsing gsub table requires |file->maxp->num_glyphs| 1.595 + if (!file->maxp) { 1.596 + return OTS_FAILURE_MSG("Missing maxp table in font, needed by GSUB"); 1.597 + } 1.598 + 1.599 + Buffer table(data, length); 1.600 + 1.601 + OpenTypeGSUB *gsub = new OpenTypeGSUB; 1.602 + file->gsub = gsub; 1.603 + 1.604 + uint32_t version = 0; 1.605 + uint16_t offset_script_list = 0; 1.606 + uint16_t offset_feature_list = 0; 1.607 + uint16_t offset_lookup_list = 0; 1.608 + if (!table.ReadU32(&version) || 1.609 + !table.ReadU16(&offset_script_list) || 1.610 + !table.ReadU16(&offset_feature_list) || 1.611 + !table.ReadU16(&offset_lookup_list)) { 1.612 + DROP_THIS_TABLE("Incomplete table"); 1.613 + return true; 1.614 + } 1.615 + 1.616 + if (version != 0x00010000) { 1.617 + DROP_THIS_TABLE("Bad version"); 1.618 + return true; 1.619 + } 1.620 + if ((offset_script_list < kGsubHeaderSize || 1.621 + offset_script_list >= length) || 1.622 + (offset_feature_list < kGsubHeaderSize || 1.623 + offset_feature_list >= length) || 1.624 + (offset_lookup_list < kGsubHeaderSize || 1.625 + offset_lookup_list >= length)) { 1.626 + DROP_THIS_TABLE("Bad offset in table header"); 1.627 + return true; 1.628 + } 1.629 + 1.630 + if (!ParseLookupListTable(file, data + offset_lookup_list, 1.631 + length - offset_lookup_list, 1.632 + &kGsubLookupSubtableParser, 1.633 + &gsub->num_lookups)) { 1.634 + DROP_THIS_TABLE("Failed to parse lookup list table"); 1.635 + return true; 1.636 + } 1.637 + 1.638 + uint16_t num_features = 0; 1.639 + if (!ParseFeatureListTable(file, data + offset_feature_list, 1.640 + length - offset_feature_list, gsub->num_lookups, 1.641 + &num_features)) { 1.642 + DROP_THIS_TABLE("Failed to parse feature list table"); 1.643 + return true; 1.644 + } 1.645 + 1.646 + if (!ParseScriptListTable(file, data + offset_script_list, 1.647 + length - offset_script_list, num_features)) { 1.648 + DROP_THIS_TABLE("Failed to parse script list table"); 1.649 + return true; 1.650 + } 1.651 + 1.652 + gsub->data = data; 1.653 + gsub->length = length; 1.654 + return true; 1.655 +} 1.656 + 1.657 +bool ots_gsub_should_serialise(OpenTypeFile *file) { 1.658 + return file->gsub != NULL && file->gsub->data != NULL; 1.659 +} 1.660 + 1.661 +bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) { 1.662 + if (!out->Write(file->gsub->data, file->gsub->length)) { 1.663 + return OTS_FAILURE_MSG("Failed to write GSUB table"); 1.664 + } 1.665 + 1.666 + return true; 1.667 +} 1.668 + 1.669 +void ots_gsub_free(OpenTypeFile *file) { 1.670 + delete file->gsub; 1.671 +} 1.672 + 1.673 +} // namespace ots 1.674 +