gfx/ots/src/gsub.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial