gpos.cc (26036B)
1 // Copyright (c) 2011-2017 The OTS 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 "gpos.h" 6 7 #include <limits> 8 #include <vector> 9 10 #include "layout.h" 11 #include "maxp.h" 12 13 // GPOS - The Glyph Positioning Table 14 // http://www.microsoft.com/typography/otspec/gpos.htm 15 16 #define TABLE_NAME "GPOS" 17 18 namespace { 19 20 enum GPOS_TYPE { 21 GPOS_TYPE_SINGLE_ADJUSTMENT = 1, 22 GPOS_TYPE_PAIR_ADJUSTMENT = 2, 23 GPOS_TYPE_CURSIVE_ATTACHMENT = 3, 24 GPOS_TYPE_MARK_TO_BASE_ATTACHMENT = 4, 25 GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT = 5, 26 GPOS_TYPE_MARK_TO_MARK_ATTACHMENT = 6, 27 GPOS_TYPE_CONTEXT_POSITIONING = 7, 28 GPOS_TYPE_CHAINED_CONTEXT_POSITIONING = 8, 29 GPOS_TYPE_EXTENSION_POSITIONING = 9, 30 GPOS_TYPE_RESERVED = 10 31 }; 32 33 // The maximum format number for anchor tables. 34 const uint16_t kMaxAnchorFormat = 3; 35 36 // Shared Tables: ValueRecord, Anchor Table, and MarkArray 37 38 size_t CalcValueRecordSize(const uint16_t value_format) { 39 size_t size = 0; 40 for (unsigned i = 0; i < 8; ++i) { 41 if ((value_format >> i) & 0x1) { 42 size += 2; 43 } 44 } 45 46 return size; 47 } 48 49 bool ParseValueRecord(const ots::Font *font, 50 ots::Buffer* subtable, 51 const uint16_t value_format) { 52 const uint8_t *data = subtable->buffer(); 53 const size_t length = subtable->length(); 54 55 // Check existence of adjustment fields. 56 for (unsigned i = 0; i < 4; ++i) { 57 if ((value_format >> i) & 0x1) { 58 // Just read the field since these fileds could take an arbitrary values. 59 if (!subtable->Skip(2)) { 60 return OTS_FAILURE_MSG("Failed to read value reacord component"); 61 } 62 } 63 } 64 65 // Check existence of offsets to device table. 66 for (unsigned i = 0; i < 4; ++i) { 67 if ((value_format >> (i + 4)) & 0x1) { 68 uint16_t offset = 0; 69 if (!subtable->ReadU16(&offset)) { 70 return OTS_FAILURE_MSG("Failed to read value record offset"); 71 } 72 if (offset) { 73 // TODO(bashi): Is it possible that device tables locate before 74 // this record? No fonts contain such offset AKAIF. 75 if (offset >= length) { 76 return OTS_FAILURE_MSG("Value record offset too high %d >= %ld", offset, length); 77 } 78 if (!ots::ParseDeviceTable(font, data + offset, length - offset)) { 79 return OTS_FAILURE_MSG("Failed to parse device table in value record"); 80 } 81 } 82 } 83 } 84 return true; 85 } 86 87 bool ParseAnchorTable(const ots::Font *font, 88 const uint8_t *data, const size_t length) { 89 ots::Buffer subtable(data, length); 90 91 uint16_t format = 0; 92 // Read format and skip 2 2-byte fields that could be arbitrary values. 93 if (!subtable.ReadU16(&format) || 94 !subtable.Skip(4)) { 95 return OTS_FAILURE_MSG("Faled to read anchor table"); 96 } 97 98 if (format == 0 || format > kMaxAnchorFormat) { 99 return OTS_FAILURE_MSG("Bad Anchor table format %d", format); 100 } 101 102 // Format 2 and 3 has additional fields. 103 if (format == 2) { 104 // Format 2 provides an index to a glyph contour point, which will take 105 // arbitrary value. 106 uint16_t anchor_point = 0; 107 if (!subtable.ReadU16(&anchor_point)) { 108 return OTS_FAILURE_MSG("Failed to read anchor point in format 2 Anchor Table"); 109 } 110 } else if (format == 3) { 111 uint16_t offset_x_device = 0; 112 uint16_t offset_y_device = 0; 113 if (!subtable.ReadU16(&offset_x_device) || 114 !subtable.ReadU16(&offset_y_device)) { 115 return OTS_FAILURE_MSG("Failed to read device table offsets in format 3 anchor table"); 116 } 117 const unsigned format_end = static_cast<unsigned>(10); 118 if (offset_x_device) { 119 if (offset_x_device < format_end || offset_x_device >= length) { 120 return OTS_FAILURE_MSG("Bad x device table offset %d", offset_x_device); 121 } 122 if (!ots::ParseDeviceTable(font, data + offset_x_device, 123 length - offset_x_device)) { 124 return OTS_FAILURE_MSG("Failed to parse device table in anchor table"); 125 } 126 } 127 if (offset_y_device) { 128 if (offset_y_device < format_end || offset_y_device >= length) { 129 return OTS_FAILURE_MSG("Bad y device table offset %d", offset_y_device); 130 } 131 if (!ots::ParseDeviceTable(font, data + offset_y_device, 132 length - offset_y_device)) { 133 return OTS_FAILURE_MSG("Failed to parse device table in anchor table"); 134 } 135 } 136 } 137 return true; 138 } 139 140 bool ParseMarkArrayTable(const ots::Font *font, 141 const uint8_t *data, const size_t length) { 142 ots::Buffer subtable(data, length); 143 144 uint16_t mark_count = 0; 145 if (!subtable.ReadU16(&mark_count)) { 146 return OTS_FAILURE_MSG("Can't read mark table length"); 147 } 148 149 // MarkRecord consists of 4-bytes. 150 const unsigned mark_records_end = 4 * static_cast<unsigned>(mark_count) + 2; 151 if (mark_records_end > std::numeric_limits<uint16_t>::max()) { 152 return OTS_FAILURE_MSG("Bad mark table length"); 153 } 154 for (unsigned i = 0; i < mark_count; ++i) { 155 uint16_t class_value = 0; 156 uint16_t offset_mark_anchor = 0; 157 if (!subtable.ReadU16(&class_value) || 158 !subtable.ReadU16(&offset_mark_anchor)) { 159 return OTS_FAILURE_MSG("Can't read mark table %d", i); 160 } 161 // |class_value| may take arbitrary values including 0 here so we don't 162 // check the value. 163 if (offset_mark_anchor < mark_records_end || 164 offset_mark_anchor >= length) { 165 return OTS_FAILURE_MSG("Bad mark anchor offset %d for mark table %d", offset_mark_anchor, i); 166 } 167 if (!ParseAnchorTable(font, data + offset_mark_anchor, 168 length - offset_mark_anchor)) { 169 return OTS_FAILURE_MSG("Faled to parse anchor table for mark table %d", i); 170 } 171 } 172 173 return true; 174 } 175 176 bool ParsePairSetTable(const ots::Font *font, 177 const uint8_t *data, const size_t length, 178 const uint16_t value_format1, 179 const uint16_t value_format2, 180 const uint16_t num_glyphs) { 181 ots::Buffer subtable(data, length); 182 183 uint16_t value_count = 0; 184 if (!subtable.ReadU16(&value_count)) { 185 return OTS_FAILURE_MSG("Failed to read pair set table structure"); 186 } 187 for (unsigned i = 0; i < value_count; ++i) { 188 // Check pair value record. 189 uint16_t glyph_id = 0; 190 if (!subtable.ReadU16(&glyph_id)) { 191 return OTS_FAILURE_MSG("Failed to read glyph in pair value record %d", i); 192 } 193 if (glyph_id >= num_glyphs) { 194 return OTS_FAILURE_MSG("glyph id %d too high >= %d", glyph_id, num_glyphs); 195 } 196 if (!ParseValueRecord(font, &subtable, value_format1)) { 197 return OTS_FAILURE_MSG("Failed to parse value record in format 1 pair set table"); 198 } 199 if (!ParseValueRecord(font, &subtable, value_format2)) { 200 return OTS_FAILURE_MSG("Failed to parse value record in format 2 pair set table"); 201 } 202 } 203 return true; 204 } 205 206 bool ParsePairPosFormat1(const ots::Font *font, 207 const uint8_t *data, const size_t length, 208 const uint16_t value_format1, 209 const uint16_t value_format2, 210 const uint16_t num_glyphs) { 211 ots::Buffer subtable(data, length); 212 213 // Skip 8 bytes that are already read before. 214 if (!subtable.Skip(8)) { 215 return OTS_FAILURE_MSG("Failed to read pair pos table structure"); 216 } 217 218 uint16_t pair_set_count = 0; 219 if (!subtable.ReadU16(&pair_set_count)) { 220 return OTS_FAILURE_MSG("Failed to read pair pos set count"); 221 } 222 223 const unsigned pair_pos_end = 2 * static_cast<unsigned>(pair_set_count) + 10; 224 if (pair_pos_end > std::numeric_limits<uint16_t>::max()) { 225 return OTS_FAILURE_MSG("Bad pair set length %d", pair_pos_end); 226 } 227 for (unsigned i = 0; i < pair_set_count; ++i) { 228 uint16_t pair_set_offset = 0; 229 if (!subtable.ReadU16(&pair_set_offset)) { 230 return OTS_FAILURE_MSG("Failed to read pair set offset for pair set %d", i); 231 } 232 if (pair_set_offset < pair_pos_end || pair_set_offset >= length) { 233 return OTS_FAILURE_MSG("Bad pair set offset %d for pair set %d", pair_set_offset, i); 234 } 235 // Check pair set tables 236 if (!ParsePairSetTable(font, data + pair_set_offset, length - pair_set_offset, 237 value_format1, value_format2, 238 num_glyphs)) { 239 return OTS_FAILURE_MSG("Failed to parse pair set table %d", i); 240 } 241 } 242 243 return true; 244 } 245 246 bool ParsePairPosFormat2(const ots::Font *font, 247 const uint8_t *data, const size_t length, 248 const uint16_t value_format1, 249 const uint16_t value_format2, 250 const uint16_t num_glyphs) { 251 ots::Buffer subtable(data, length); 252 253 // Skip 8 bytes that are already read before. 254 if (!subtable.Skip(8)) { 255 return OTS_FAILURE_MSG("Failed to read pair pos format 2 structure"); 256 } 257 258 uint16_t offset_class_def1 = 0; 259 uint16_t offset_class_def2 = 0; 260 uint16_t class1_count = 0; 261 uint16_t class2_count = 0; 262 if (!subtable.ReadU16(&offset_class_def1) || 263 !subtable.ReadU16(&offset_class_def2) || 264 !subtable.ReadU16(&class1_count) || 265 !subtable.ReadU16(&class2_count)) { 266 return OTS_FAILURE_MSG("Failed to read pair pos format 2 data"); 267 } 268 269 size_t value_record1_size = CalcValueRecordSize(value_format1); 270 size_t value_record2_size = CalcValueRecordSize(value_format2); 271 size_t value_records_size = size_t(class1_count) * size_t(class2_count) * 272 (value_record1_size + value_record2_size); 273 274 // Check the validity of class definition offsets. 275 if (offset_class_def1 < subtable.offset() + value_records_size || 276 offset_class_def2 < subtable.offset() + value_records_size || 277 offset_class_def1 >= length || offset_class_def2 >= length) { 278 return OTS_FAILURE_MSG("Bad ParsePairPosFormat2 class definition offsets %d or %d", offset_class_def1, offset_class_def2); 279 } 280 281 // Check class 1 records. 282 if (value_record1_size || value_record2_size) { 283 for (unsigned i = 0; i < class1_count; ++i) { 284 // Check class 2 records. 285 for (unsigned j = 0; j < class2_count; ++j) { 286 if (value_format1 && value_record2_size && 287 !ParseValueRecord(font, &subtable, value_format1)) { 288 return OTS_FAILURE_MSG("Failed to parse value record 1 %d and %d", j, i); 289 } 290 if (value_format2 && value_record2_size && 291 !ParseValueRecord(font, &subtable, value_format2)) { 292 return OTS_FAILURE_MSG("Falied to parse value record 2 %d and %d", j, i); 293 } 294 } 295 } 296 } 297 298 // Check class definition tables. 299 if (!ots::ParseClassDefTable(font, data + offset_class_def1, 300 length - offset_class_def1, 301 num_glyphs, ots::kMaxClassDefValue)) { 302 return OTS_FAILURE_MSG("Failed to parse class definition table 1"); 303 } 304 if (!ots::ParseClassDefTable(font, data + offset_class_def2, 305 length - offset_class_def2, 306 num_glyphs, ots::kMaxClassDefValue)) { 307 return OTS_FAILURE_MSG("Failed to parse class definition table 2"); 308 } 309 310 return true; 311 } 312 313 bool ParseAnchorArrayTable(const ots::Font *font, 314 const uint8_t *data, const size_t length, 315 const uint16_t class_count) { 316 ots::Buffer subtable(data, length); 317 318 uint16_t record_count = 0; 319 if (!subtable.ReadU16(&record_count)) { 320 return OTS_FAILURE_MSG("Can't read anchor array length"); 321 } 322 323 const unsigned anchor_array_end = 2 * static_cast<unsigned>(record_count) * 324 static_cast<unsigned>(class_count) + 2; 325 if (anchor_array_end > std::numeric_limits<uint16_t>::max()) { 326 return OTS_FAILURE_MSG("Bad end of anchor array %d", anchor_array_end); 327 } 328 for (unsigned i = 0; i < record_count; ++i) { 329 for (unsigned j = 0; j < class_count; ++j) { 330 uint16_t offset_record = 0; 331 if (!subtable.ReadU16(&offset_record)) { 332 return OTS_FAILURE_MSG("Can't read anchor array record offset for class %d and record %d", j, i); 333 } 334 // |offset_record| could be NULL. 335 if (offset_record) { 336 if (offset_record < anchor_array_end || offset_record >= length) { 337 return OTS_FAILURE_MSG("Bad record offset %d in class %d, record %d", offset_record, j, i); 338 } 339 if (!ParseAnchorTable(font, data + offset_record, 340 length - offset_record)) { 341 return OTS_FAILURE_MSG("Failed to parse anchor table for class %d, record %d", j, i); 342 } 343 } 344 } 345 } 346 return true; 347 } 348 349 bool ParseLigatureArrayTable(const ots::Font *font, 350 const uint8_t *data, const size_t length, 351 const uint16_t class_count) { 352 ots::Buffer subtable(data, length); 353 354 uint16_t ligature_count = 0; 355 if (!subtable.ReadU16(&ligature_count)) { 356 return OTS_FAILURE_MSG("Failed to read ligature count"); 357 } 358 for (unsigned i = 0; i < ligature_count; ++i) { 359 uint16_t offset_ligature_attach = 0; 360 if (!subtable.ReadU16(&offset_ligature_attach)) { 361 return OTS_FAILURE_MSG("Can't read ligature offset %d", i); 362 } 363 if (offset_ligature_attach < 2 || offset_ligature_attach >= length) { 364 return OTS_FAILURE_MSG("Bad ligature attachment offset %d in ligature %d", offset_ligature_attach, i); 365 } 366 if (!ParseAnchorArrayTable(font, data + offset_ligature_attach, 367 length - offset_ligature_attach, class_count)) { 368 return OTS_FAILURE_MSG("Failed to parse anchor table for ligature %d", i); 369 } 370 } 371 return true; 372 } 373 374 // Common parser for Lookup Type 4, 5 and 6. 375 bool ParseMarkToAttachmentSubtables(const ots::Font *font, 376 const uint8_t *data, const size_t length, 377 const GPOS_TYPE type) { 378 ots::Buffer subtable(data, length); 379 380 ots::OpenTypeMAXP *maxp = static_cast<ots::OpenTypeMAXP*>( 381 font->GetTypedTable(OTS_TAG_MAXP)); 382 if (!maxp) { 383 return OTS_FAILURE_MSG("Required maxp table missing"); 384 } 385 386 uint16_t format = 0; 387 uint16_t offset_coverage1 = 0; 388 uint16_t offset_coverage2 = 0; 389 uint16_t class_count = 0; 390 uint16_t offset_mark_array = 0; 391 uint16_t offset_type_specific_array = 0; 392 if (!subtable.ReadU16(&format) || 393 !subtable.ReadU16(&offset_coverage1) || 394 !subtable.ReadU16(&offset_coverage2) || 395 !subtable.ReadU16(&class_count) || 396 !subtable.ReadU16(&offset_mark_array) || 397 !subtable.ReadU16(&offset_type_specific_array)) { 398 return OTS_FAILURE_MSG("Failed to read mark attachment subtable header"); 399 } 400 401 if (format != 1) { 402 return OTS_FAILURE_MSG("bad mark attachment subtable format %d", format); 403 } 404 405 const unsigned header_end = static_cast<unsigned>(subtable.offset()); 406 if (header_end > std::numeric_limits<uint16_t>::max()) { 407 return OTS_FAILURE_MSG("Bad mark attachment subtable size ending at %d", header_end); 408 } 409 if (offset_coverage1 < header_end || offset_coverage1 >= length) { 410 return OTS_FAILURE_MSG("Bad coverage 1 offset %d", offset_coverage1); 411 } 412 if (!ots::ParseCoverageTable(font, data + offset_coverage1, 413 length - offset_coverage1, 414 maxp->num_glyphs)) { 415 return OTS_FAILURE_MSG("Failed to parse converge 1 table"); 416 } 417 if (offset_coverage2 < header_end || offset_coverage2 >= length) { 418 return OTS_FAILURE_MSG("Bad coverage 2 offset %d", offset_coverage2); 419 } 420 if (!ots::ParseCoverageTable(font, data + offset_coverage2, 421 length - offset_coverage2, 422 maxp->num_glyphs)) { 423 return OTS_FAILURE_MSG("Failed to parse coverage table 2"); 424 } 425 426 if (offset_mark_array < header_end || offset_mark_array >= length) { 427 return OTS_FAILURE_MSG("Bad mark array offset %d", offset_mark_array); 428 } 429 if (!ParseMarkArrayTable(font, data + offset_mark_array, 430 length - offset_mark_array)) { 431 return OTS_FAILURE_MSG("Failed to parse mark array"); 432 } 433 434 if (offset_type_specific_array < header_end || 435 offset_type_specific_array >= length) { 436 return OTS_FAILURE_MSG("Bad type specific array offset %d", offset_type_specific_array); 437 } 438 if (type == GPOS_TYPE_MARK_TO_BASE_ATTACHMENT || 439 type == GPOS_TYPE_MARK_TO_MARK_ATTACHMENT) { 440 if (!ParseAnchorArrayTable(font, data + offset_type_specific_array, 441 length - offset_type_specific_array, 442 class_count)) { 443 return OTS_FAILURE_MSG("Failed to parse anchor array"); 444 } 445 } else if (type == GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT) { 446 if (!ParseLigatureArrayTable(font, data + offset_type_specific_array, 447 length - offset_type_specific_array, 448 class_count)) { 449 return OTS_FAILURE_MSG("Failed to parse ligature array"); 450 } 451 } else { 452 return OTS_FAILURE_MSG("Bad attachment type %d", type); 453 } 454 455 return true; 456 } 457 458 } // namespace 459 460 namespace ots { 461 462 // Lookup Type 1: 463 // Single Adjustment Positioning Subtable 464 bool OpenTypeGPOS::ParseSingleAdjustment(const uint8_t *data, 465 const size_t length) { 466 Font* font = GetFont(); 467 Buffer subtable(data, length); 468 469 OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( 470 font->GetTypedTable(OTS_TAG_MAXP)); 471 if (!maxp) { 472 return Error("Required maxp table missing"); 473 } 474 475 uint16_t format = 0; 476 uint16_t offset_coverage = 0; 477 uint16_t value_format = 0; 478 if (!subtable.ReadU16(&format) || 479 !subtable.ReadU16(&offset_coverage) || 480 !subtable.ReadU16(&value_format)) { 481 return Error("Can't read single adjustment information"); 482 } 483 484 if (format == 1) { 485 // Format 1 exactly one value record. 486 if (!ParseValueRecord(font, &subtable, value_format)) { 487 return Error("Failed to parse format 1 single adjustment table"); 488 } 489 } else if (format == 2) { 490 uint16_t value_count = 0; 491 if (!subtable.ReadU16(&value_count)) { 492 return Error("Failed to parse format 2 single adjustment table"); 493 } 494 for (unsigned i = 0; i < value_count; ++i) { 495 if (!ParseValueRecord(font, &subtable, value_format)) { 496 return Error("Failed to parse value record %d in format 2 single adjustment table", i); 497 } 498 } 499 } else { 500 return Error("Bad format %d in single adjustment table", format); 501 } 502 503 if (offset_coverage < subtable.offset() || offset_coverage >= length) { 504 return Error("Bad coverage offset %d in single adjustment table", offset_coverage); 505 } 506 507 if (!ots::ParseCoverageTable(font, data + offset_coverage, 508 length - offset_coverage, 509 maxp->num_glyphs)) { 510 return Error("Failed to parse coverage table in single adjustment table"); 511 } 512 513 return true; 514 } 515 516 // Lookup Type 2: 517 // Pair Adjustment Positioning Subtable 518 bool OpenTypeGPOS::ParsePairAdjustment(const uint8_t *data, 519 const size_t length) { 520 Font* font = GetFont(); 521 Buffer subtable(data, length); 522 523 OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( 524 font->GetTypedTable(OTS_TAG_MAXP)); 525 if (!maxp) { 526 return Error("Required maxp table missing"); 527 } 528 529 uint16_t format = 0; 530 uint16_t offset_coverage = 0; 531 uint16_t value_format1 = 0; 532 uint16_t value_format2 = 0; 533 if (!subtable.ReadU16(&format) || 534 !subtable.ReadU16(&offset_coverage) || 535 !subtable.ReadU16(&value_format1) || 536 !subtable.ReadU16(&value_format2)) { 537 return Error("Failed to read pair adjustment structure"); 538 } 539 540 if (format == 1) { 541 if (!ParsePairPosFormat1(font, data, length, value_format1, value_format2, 542 maxp->num_glyphs)) { 543 return Error("Failed to parse pair pos format 1"); 544 } 545 } else if (format == 2) { 546 if (!ParsePairPosFormat2(font, data, length, value_format1, value_format2, 547 maxp->num_glyphs)) { 548 return Error("Failed to parse pair format 2"); 549 } 550 } else { 551 return Error("Bad pos pair format %d", format); 552 } 553 554 if (offset_coverage < subtable.offset() || offset_coverage >= length) { 555 return Error("Bad pair pos offset coverage %d", offset_coverage); 556 } 557 if (!ots::ParseCoverageTable(font, data + offset_coverage, 558 length - offset_coverage, 559 maxp->num_glyphs)) { 560 return Error("Failed to parse coverage table"); 561 } 562 563 return true; 564 } 565 566 // Lookup Type 3 567 // Cursive Attachment Positioning Subtable 568 bool OpenTypeGPOS::ParseCursiveAttachment(const uint8_t *data, 569 const size_t length) { 570 Font* font = GetFont(); 571 Buffer subtable(data, length); 572 573 OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( 574 font->GetTypedTable(OTS_TAG_MAXP)); 575 if (!maxp) { 576 return Error("Required maxp table missing"); 577 } 578 579 uint16_t format = 0; 580 uint16_t offset_coverage = 0; 581 uint16_t entry_exit_count = 0; 582 if (!subtable.ReadU16(&format) || 583 !subtable.ReadU16(&offset_coverage) || 584 !subtable.ReadU16(&entry_exit_count)) { 585 return Error("Failed to read cursive attachment structure"); 586 } 587 588 if (format != 1) { 589 return Error("Bad cursive attachment format %d", format); 590 } 591 592 // Check entry exit records. 593 const unsigned entry_exit_records_end = 594 2 * static_cast<unsigned>(entry_exit_count) + 6; 595 if (entry_exit_records_end > std::numeric_limits<uint16_t>::max()) { 596 return Error("Bad entry exit record end %d", entry_exit_records_end); 597 } 598 for (unsigned i = 0; i < entry_exit_count; ++i) { 599 uint16_t offset_entry_anchor = 0; 600 uint16_t offset_exit_anchor = 0; 601 if (!subtable.ReadU16(&offset_entry_anchor) || 602 !subtable.ReadU16(&offset_exit_anchor)) { 603 return Error("Can't read entry exit record %d", i); 604 } 605 // These offsets could be NULL. 606 if (offset_entry_anchor) { 607 if (offset_entry_anchor < entry_exit_records_end || 608 offset_entry_anchor >= length) { 609 return Error("Bad entry anchor offset %d in entry exit record %d", offset_entry_anchor, i); 610 } 611 if (!ParseAnchorTable(font, data + offset_entry_anchor, 612 length - offset_entry_anchor)) { 613 return Error("Failed to parse entry anchor table in entry exit record %d", i); 614 } 615 } 616 if (offset_exit_anchor) { 617 if (offset_exit_anchor < entry_exit_records_end || 618 offset_exit_anchor >= length) { 619 return Error("Bad exit anchor offset %d in entry exit record %d", offset_exit_anchor, i); 620 } 621 if (!ParseAnchorTable(font, data + offset_exit_anchor, 622 length - offset_exit_anchor)) { 623 return Error("Failed to parse exit anchor table in entry exit record %d", i); 624 } 625 } 626 } 627 628 if (offset_coverage < subtable.offset() || offset_coverage >= length) { 629 return Error("Bad coverage offset in cursive attachment %d", offset_coverage); 630 } 631 if (!ots::ParseCoverageTable(font, data + offset_coverage, 632 length - offset_coverage, 633 maxp->num_glyphs)) { 634 return Error("Failed to parse coverage table in cursive attachment"); 635 } 636 637 return true; 638 } 639 640 // Lookup Type 4: 641 // MarkToBase Attachment Positioning Subtable 642 bool OpenTypeGPOS::ParseMarkToBaseAttachment(const uint8_t *data, 643 const size_t length) { 644 return ParseMarkToAttachmentSubtables(GetFont(), data, length, 645 GPOS_TYPE_MARK_TO_BASE_ATTACHMENT); 646 } 647 648 // Lookup Type 5: 649 // MarkToLigature Attachment Positioning Subtable 650 bool OpenTypeGPOS::ParseMarkToLigatureAttachment(const uint8_t *data, 651 const size_t length) { 652 return ParseMarkToAttachmentSubtables(GetFont(), data, length, 653 GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT); 654 } 655 656 // Lookup Type 6: 657 // MarkToMark Attachment Positioning Subtable 658 bool OpenTypeGPOS::ParseMarkToMarkAttachment(const uint8_t *data, 659 const size_t length) { 660 return ParseMarkToAttachmentSubtables(GetFont(), data, length, 661 GPOS_TYPE_MARK_TO_MARK_ATTACHMENT); 662 } 663 664 // Lookup Type 7: 665 // Contextual Positioning Subtables 666 // OpenTypeLayoutTable::ParseContextSubtable() 667 668 // Lookup Type 8: 669 // Chaining Contexual Positioning Subtable 670 // OpenTypeLayoutTable::ParseChainingContextSubtable() 671 672 // Lookup Type 9: 673 // Extension Positioning 674 // OpenTypeLayoutTable::ParseExtensionSubtable 675 676 677 bool OpenTypeGPOS::ValidLookupSubtableType(const uint16_t lookup_type, 678 bool extension) const { 679 if (extension && lookup_type == GPOS_TYPE_EXTENSION_POSITIONING) 680 return false; 681 return lookup_type >= GPOS_TYPE_SINGLE_ADJUSTMENT && lookup_type < GPOS_TYPE_RESERVED; 682 } 683 684 bool OpenTypeGPOS::ParseLookupSubtable(const uint8_t *data, const size_t length, 685 const uint16_t lookup_type) { 686 switch (lookup_type) { 687 case GPOS_TYPE_SINGLE_ADJUSTMENT: 688 return ParseSingleAdjustment(data, length); 689 case GPOS_TYPE_PAIR_ADJUSTMENT: 690 return ParsePairAdjustment(data, length); 691 case GPOS_TYPE_CURSIVE_ATTACHMENT: 692 return ParseCursiveAttachment(data, length); 693 case GPOS_TYPE_MARK_TO_BASE_ATTACHMENT: 694 return ParseMarkToBaseAttachment(data, length); 695 case GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT: 696 return ParseMarkToLigatureAttachment(data, length); 697 case GPOS_TYPE_MARK_TO_MARK_ATTACHMENT: 698 return ParseMarkToMarkAttachment(data, length); 699 case GPOS_TYPE_CONTEXT_POSITIONING: 700 return ParseContextSubtable(data, length); 701 case GPOS_TYPE_CHAINED_CONTEXT_POSITIONING: 702 return ParseChainingContextSubtable(data, length); 703 case GPOS_TYPE_EXTENSION_POSITIONING: 704 return ParseExtensionSubtable(data, length); 705 } 706 return false; 707 } 708 709 } // namespace ots 710 711 #undef TABLE_NAME