1 /* 2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 3 * Copyright © 2010,2012,2013 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Red Hat Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29 #ifndef HB_OT_LAYOUT_GPOS_TABLE_HH 30 #define HB_OT_LAYOUT_GPOS_TABLE_HH 31 32 #include "hb-ot-layout-gsubgpos-private.hh" 33 34 35 namespace OT { 36 37 38 /* buffer **position** var allocations */ 39 #define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */ 40 #define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */ 41 42 43 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */ 44 45 typedef USHORT Value; 46 47 typedef Value ValueRecord[VAR]; 48 49 struct ValueFormat : USHORT 50 { 51 enum Flags { 52 xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */ 53 yPlacement = 0x0002u, /* Includes vertical adjustment for placement */ 54 xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */ 55 yAdvance = 0x0008u, /* Includes vertical adjustment for advance */ 56 xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */ 57 yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */ 58 xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */ 59 yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */ 60 ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */ 61 reserved = 0xF000u, /* For future use */ 62 63 devices = 0x00F0u /* Mask for having any Device table */ 64 }; 65 66 /* All fields are options. Only those available advance the value pointer. */ 67 #if 0 68 SHORT xPlacement; /* Horizontal adjustment for 69 * placement--in design units */ 70 SHORT yPlacement; /* Vertical adjustment for 71 * placement--in design units */ 72 SHORT xAdvance; /* Horizontal adjustment for 73 * advance--in design units (only used 74 * for horizontal writing) */ 75 SHORT yAdvance; /* Vertical adjustment for advance--in 76 * design units (only used for vertical 77 * writing) */ 78 Offset xPlaDevice; /* Offset to Device table for 79 * horizontal placement--measured from 80 * beginning of PosTable (may be NULL) */ 81 Offset yPlaDevice; /* Offset to Device table for vertical 82 * placement--measured from beginning 83 * of PosTable (may be NULL) */ 84 Offset xAdvDevice; /* Offset to Device table for 85 * horizontal advance--measured from 86 * beginning of PosTable (may be NULL) */ 87 Offset yAdvDevice; /* Offset to Device table for vertical 88 * advance--measured from beginning of 89 * PosTable (may be NULL) */ 90 #endif 91 92 inline unsigned int get_len (void) const 93 { return _hb_popcount32 ((unsigned int) *this); } 94 inline unsigned int get_size (void) const 95 { return get_len () * Value::static_size; } 96 97 void apply_value (hb_font_t *font, 98 hb_direction_t direction, 99 const void *base, 100 const Value *values, 101 hb_glyph_position_t &glyph_pos) const 102 { 103 unsigned int x_ppem, y_ppem; 104 unsigned int format = *this; 105 hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction); 106 107 if (!format) return; 108 109 if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++)); 110 if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++)); 111 if (format & xAdvance) { 112 if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values)); 113 values++; 114 } 115 /* y_advance values grow downward but font-space grows upward, hence negation */ 116 if (format & yAdvance) { 117 if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values)); 118 values++; 119 } 120 121 if (!has_device ()) return; 122 123 x_ppem = font->x_ppem; 124 y_ppem = font->y_ppem; 125 126 if (!x_ppem && !y_ppem) return; 127 128 /* pixel -> fractional pixel */ 129 if (format & xPlaDevice) { 130 if (x_ppem) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font); 131 values++; 132 } 133 if (format & yPlaDevice) { 134 if (y_ppem) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font); 135 values++; 136 } 137 if (format & xAdvDevice) { 138 if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font); 139 values++; 140 } 141 if (format & yAdvDevice) { 142 /* y_advance values grow downward but font-space grows upward, hence negation */ 143 if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font); 144 values++; 145 } 146 } 147 148 private: 149 inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const 150 { 151 unsigned int format = *this; 152 153 if (format & xPlacement) values++; 154 if (format & yPlacement) values++; 155 if (format & xAdvance) values++; 156 if (format & yAdvance) values++; 157 158 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 159 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 160 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 161 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 162 163 return true; 164 } 165 166 static inline OffsetTo<Device>& get_device (Value* value) 167 { return *CastP<OffsetTo<Device> > (value); } 168 static inline const OffsetTo<Device>& get_device (const Value* value) 169 { return *CastP<OffsetTo<Device> > (value); } 170 171 static inline const SHORT& get_short (const Value* value) 172 { return *CastP<SHORT> (value); } 173 174 public: 175 176 inline bool has_device (void) const { 177 unsigned int format = *this; 178 return (format & devices) != 0; 179 } 180 181 inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const 182 { 183 TRACE_SANITIZE (this); 184 return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); 185 } 186 187 inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const 188 { 189 TRACE_SANITIZE (this); 190 unsigned int len = get_len (); 191 192 if (!c->check_array (values, get_size (), count)) return_trace (false); 193 194 if (!has_device ()) return_trace (true); 195 196 for (unsigned int i = 0; i < count; i++) { 197 if (!sanitize_value_devices (c, base, values)) 198 return_trace (false); 199 values += len; 200 } 201 202 return_trace (true); 203 } 204 205 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ 206 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const 207 { 208 TRACE_SANITIZE (this); 209 210 if (!has_device ()) return_trace (true); 211 212 for (unsigned int i = 0; i < count; i++) { 213 if (!sanitize_value_devices (c, base, values)) 214 return_trace (false); 215 values += stride; 216 } 217 218 return_trace (true); 219 } 220 }; 221 222 223 struct AnchorFormat1 224 { 225 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED, 226 hb_position_t *x, hb_position_t *y) const 227 { 228 *x = font->em_scale_x (xCoordinate); 229 *y = font->em_scale_y (yCoordinate); 230 } 231 232 inline bool sanitize (hb_sanitize_context_t *c) const 233 { 234 TRACE_SANITIZE (this); 235 return_trace (c->check_struct (this)); 236 } 237 238 protected: 239 USHORT format; /* Format identifier--format = 1 */ 240 SHORT xCoordinate; /* Horizontal value--in design units */ 241 SHORT yCoordinate; /* Vertical value--in design units */ 242 public: 243 DEFINE_SIZE_STATIC (6); 244 }; 245 246 struct AnchorFormat2 247 { 248 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id, 249 hb_position_t *x, hb_position_t *y) const 250 { 251 unsigned int x_ppem = font->x_ppem; 252 unsigned int y_ppem = font->y_ppem; 253 hb_position_t cx, cy; 254 hb_bool_t ret; 255 256 ret = (x_ppem || y_ppem) && 257 font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy); 258 *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate); 259 *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate); 260 } 261 262 inline bool sanitize (hb_sanitize_context_t *c) const 263 { 264 TRACE_SANITIZE (this); 265 return_trace (c->check_struct (this)); 266 } 267 268 protected: 269 USHORT format; /* Format identifier--format = 2 */ 270 SHORT xCoordinate; /* Horizontal value--in design units */ 271 SHORT yCoordinate; /* Vertical value--in design units */ 272 USHORT anchorPoint; /* Index to glyph contour point */ 273 public: 274 DEFINE_SIZE_STATIC (8); 275 }; 276 277 struct AnchorFormat3 278 { 279 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED, 280 hb_position_t *x, hb_position_t *y) const 281 { 282 *x = font->em_scale_x (xCoordinate); 283 *y = font->em_scale_y (yCoordinate); 284 285 if (font->x_ppem) 286 *x += (this+xDeviceTable).get_x_delta (font); 287 if (font->y_ppem) 288 *y += (this+yDeviceTable).get_x_delta (font); 289 } 290 291 inline bool sanitize (hb_sanitize_context_t *c) const 292 { 293 TRACE_SANITIZE (this); 294 return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); 295 } 296 297 protected: 298 USHORT format; /* Format identifier--format = 3 */ 299 SHORT xCoordinate; /* Horizontal value--in design units */ 300 SHORT yCoordinate; /* Vertical value--in design units */ 301 OffsetTo<Device> 302 xDeviceTable; /* Offset to Device table for X 303 * coordinate-- from beginning of 304 * Anchor table (may be NULL) */ 305 OffsetTo<Device> 306 yDeviceTable; /* Offset to Device table for Y 307 * coordinate-- from beginning of 308 * Anchor table (may be NULL) */ 309 public: 310 DEFINE_SIZE_STATIC (10); 311 }; 312 313 struct Anchor 314 { 315 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id, 316 hb_position_t *x, hb_position_t *y) const 317 { 318 *x = *y = 0; 319 switch (u.format) { 320 case 1: u.format1.get_anchor (font, glyph_id, x, y); return; 321 case 2: u.format2.get_anchor (font, glyph_id, x, y); return; 322 case 3: u.format3.get_anchor (font, glyph_id, x, y); return; 323 default: return; 324 } 325 } 326 327 inline bool sanitize (hb_sanitize_context_t *c) const 328 { 329 TRACE_SANITIZE (this); 330 if (!u.format.sanitize (c)) return_trace (false); 331 switch (u.format) { 332 case 1: return_trace (u.format1.sanitize (c)); 333 case 2: return_trace (u.format2.sanitize (c)); 334 case 3: return_trace (u.format3.sanitize (c)); 335 default:return_trace (true); 336 } 337 } 338 339 protected: 340 union { 341 USHORT format; /* Format identifier */ 342 AnchorFormat1 format1; 343 AnchorFormat2 format2; 344 AnchorFormat3 format3; 345 } u; 346 public: 347 DEFINE_SIZE_UNION (2, format); 348 }; 349 350 351 struct AnchorMatrix 352 { 353 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const { 354 *found = false; 355 if (unlikely (row >= rows || col >= cols)) return Null(Anchor); 356 *found = !matrixZ[row * cols + col].is_null (); 357 return this+matrixZ[row * cols + col]; 358 } 359 360 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const 361 { 362 TRACE_SANITIZE (this); 363 if (!c->check_struct (this)) return_trace (false); 364 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false); 365 unsigned int count = rows * cols; 366 if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false); 367 for (unsigned int i = 0; i < count; i++) 368 if (!matrixZ[i].sanitize (c, this)) return_trace (false); 369 return_trace (true); 370 } 371 372 USHORT rows; /* Number of rows */ 373 protected: 374 OffsetTo<Anchor> 375 matrixZ[VAR]; /* Matrix of offsets to Anchor tables-- 376 * from beginning of AnchorMatrix table */ 377 public: 378 DEFINE_SIZE_ARRAY (2, matrixZ); 379 }; 380 381 382 struct MarkRecord 383 { 384 friend struct MarkArray; 385 386 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 387 { 388 TRACE_SANITIZE (this); 389 return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); 390 } 391 392 protected: 393 USHORT klass; /* Class defined for this mark */ 394 OffsetTo<Anchor> 395 markAnchor; /* Offset to Anchor table--from 396 * beginning of MarkArray table */ 397 public: 398 DEFINE_SIZE_STATIC (4); 399 }; 400 401 struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */ 402 { 403 inline bool apply (hb_apply_context_t *c, 404 unsigned int mark_index, unsigned int glyph_index, 405 const AnchorMatrix &anchors, unsigned int class_count, 406 unsigned int glyph_pos) const 407 { 408 TRACE_APPLY (this); 409 hb_buffer_t *buffer = c->buffer; 410 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index); 411 unsigned int mark_class = record.klass; 412 413 const Anchor& mark_anchor = this + record.markAnchor; 414 bool found; 415 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found); 416 /* If this subtable doesn't have an anchor for this base and this class, 417 * return false such that the subsequent subtables have a chance at it. */ 418 if (unlikely (!found)) return_trace (false); 419 420 hb_position_t mark_x, mark_y, base_x, base_y; 421 422 mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y); 423 glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y); 424 425 hb_glyph_position_t &o = buffer->cur_pos(); 426 o.x_offset = base_x - mark_x; 427 o.y_offset = base_y - mark_y; 428 o.attach_lookback() = buffer->idx - glyph_pos; 429 430 buffer->idx++; 431 return_trace (true); 432 } 433 434 inline bool sanitize (hb_sanitize_context_t *c) const 435 { 436 TRACE_SANITIZE (this); 437 return_trace (ArrayOf<MarkRecord>::sanitize (c, this)); 438 } 439 }; 440 441 442 /* Lookups */ 443 444 struct SinglePosFormat1 445 { 446 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 447 { 448 TRACE_COLLECT_GLYPHS (this); 449 (this+coverage).add_coverage (c->input); 450 } 451 452 inline const Coverage &get_coverage (void) const 453 { 454 return this+coverage; 455 } 456 457 inline bool apply (hb_apply_context_t *c) const 458 { 459 TRACE_APPLY (this); 460 hb_buffer_t *buffer = c->buffer; 461 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 462 if (likely (index == NOT_COVERED)) return_trace (false); 463 464 valueFormat.apply_value (c->font, c->direction, this, 465 values, buffer->cur_pos()); 466 467 buffer->idx++; 468 return_trace (true); 469 } 470 471 inline bool sanitize (hb_sanitize_context_t *c) const 472 { 473 TRACE_SANITIZE (this); 474 return_trace (c->check_struct (this) && 475 coverage.sanitize (c, this) && 476 valueFormat.sanitize_value (c, this, values)); 477 } 478 479 protected: 480 USHORT format; /* Format identifier--format = 1 */ 481 OffsetTo<Coverage> 482 coverage; /* Offset to Coverage table--from 483 * beginning of subtable */ 484 ValueFormat valueFormat; /* Defines the types of data in the 485 * ValueRecord */ 486 ValueRecord values; /* Defines positioning 487 * value(s)--applied to all glyphs in 488 * the Coverage table */ 489 public: 490 DEFINE_SIZE_ARRAY (6, values); 491 }; 492 493 struct SinglePosFormat2 494 { 495 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 496 { 497 TRACE_COLLECT_GLYPHS (this); 498 (this+coverage).add_coverage (c->input); 499 } 500 501 inline const Coverage &get_coverage (void) const 502 { 503 return this+coverage; 504 } 505 506 inline bool apply (hb_apply_context_t *c) const 507 { 508 TRACE_APPLY (this); 509 hb_buffer_t *buffer = c->buffer; 510 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 511 if (likely (index == NOT_COVERED)) return_trace (false); 512 513 if (likely (index >= valueCount)) return_trace (false); 514 515 valueFormat.apply_value (c->font, c->direction, this, 516 &values[index * valueFormat.get_len ()], 517 buffer->cur_pos()); 518 519 buffer->idx++; 520 return_trace (true); 521 } 522 523 inline bool sanitize (hb_sanitize_context_t *c) const 524 { 525 TRACE_SANITIZE (this); 526 return_trace (c->check_struct (this) && 527 coverage.sanitize (c, this) && 528 valueFormat.sanitize_values (c, this, values, valueCount)); 529 } 530 531 protected: 532 USHORT format; /* Format identifier--format = 2 */ 533 OffsetTo<Coverage> 534 coverage; /* Offset to Coverage table--from 535 * beginning of subtable */ 536 ValueFormat valueFormat; /* Defines the types of data in the 537 * ValueRecord */ 538 USHORT valueCount; /* Number of ValueRecords */ 539 ValueRecord values; /* Array of ValueRecords--positioning 540 * values applied to glyphs */ 541 public: 542 DEFINE_SIZE_ARRAY (8, values); 543 }; 544 545 struct SinglePos 546 { 547 template <typename context_t> 548 inline typename context_t::return_t dispatch (context_t *c) const 549 { 550 TRACE_DISPATCH (this, u.format); 551 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 552 switch (u.format) { 553 case 1: return_trace (c->dispatch (u.format1)); 554 case 2: return_trace (c->dispatch (u.format2)); 555 default:return_trace (c->default_return_value ()); 556 } 557 } 558 559 protected: 560 union { 561 USHORT format; /* Format identifier */ 562 SinglePosFormat1 format1; 563 SinglePosFormat2 format2; 564 } u; 565 }; 566 567 568 struct PairValueRecord 569 { 570 friend struct PairSet; 571 572 protected: 573 GlyphID secondGlyph; /* GlyphID of second glyph in the 574 * pair--first glyph is listed in the 575 * Coverage table */ 576 ValueRecord values; /* Positioning data for the first glyph 577 * followed by for second glyph */ 578 public: 579 DEFINE_SIZE_ARRAY (2, values); 580 }; 581 582 struct PairSet 583 { 584 friend struct PairPosFormat1; 585 586 inline void collect_glyphs (hb_collect_glyphs_context_t *c, 587 const ValueFormat *valueFormats) const 588 { 589 TRACE_COLLECT_GLYPHS (this); 590 unsigned int len1 = valueFormats[0].get_len (); 591 unsigned int len2 = valueFormats[1].get_len (); 592 unsigned int record_size = USHORT::static_size * (1 + len1 + len2); 593 594 const PairValueRecord *record = CastP<PairValueRecord> (arrayZ); 595 unsigned int count = len; 596 for (unsigned int i = 0; i < count; i++) 597 { 598 c->input->add (record->secondGlyph); 599 record = &StructAtOffset<PairValueRecord> (record, record_size); 600 } 601 } 602 603 inline bool apply (hb_apply_context_t *c, 604 const ValueFormat *valueFormats, 605 unsigned int pos) const 606 { 607 TRACE_APPLY (this); 608 hb_buffer_t *buffer = c->buffer; 609 unsigned int len1 = valueFormats[0].get_len (); 610 unsigned int len2 = valueFormats[1].get_len (); 611 unsigned int record_size = USHORT::static_size * (1 + len1 + len2); 612 613 const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ); 614 unsigned int count = len; 615 616 /* Hand-coded bsearch. */ 617 if (unlikely (!count)) 618 return_trace (false); 619 hb_codepoint_t x = buffer->info[pos].codepoint; 620 int min = 0, max = (int) count - 1; 621 while (min <= max) 622 { 623 int mid = (min + max) / 2; 624 const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid); 625 hb_codepoint_t mid_x = record->secondGlyph; 626 if (x < mid_x) 627 max = mid - 1; 628 else if (x > mid_x) 629 min = mid + 1; 630 else 631 { 632 valueFormats[0].apply_value (c->font, c->direction, this, 633 &record->values[0], buffer->cur_pos()); 634 valueFormats[1].apply_value (c->font, c->direction, this, 635 &record->values[len1], buffer->pos[pos]); 636 if (len2) 637 pos++; 638 buffer->idx = pos; 639 return_trace (true); 640 } 641 } 642 643 return_trace (false); 644 } 645 646 struct sanitize_closure_t { 647 const void *base; 648 const ValueFormat *valueFormats; 649 unsigned int len1; /* valueFormats[0].get_len() */ 650 unsigned int stride; /* 1 + len1 + len2 */ 651 }; 652 653 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const 654 { 655 TRACE_SANITIZE (this); 656 if (!(c->check_struct (this) 657 && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false); 658 659 unsigned int count = len; 660 const PairValueRecord *record = CastP<PairValueRecord> (arrayZ); 661 return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) && 662 closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride)); 663 } 664 665 protected: 666 USHORT len; /* Number of PairValueRecords */ 667 USHORT arrayZ[VAR]; /* Array of PairValueRecords--ordered 668 * by GlyphID of the second glyph */ 669 public: 670 DEFINE_SIZE_ARRAY (2, arrayZ); 671 }; 672 673 struct PairPosFormat1 674 { 675 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 676 { 677 TRACE_COLLECT_GLYPHS (this); 678 (this+coverage).add_coverage (c->input); 679 unsigned int count = pairSet.len; 680 for (unsigned int i = 0; i < count; i++) 681 (this+pairSet[i]).collect_glyphs (c, &valueFormat1); 682 } 683 684 inline const Coverage &get_coverage (void) const 685 { 686 return this+coverage; 687 } 688 689 inline bool apply (hb_apply_context_t *c) const 690 { 691 TRACE_APPLY (this); 692 hb_buffer_t *buffer = c->buffer; 693 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 694 if (likely (index == NOT_COVERED)) return_trace (false); 695 696 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 697 skippy_iter.reset (buffer->idx, 1); 698 if (!skippy_iter.next ()) return_trace (false); 699 700 return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx)); 701 } 702 703 inline bool sanitize (hb_sanitize_context_t *c) const 704 { 705 TRACE_SANITIZE (this); 706 707 if (!c->check_struct (this)) return_trace (false); 708 709 unsigned int len1 = valueFormat1.get_len (); 710 unsigned int len2 = valueFormat2.get_len (); 711 PairSet::sanitize_closure_t closure = { 712 this, 713 &valueFormat1, 714 len1, 715 1 + len1 + len2 716 }; 717 718 return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); 719 } 720 721 protected: 722 USHORT format; /* Format identifier--format = 1 */ 723 OffsetTo<Coverage> 724 coverage; /* Offset to Coverage table--from 725 * beginning of subtable */ 726 ValueFormat valueFormat1; /* Defines the types of data in 727 * ValueRecord1--for the first glyph 728 * in the pair--may be zero (0) */ 729 ValueFormat valueFormat2; /* Defines the types of data in 730 * ValueRecord2--for the second glyph 731 * in the pair--may be zero (0) */ 732 OffsetArrayOf<PairSet> 733 pairSet; /* Array of PairSet tables 734 * ordered by Coverage Index */ 735 public: 736 DEFINE_SIZE_ARRAY (10, pairSet); 737 }; 738 739 struct PairPosFormat2 740 { 741 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 742 { 743 TRACE_COLLECT_GLYPHS (this); 744 /* (this+coverage).add_coverage (c->input); // Don't need this. */ 745 746 unsigned int count1 = class1Count; 747 const ClassDef &klass1 = this+classDef1; 748 for (unsigned int i = 0; i < count1; i++) 749 klass1.add_class (c->input, i); 750 751 unsigned int count2 = class2Count; 752 const ClassDef &klass2 = this+classDef2; 753 for (unsigned int i = 0; i < count2; i++) 754 klass2.add_class (c->input, i); 755 } 756 757 inline const Coverage &get_coverage (void) const 758 { 759 return this+coverage; 760 } 761 762 inline bool apply (hb_apply_context_t *c) const 763 { 764 TRACE_APPLY (this); 765 hb_buffer_t *buffer = c->buffer; 766 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 767 if (likely (index == NOT_COVERED)) return_trace (false); 768 769 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 770 skippy_iter.reset (buffer->idx, 1); 771 if (!skippy_iter.next ()) return_trace (false); 772 773 unsigned int len1 = valueFormat1.get_len (); 774 unsigned int len2 = valueFormat2.get_len (); 775 unsigned int record_len = len1 + len2; 776 777 unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); 778 unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); 779 if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false); 780 781 const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; 782 valueFormat1.apply_value (c->font, c->direction, this, 783 v, buffer->cur_pos()); 784 valueFormat2.apply_value (c->font, c->direction, this, 785 v + len1, buffer->pos[skippy_iter.idx]); 786 787 buffer->idx = skippy_iter.idx; 788 if (len2) 789 buffer->idx++; 790 791 return_trace (true); 792 } 793 794 inline bool sanitize (hb_sanitize_context_t *c) const 795 { 796 TRACE_SANITIZE (this); 797 if (!(c->check_struct (this) 798 && coverage.sanitize (c, this) 799 && classDef1.sanitize (c, this) 800 && classDef2.sanitize (c, this))) return_trace (false); 801 802 unsigned int len1 = valueFormat1.get_len (); 803 unsigned int len2 = valueFormat2.get_len (); 804 unsigned int stride = len1 + len2; 805 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); 806 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; 807 return_trace (c->check_array (values, record_size, count) && 808 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && 809 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); 810 } 811 812 protected: 813 USHORT format; /* Format identifier--format = 2 */ 814 OffsetTo<Coverage> 815 coverage; /* Offset to Coverage table--from 816 * beginning of subtable */ 817 ValueFormat valueFormat1; /* ValueRecord definition--for the 818 * first glyph of the pair--may be zero 819 * (0) */ 820 ValueFormat valueFormat2; /* ValueRecord definition--for the 821 * second glyph of the pair--may be 822 * zero (0) */ 823 OffsetTo<ClassDef> 824 classDef1; /* Offset to ClassDef table--from 825 * beginning of PairPos subtable--for 826 * the first glyph of the pair */ 827 OffsetTo<ClassDef> 828 classDef2; /* Offset to ClassDef table--from 829 * beginning of PairPos subtable--for 830 * the second glyph of the pair */ 831 USHORT class1Count; /* Number of classes in ClassDef1 832 * table--includes Class0 */ 833 USHORT class2Count; /* Number of classes in ClassDef2 834 * table--includes Class0 */ 835 ValueRecord values; /* Matrix of value pairs: 836 * class1-major, class2-minor, 837 * Each entry has value1 and value2 */ 838 public: 839 DEFINE_SIZE_ARRAY (16, values); 840 }; 841 842 struct PairPos 843 { 844 template <typename context_t> 845 inline typename context_t::return_t dispatch (context_t *c) const 846 { 847 TRACE_DISPATCH (this, u.format); 848 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 849 switch (u.format) { 850 case 1: return_trace (c->dispatch (u.format1)); 851 case 2: return_trace (c->dispatch (u.format2)); 852 default:return_trace (c->default_return_value ()); 853 } 854 } 855 856 protected: 857 union { 858 USHORT format; /* Format identifier */ 859 PairPosFormat1 format1; 860 PairPosFormat2 format2; 861 } u; 862 }; 863 864 865 struct EntryExitRecord 866 { 867 friend struct CursivePosFormat1; 868 869 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 870 { 871 TRACE_SANITIZE (this); 872 return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); 873 } 874 875 protected: 876 OffsetTo<Anchor> 877 entryAnchor; /* Offset to EntryAnchor table--from 878 * beginning of CursivePos 879 * subtable--may be NULL */ 880 OffsetTo<Anchor> 881 exitAnchor; /* Offset to ExitAnchor table--from 882 * beginning of CursivePos 883 * subtable--may be NULL */ 884 public: 885 DEFINE_SIZE_STATIC (4); 886 }; 887 888 static void 889 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent); 890 891 struct CursivePosFormat1 892 { 893 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 894 { 895 TRACE_COLLECT_GLYPHS (this); 896 (this+coverage).add_coverage (c->input); 897 } 898 899 inline const Coverage &get_coverage (void) const 900 { 901 return this+coverage; 902 } 903 904 inline bool apply (hb_apply_context_t *c) const 905 { 906 TRACE_APPLY (this); 907 hb_buffer_t *buffer = c->buffer; 908 909 /* We don't handle mark glyphs here. */ 910 if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return_trace (false); 911 912 const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; 913 if (!this_record.exitAnchor) return_trace (false); 914 915 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 916 skippy_iter.reset (buffer->idx, 1); 917 if (!skippy_iter.next ()) return_trace (false); 918 919 const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; 920 if (!next_record.entryAnchor) return_trace (false); 921 922 unsigned int i = buffer->idx; 923 unsigned int j = skippy_iter.idx; 924 925 hb_position_t entry_x, entry_y, exit_x, exit_y; 926 (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y); 927 (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y); 928 929 hb_glyph_position_t *pos = buffer->pos; 930 931 hb_position_t d; 932 /* Main-direction adjustment */ 933 switch (c->direction) { 934 case HB_DIRECTION_LTR: 935 pos[i].x_advance = exit_x + pos[i].x_offset; 936 937 d = entry_x + pos[j].x_offset; 938 pos[j].x_advance -= d; 939 pos[j].x_offset -= d; 940 break; 941 case HB_DIRECTION_RTL: 942 d = exit_x + pos[i].x_offset; 943 pos[i].x_advance -= d; 944 pos[i].x_offset -= d; 945 946 pos[j].x_advance = entry_x + pos[j].x_offset; 947 break; 948 case HB_DIRECTION_TTB: 949 pos[i].y_advance = exit_y + pos[i].y_offset; 950 951 d = entry_y + pos[j].y_offset; 952 pos[j].y_advance -= d; 953 pos[j].y_offset -= d; 954 break; 955 case HB_DIRECTION_BTT: 956 d = exit_y + pos[i].y_offset; 957 pos[i].y_advance -= d; 958 pos[i].y_offset -= d; 959 960 pos[j].y_advance = entry_y; 961 break; 962 case HB_DIRECTION_INVALID: 963 default: 964 break; 965 } 966 967 /* Cross-direction adjustment */ 968 969 /* We attach child to parent (think graph theory and rooted trees whereas 970 * the root stays on baseline and each node aligns itself against its 971 * parent. 972 * 973 * Optimize things for the case of RightToLeft, as that's most common in 974 * Arabinc. */ 975 unsigned int child = i; 976 unsigned int parent = j; 977 hb_position_t x_offset = entry_x - exit_x; 978 hb_position_t y_offset = entry_y - exit_y; 979 if (!(c->lookup_props & LookupFlag::RightToLeft)) 980 { 981 unsigned int k = child; 982 child = parent; 983 parent = k; 984 x_offset = -x_offset; 985 y_offset = -y_offset; 986 } 987 988 /* If child was already connected to someone else, walk through its old 989 * chain and reverse the link direction, such that the whole tree of its 990 * previous connection now attaches to new parent. Watch out for case 991 * where new parent is on the path from old chain... 992 */ 993 reverse_cursive_minor_offset (pos, child, c->direction, parent); 994 995 pos[child].cursive_chain() = parent - child; 996 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) 997 pos[child].y_offset = y_offset; 998 else 999 pos[child].x_offset = x_offset; 1000 1001 buffer->idx = j; 1002 return_trace (true); 1003 } 1004 1005 inline bool sanitize (hb_sanitize_context_t *c) const 1006 { 1007 TRACE_SANITIZE (this); 1008 return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); 1009 } 1010 1011 protected: 1012 USHORT format; /* Format identifier--format = 1 */ 1013 OffsetTo<Coverage> 1014 coverage; /* Offset to Coverage table--from 1015 * beginning of subtable */ 1016 ArrayOf<EntryExitRecord> 1017 entryExitRecord; /* Array of EntryExit records--in 1018 * Coverage Index order */ 1019 public: 1020 DEFINE_SIZE_ARRAY (6, entryExitRecord); 1021 }; 1022 1023 struct CursivePos 1024 { 1025 template <typename context_t> 1026 inline typename context_t::return_t dispatch (context_t *c) const 1027 { 1028 TRACE_DISPATCH (this, u.format); 1029 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1030 switch (u.format) { 1031 case 1: return_trace (c->dispatch (u.format1)); 1032 default:return_trace (c->default_return_value ()); 1033 } 1034 } 1035 1036 protected: 1037 union { 1038 USHORT format; /* Format identifier */ 1039 CursivePosFormat1 format1; 1040 } u; 1041 }; 1042 1043 1044 typedef AnchorMatrix BaseArray; /* base-major-- 1045 * in order of BaseCoverage Index--, 1046 * mark-minor-- 1047 * ordered by class--zero-based. */ 1048 1049 struct MarkBasePosFormat1 1050 { 1051 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1052 { 1053 TRACE_COLLECT_GLYPHS (this); 1054 (this+markCoverage).add_coverage (c->input); 1055 (this+baseCoverage).add_coverage (c->input); 1056 } 1057 1058 inline const Coverage &get_coverage (void) const 1059 { 1060 return this+markCoverage; 1061 } 1062 1063 inline bool apply (hb_apply_context_t *c) const 1064 { 1065 TRACE_APPLY (this); 1066 hb_buffer_t *buffer = c->buffer; 1067 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); 1068 if (likely (mark_index == NOT_COVERED)) return_trace (false); 1069 1070 /* now we search backwards for a non-mark glyph */ 1071 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 1072 skippy_iter.reset (buffer->idx, 1); 1073 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); 1074 do { 1075 if (!skippy_iter.prev ()) return_trace (false); 1076 /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */ 1077 if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break; 1078 skippy_iter.reject (); 1079 } while (1); 1080 1081 /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ 1082 if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ } 1083 1084 unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); 1085 if (base_index == NOT_COVERED) return_trace (false); 1086 1087 return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); 1088 } 1089 1090 inline bool sanitize (hb_sanitize_context_t *c) const 1091 { 1092 TRACE_SANITIZE (this); 1093 return_trace (c->check_struct (this) && 1094 markCoverage.sanitize (c, this) && 1095 baseCoverage.sanitize (c, this) && 1096 markArray.sanitize (c, this) && 1097 baseArray.sanitize (c, this, (unsigned int) classCount)); 1098 } 1099 1100 protected: 1101 USHORT format; /* Format identifier--format = 1 */ 1102 OffsetTo<Coverage> 1103 markCoverage; /* Offset to MarkCoverage table--from 1104 * beginning of MarkBasePos subtable */ 1105 OffsetTo<Coverage> 1106 baseCoverage; /* Offset to BaseCoverage table--from 1107 * beginning of MarkBasePos subtable */ 1108 USHORT classCount; /* Number of classes defined for marks */ 1109 OffsetTo<MarkArray> 1110 markArray; /* Offset to MarkArray table--from 1111 * beginning of MarkBasePos subtable */ 1112 OffsetTo<BaseArray> 1113 baseArray; /* Offset to BaseArray table--from 1114 * beginning of MarkBasePos subtable */ 1115 public: 1116 DEFINE_SIZE_STATIC (12); 1117 }; 1118 1119 struct MarkBasePos 1120 { 1121 template <typename context_t> 1122 inline typename context_t::return_t dispatch (context_t *c) const 1123 { 1124 TRACE_DISPATCH (this, u.format); 1125 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1126 switch (u.format) { 1127 case 1: return_trace (c->dispatch (u.format1)); 1128 default:return_trace (c->default_return_value ()); 1129 } 1130 } 1131 1132 protected: 1133 union { 1134 USHORT format; /* Format identifier */ 1135 MarkBasePosFormat1 format1; 1136 } u; 1137 }; 1138 1139 1140 typedef AnchorMatrix LigatureAttach; /* component-major-- 1141 * in order of writing direction--, 1142 * mark-minor-- 1143 * ordered by class--zero-based. */ 1144 1145 typedef OffsetListOf<LigatureAttach> LigatureArray; 1146 /* Array of LigatureAttach 1147 * tables ordered by 1148 * LigatureCoverage Index */ 1149 1150 struct MarkLigPosFormat1 1151 { 1152 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1153 { 1154 TRACE_COLLECT_GLYPHS (this); 1155 (this+markCoverage).add_coverage (c->input); 1156 (this+ligatureCoverage).add_coverage (c->input); 1157 } 1158 1159 inline const Coverage &get_coverage (void) const 1160 { 1161 return this+markCoverage; 1162 } 1163 1164 inline bool apply (hb_apply_context_t *c) const 1165 { 1166 TRACE_APPLY (this); 1167 hb_buffer_t *buffer = c->buffer; 1168 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); 1169 if (likely (mark_index == NOT_COVERED)) return_trace (false); 1170 1171 /* now we search backwards for a non-mark glyph */ 1172 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 1173 skippy_iter.reset (buffer->idx, 1); 1174 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); 1175 if (!skippy_iter.prev ()) return_trace (false); 1176 1177 /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ 1178 if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ } 1179 1180 unsigned int j = skippy_iter.idx; 1181 unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); 1182 if (lig_index == NOT_COVERED) return_trace (false); 1183 1184 const LigatureArray& lig_array = this+ligatureArray; 1185 const LigatureAttach& lig_attach = lig_array[lig_index]; 1186 1187 /* Find component to attach to */ 1188 unsigned int comp_count = lig_attach.rows; 1189 if (unlikely (!comp_count)) return_trace (false); 1190 1191 /* We must now check whether the ligature ID of the current mark glyph 1192 * is identical to the ligature ID of the found ligature. If yes, we 1193 * can directly use the component index. If not, we attach the mark 1194 * glyph to the last component of the ligature. */ 1195 unsigned int comp_index; 1196 unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); 1197 unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 1198 unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); 1199 if (lig_id && lig_id == mark_id && mark_comp > 0) 1200 comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1; 1201 else 1202 comp_index = comp_count - 1; 1203 1204 return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); 1205 } 1206 1207 inline bool sanitize (hb_sanitize_context_t *c) const 1208 { 1209 TRACE_SANITIZE (this); 1210 return_trace (c->check_struct (this) && 1211 markCoverage.sanitize (c, this) && 1212 ligatureCoverage.sanitize (c, this) && 1213 markArray.sanitize (c, this) && 1214 ligatureArray.sanitize (c, this, (unsigned int) classCount)); 1215 } 1216 1217 protected: 1218 USHORT format; /* Format identifier--format = 1 */ 1219 OffsetTo<Coverage> 1220 markCoverage; /* Offset to Mark Coverage table--from 1221 * beginning of MarkLigPos subtable */ 1222 OffsetTo<Coverage> 1223 ligatureCoverage; /* Offset to Ligature Coverage 1224 * table--from beginning of MarkLigPos 1225 * subtable */ 1226 USHORT classCount; /* Number of defined mark classes */ 1227 OffsetTo<MarkArray> 1228 markArray; /* Offset to MarkArray table--from 1229 * beginning of MarkLigPos subtable */ 1230 OffsetTo<LigatureArray> 1231 ligatureArray; /* Offset to LigatureArray table--from 1232 * beginning of MarkLigPos subtable */ 1233 public: 1234 DEFINE_SIZE_STATIC (12); 1235 }; 1236 1237 struct MarkLigPos 1238 { 1239 template <typename context_t> 1240 inline typename context_t::return_t dispatch (context_t *c) const 1241 { 1242 TRACE_DISPATCH (this, u.format); 1243 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1244 switch (u.format) { 1245 case 1: return_trace (c->dispatch (u.format1)); 1246 default:return_trace (c->default_return_value ()); 1247 } 1248 } 1249 1250 protected: 1251 union { 1252 USHORT format; /* Format identifier */ 1253 MarkLigPosFormat1 format1; 1254 } u; 1255 }; 1256 1257 1258 typedef AnchorMatrix Mark2Array; /* mark2-major-- 1259 * in order of Mark2Coverage Index--, 1260 * mark1-minor-- 1261 * ordered by class--zero-based. */ 1262 1263 struct MarkMarkPosFormat1 1264 { 1265 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1266 { 1267 TRACE_COLLECT_GLYPHS (this); 1268 (this+mark1Coverage).add_coverage (c->input); 1269 (this+mark2Coverage).add_coverage (c->input); 1270 } 1271 1272 inline const Coverage &get_coverage (void) const 1273 { 1274 return this+mark1Coverage; 1275 } 1276 1277 inline bool apply (hb_apply_context_t *c) const 1278 { 1279 TRACE_APPLY (this); 1280 hb_buffer_t *buffer = c->buffer; 1281 unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint); 1282 if (likely (mark1_index == NOT_COVERED)) return_trace (false); 1283 1284 /* now we search backwards for a suitable mark glyph until a non-mark glyph */ 1285 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 1286 skippy_iter.reset (buffer->idx, 1); 1287 skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); 1288 if (!skippy_iter.prev ()) return_trace (false); 1289 1290 if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); } 1291 1292 unsigned int j = skippy_iter.idx; 1293 1294 unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur()); 1295 unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]); 1296 unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur()); 1297 unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]); 1298 1299 if (likely (id1 == id2)) { 1300 if (id1 == 0) /* Marks belonging to the same base. */ 1301 goto good; 1302 else if (comp1 == comp2) /* Marks belonging to the same ligature component. */ 1303 goto good; 1304 } else { 1305 /* If ligature ids don't match, it may be the case that one of the marks 1306 * itself is a ligature. In which case match. */ 1307 if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2)) 1308 goto good; 1309 } 1310 1311 /* Didn't match. */ 1312 return_trace (false); 1313 1314 good: 1315 unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); 1316 if (mark2_index == NOT_COVERED) return_trace (false); 1317 1318 return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); 1319 } 1320 1321 inline bool sanitize (hb_sanitize_context_t *c) const 1322 { 1323 TRACE_SANITIZE (this); 1324 return_trace (c->check_struct (this) && 1325 mark1Coverage.sanitize (c, this) && 1326 mark2Coverage.sanitize (c, this) && 1327 mark1Array.sanitize (c, this) && 1328 mark2Array.sanitize (c, this, (unsigned int) classCount)); 1329 } 1330 1331 protected: 1332 USHORT format; /* Format identifier--format = 1 */ 1333 OffsetTo<Coverage> 1334 mark1Coverage; /* Offset to Combining Mark1 Coverage 1335 * table--from beginning of MarkMarkPos 1336 * subtable */ 1337 OffsetTo<Coverage> 1338 mark2Coverage; /* Offset to Combining Mark2 Coverage 1339 * table--from beginning of MarkMarkPos 1340 * subtable */ 1341 USHORT classCount; /* Number of defined mark classes */ 1342 OffsetTo<MarkArray> 1343 mark1Array; /* Offset to Mark1Array table--from 1344 * beginning of MarkMarkPos subtable */ 1345 OffsetTo<Mark2Array> 1346 mark2Array; /* Offset to Mark2Array table--from 1347 * beginning of MarkMarkPos subtable */ 1348 public: 1349 DEFINE_SIZE_STATIC (12); 1350 }; 1351 1352 struct MarkMarkPos 1353 { 1354 template <typename context_t> 1355 inline typename context_t::return_t dispatch (context_t *c) const 1356 { 1357 TRACE_DISPATCH (this, u.format); 1358 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1359 switch (u.format) { 1360 case 1: return_trace (c->dispatch (u.format1)); 1361 default:return_trace (c->default_return_value ()); 1362 } 1363 } 1364 1365 protected: 1366 union { 1367 USHORT format; /* Format identifier */ 1368 MarkMarkPosFormat1 format1; 1369 } u; 1370 }; 1371 1372 1373 struct ContextPos : Context {}; 1374 1375 struct ChainContextPos : ChainContext {}; 1376 1377 struct ExtensionPos : Extension<ExtensionPos> 1378 { 1379 typedef struct PosLookupSubTable LookupSubTable; 1380 }; 1381 1382 1383 1384 /* 1385 * PosLookup 1386 */ 1387 1388 1389 struct PosLookupSubTable 1390 { 1391 friend struct PosLookup; 1392 1393 enum Type { 1394 Single = 1, 1395 Pair = 2, 1396 Cursive = 3, 1397 MarkBase = 4, 1398 MarkLig = 5, 1399 MarkMark = 6, 1400 Context = 7, 1401 ChainContext = 8, 1402 Extension = 9 1403 }; 1404 1405 template <typename context_t> 1406 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const 1407 { 1408 TRACE_DISPATCH (this, lookup_type); 1409 if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ()); 1410 switch (lookup_type) { 1411 case Single: return_trace (u.single.dispatch (c)); 1412 case Pair: return_trace (u.pair.dispatch (c)); 1413 case Cursive: return_trace (u.cursive.dispatch (c)); 1414 case MarkBase: return_trace (u.markBase.dispatch (c)); 1415 case MarkLig: return_trace (u.markLig.dispatch (c)); 1416 case MarkMark: return_trace (u.markMark.dispatch (c)); 1417 case Context: return_trace (u.context.dispatch (c)); 1418 case ChainContext: return_trace (u.chainContext.dispatch (c)); 1419 case Extension: return_trace (u.extension.dispatch (c)); 1420 default: return_trace (c->default_return_value ()); 1421 } 1422 } 1423 1424 protected: 1425 union { 1426 USHORT sub_format; 1427 SinglePos single; 1428 PairPos pair; 1429 CursivePos cursive; 1430 MarkBasePos markBase; 1431 MarkLigPos markLig; 1432 MarkMarkPos markMark; 1433 ContextPos context; 1434 ChainContextPos chainContext; 1435 ExtensionPos extension; 1436 } u; 1437 public: 1438 DEFINE_SIZE_UNION (2, sub_format); 1439 }; 1440 1441 1442 struct PosLookup : Lookup 1443 { 1444 inline const PosLookupSubTable& get_subtable (unsigned int i) const 1445 { return Lookup::get_subtable<PosLookupSubTable> (i); } 1446 1447 inline bool is_reverse (void) const 1448 { 1449 return false; 1450 } 1451 1452 inline bool apply (hb_apply_context_t *c) const 1453 { 1454 TRACE_APPLY (this); 1455 return_trace (dispatch (c)); 1456 } 1457 1458 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const 1459 { 1460 TRACE_COLLECT_GLYPHS (this); 1461 return_trace (dispatch (c)); 1462 } 1463 1464 template <typename set_t> 1465 inline void add_coverage (set_t *glyphs) const 1466 { 1467 hb_add_coverage_context_t<set_t> c (glyphs); 1468 dispatch (&c); 1469 } 1470 1471 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); 1472 1473 template <typename context_t> 1474 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); 1475 1476 template <typename context_t> 1477 inline typename context_t::return_t dispatch (context_t *c) const 1478 { return Lookup::dispatch<PosLookupSubTable> (c); } 1479 1480 inline bool sanitize (hb_sanitize_context_t *c) const 1481 { 1482 TRACE_SANITIZE (this); 1483 if (unlikely (!Lookup::sanitize (c))) return_trace (false); 1484 return_trace (dispatch (c)); 1485 } 1486 }; 1487 1488 typedef OffsetListOf<PosLookup> PosLookupList; 1489 1490 /* 1491 * GPOS -- The Glyph Positioning Table 1492 */ 1493 1494 struct GPOS : GSUBGPOS 1495 { 1496 static const hb_tag_t tableTag = HB_OT_TAG_GPOS; 1497 1498 inline const PosLookup& get_lookup (unsigned int i) const 1499 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } 1500 1501 static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); 1502 static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer); 1503 1504 inline bool sanitize (hb_sanitize_context_t *c) const 1505 { 1506 TRACE_SANITIZE (this); 1507 if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); 1508 const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList); 1509 return_trace (list.sanitize (c, this)); 1510 } 1511 public: 1512 DEFINE_SIZE_STATIC (10); 1513 }; 1514 1515 1516 static void 1517 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) 1518 { 1519 unsigned int j = pos[i].cursive_chain(); 1520 if (likely (!j)) 1521 return; 1522 1523 j += i; 1524 1525 pos[i].cursive_chain() = 0; 1526 1527 /* Stop if we see new parent in the chain. */ 1528 if (j == new_parent) 1529 return; 1530 1531 reverse_cursive_minor_offset (pos, j, direction, new_parent); 1532 1533 if (HB_DIRECTION_IS_HORIZONTAL (direction)) 1534 pos[j].y_offset = -pos[i].y_offset; 1535 else 1536 pos[j].x_offset = -pos[i].x_offset; 1537 1538 pos[j].cursive_chain() = i - j; 1539 } 1540 static void 1541 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) 1542 { 1543 unsigned int j = pos[i].cursive_chain(); 1544 if (likely (!j)) 1545 return; 1546 1547 j += i; 1548 1549 pos[i].cursive_chain() = 0; 1550 1551 fix_cursive_minor_offset (pos, j, direction); 1552 1553 if (HB_DIRECTION_IS_HORIZONTAL (direction)) 1554 pos[i].y_offset += pos[j].y_offset; 1555 else 1556 pos[i].x_offset += pos[j].x_offset; 1557 } 1558 1559 static void 1560 fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) 1561 { 1562 if (likely (!(pos[i].attach_lookback()))) 1563 return; 1564 1565 unsigned int j = i - pos[i].attach_lookback(); 1566 1567 pos[i].x_offset += pos[j].x_offset; 1568 pos[i].y_offset += pos[j].y_offset; 1569 1570 if (HB_DIRECTION_IS_FORWARD (direction)) 1571 for (unsigned int k = j; k < i; k++) { 1572 pos[i].x_offset -= pos[k].x_advance; 1573 pos[i].y_offset -= pos[k].y_advance; 1574 } 1575 else 1576 for (unsigned int k = j + 1; k < i + 1; k++) { 1577 pos[i].x_offset += pos[k].x_advance; 1578 pos[i].y_offset += pos[k].y_advance; 1579 } 1580 } 1581 1582 void 1583 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) 1584 { 1585 buffer->clear_positions (); 1586 1587 unsigned int count = buffer->len; 1588 for (unsigned int i = 0; i < count; i++) 1589 buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0; 1590 } 1591 1592 void 1593 GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) 1594 { 1595 _hb_buffer_assert_gsubgpos_vars (buffer); 1596 1597 unsigned int len; 1598 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len); 1599 hb_direction_t direction = buffer->props.direction; 1600 1601 /* Handle cursive connections */ 1602 for (unsigned int i = 0; i < len; i++) 1603 fix_cursive_minor_offset (pos, i, direction); 1604 1605 /* Handle attachments */ 1606 for (unsigned int i = 0; i < len; i++) 1607 fix_mark_attachment (pos, i, direction); 1608 } 1609 1610 1611 /* Out-of-class implementation for methods recursing */ 1612 1613 template <typename context_t> 1614 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) 1615 { 1616 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); 1617 const PosLookup &l = gpos.get_lookup (lookup_index); 1618 return l.dispatch (c); 1619 } 1620 1621 /*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) 1622 { 1623 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); 1624 const PosLookup &l = gpos.get_lookup (lookup_index); 1625 unsigned int saved_lookup_props = c->lookup_props; 1626 unsigned int saved_lookup_index = c->lookup_index; 1627 c->set_lookup_index (lookup_index); 1628 c->set_lookup_props (l.get_props ()); 1629 bool ret = l.dispatch (c); 1630 c->set_lookup_index (saved_lookup_index); 1631 c->set_lookup_props (saved_lookup_props); 1632 return ret; 1633 } 1634 1635 1636 #undef attach_lookback 1637 #undef cursive_chain 1638 1639 1640 } /* namespace OT */ 1641 1642 1643 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */