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