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 UINT16 Value; 55 56 typedef Value ValueRecord[VAR]; 57 58 struct ValueFormat : UINT16 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 INT16 xPlacement; /* Horizontal adjustment for 78 * placement--in design units */ 79 INT16 yPlacement; /* Vertical adjustment for 80 * placement--in design units */ 81 INT16 xAdvance; /* Horizontal adjustment for 82 * advance--in design units (only used 83 * for horizontal writing) */ 84 INT16 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 INT16& get_short (const Value* value) 182 { return *CastP<INT16> (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 UINT16 format; /* Format identifier--format = 1 */ 251 INT16 xCoordinate; /* Horizontal value--in design units */ 252 INT16 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 UINT16 format; /* Format identifier--format = 2 */ 282 INT16 xCoordinate; /* Horizontal value--in design units */ 283 INT16 yCoordinate; /* Vertical value--in design units */ 284 UINT16 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 UINT16 format; /* Format identifier--format = 3 */ 312 INT16 xCoordinate; /* Horizontal value--in design units */ 313 INT16 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 UINT16 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 UINT16 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 UINT16 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 buffer->unsafe_to_break (glyph_pos, buffer->idx); 436 mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y); 437 glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y); 438 439 hb_glyph_position_t &o = buffer->cur_pos(); 440 o.x_offset = base_x - mark_x; 441 o.y_offset = base_y - mark_y; 442 o.attach_type() = ATTACH_TYPE_MARK; 443 o.attach_chain() = (int) glyph_pos - (int) buffer->idx; 444 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; 445 446 buffer->idx++; 447 return_trace (true); 448 } 449 450 inline bool sanitize (hb_sanitize_context_t *c) const 451 { 452 TRACE_SANITIZE (this); 453 return_trace (ArrayOf<MarkRecord>::sanitize (c, this)); 454 } 455 }; 456 457 458 /* Lookups */ 459 460 struct SinglePosFormat1 461 { 462 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 463 { 464 TRACE_COLLECT_GLYPHS (this); 465 if (unlikely (!(this+coverage).add_coverage (c->input))) return; 466 } 467 468 inline const Coverage &get_coverage (void) const 469 { 470 return this+coverage; 471 } 472 473 inline bool apply (hb_apply_context_t *c) const 474 { 475 TRACE_APPLY (this); 476 hb_buffer_t *buffer = c->buffer; 477 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 478 if (likely (index == NOT_COVERED)) return_trace (false); 479 480 valueFormat.apply_value (c, this, values, buffer->cur_pos()); 481 482 buffer->idx++; 483 return_trace (true); 484 } 485 486 inline bool sanitize (hb_sanitize_context_t *c) const 487 { 488 TRACE_SANITIZE (this); 489 return_trace (c->check_struct (this) && 490 coverage.sanitize (c, this) && 491 valueFormat.sanitize_value (c, this, values)); 492 } 493 494 protected: 495 UINT16 format; /* Format identifier--format = 1 */ 496 OffsetTo<Coverage> 497 coverage; /* Offset to Coverage table--from 498 * beginning of subtable */ 499 ValueFormat valueFormat; /* Defines the types of data in the 500 * ValueRecord */ 501 ValueRecord values; /* Defines positioning 502 * value(s)--applied to all glyphs in 503 * the Coverage table */ 504 public: 505 DEFINE_SIZE_ARRAY (6, values); 506 }; 507 508 struct SinglePosFormat2 509 { 510 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 511 { 512 TRACE_COLLECT_GLYPHS (this); 513 if (unlikely (!(this+coverage).add_coverage (c->input))) return; 514 } 515 516 inline const Coverage &get_coverage (void) const 517 { 518 return this+coverage; 519 } 520 521 inline bool apply (hb_apply_context_t *c) const 522 { 523 TRACE_APPLY (this); 524 hb_buffer_t *buffer = c->buffer; 525 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 526 if (likely (index == NOT_COVERED)) return_trace (false); 527 528 if (likely (index >= valueCount)) return_trace (false); 529 530 valueFormat.apply_value (c, this, 531 &values[index * valueFormat.get_len ()], 532 buffer->cur_pos()); 533 534 buffer->idx++; 535 return_trace (true); 536 } 537 538 inline bool sanitize (hb_sanitize_context_t *c) const 539 { 540 TRACE_SANITIZE (this); 541 return_trace (c->check_struct (this) && 542 coverage.sanitize (c, this) && 543 valueFormat.sanitize_values (c, this, values, valueCount)); 544 } 545 546 protected: 547 UINT16 format; /* Format identifier--format = 2 */ 548 OffsetTo<Coverage> 549 coverage; /* Offset to Coverage table--from 550 * beginning of subtable */ 551 ValueFormat valueFormat; /* Defines the types of data in the 552 * ValueRecord */ 553 UINT16 valueCount; /* Number of ValueRecords */ 554 ValueRecord values; /* Array of ValueRecords--positioning 555 * values applied to glyphs */ 556 public: 557 DEFINE_SIZE_ARRAY (8, values); 558 }; 559 560 struct SinglePos 561 { 562 template <typename context_t> 563 inline typename context_t::return_t dispatch (context_t *c) const 564 { 565 TRACE_DISPATCH (this, u.format); 566 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 567 switch (u.format) { 568 case 1: return_trace (c->dispatch (u.format1)); 569 case 2: return_trace (c->dispatch (u.format2)); 570 default:return_trace (c->default_return_value ()); 571 } 572 } 573 574 protected: 575 union { 576 UINT16 format; /* Format identifier */ 577 SinglePosFormat1 format1; 578 SinglePosFormat2 format2; 579 } u; 580 }; 581 582 583 struct PairValueRecord 584 { 585 friend struct PairSet; 586 587 protected: 588 GlyphID secondGlyph; /* GlyphID of second glyph in the 589 * pair--first glyph is listed in the 590 * Coverage table */ 591 ValueRecord values; /* Positioning data for the first glyph 592 * followed by for second glyph */ 593 public: 594 DEFINE_SIZE_ARRAY (2, values); 595 }; 596 597 struct PairSet 598 { 599 friend struct PairPosFormat1; 600 601 inline void collect_glyphs (hb_collect_glyphs_context_t *c, 602 const ValueFormat *valueFormats) const 603 { 604 TRACE_COLLECT_GLYPHS (this); 605 unsigned int len1 = valueFormats[0].get_len (); 606 unsigned int len2 = valueFormats[1].get_len (); 607 unsigned int record_size = UINT16::static_size * (1 + len1 + len2); 608 609 const PairValueRecord *record = CastP<PairValueRecord> (arrayZ); 610 c->input->add_array (&record->secondGlyph, len, record_size); 611 } 612 613 inline bool apply (hb_apply_context_t *c, 614 const ValueFormat *valueFormats, 615 unsigned int pos) const 616 { 617 TRACE_APPLY (this); 618 hb_buffer_t *buffer = c->buffer; 619 unsigned int len1 = valueFormats[0].get_len (); 620 unsigned int len2 = valueFormats[1].get_len (); 621 unsigned int record_size = UINT16::static_size * (1 + len1 + len2); 622 623 const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ); 624 unsigned int count = len; 625 626 /* Hand-coded bsearch. */ 627 if (unlikely (!count)) 628 return_trace (false); 629 hb_codepoint_t x = buffer->info[pos].codepoint; 630 int min = 0, max = (int) count - 1; 631 while (min <= max) 632 { 633 int mid = (min + max) / 2; 634 const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid); 635 hb_codepoint_t mid_x = record->secondGlyph; 636 if (x < mid_x) 637 max = mid - 1; 638 else if (x > mid_x) 639 min = mid + 1; 640 else 641 { 642 buffer->unsafe_to_break (buffer->idx, pos + 1); 643 valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); 644 valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); 645 if (len2) 646 pos++; 647 buffer->idx = pos; 648 return_trace (true); 649 } 650 } 651 652 return_trace (false); 653 } 654 655 struct sanitize_closure_t { 656 const void *base; 657 const ValueFormat *valueFormats; 658 unsigned int len1; /* valueFormats[0].get_len() */ 659 unsigned int stride; /* 1 + len1 + len2 */ 660 }; 661 662 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const 663 { 664 TRACE_SANITIZE (this); 665 if (!(c->check_struct (this) 666 && c->check_array (arrayZ, UINT16::static_size * closure->stride, len))) return_trace (false); 667 668 unsigned int count = len; 669 const PairValueRecord *record = CastP<PairValueRecord> (arrayZ); 670 return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) && 671 closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride)); 672 } 673 674 protected: 675 UINT16 len; /* Number of PairValueRecords */ 676 UINT16 arrayZ[VAR]; /* Array of PairValueRecords--ordered 677 * by GlyphID of the second glyph */ 678 public: 679 DEFINE_SIZE_ARRAY (2, arrayZ); 680 }; 681 682 struct PairPosFormat1 683 { 684 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 685 { 686 TRACE_COLLECT_GLYPHS (this); 687 if (unlikely (!(this+coverage).add_coverage (c->input))) return; 688 unsigned int count = pairSet.len; 689 for (unsigned int i = 0; i < count; i++) 690 (this+pairSet[i]).collect_glyphs (c, valueFormat); 691 } 692 693 inline const Coverage &get_coverage (void) const 694 { 695 return this+coverage; 696 } 697 698 inline bool apply (hb_apply_context_t *c) const 699 { 700 TRACE_APPLY (this); 701 hb_buffer_t *buffer = c->buffer; 702 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 703 if (likely (index == NOT_COVERED)) return_trace (false); 704 705 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 706 skippy_iter.reset (buffer->idx, 1); 707 if (!skippy_iter.next ()) return_trace (false); 708 709 return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); 710 } 711 712 inline bool sanitize (hb_sanitize_context_t *c) const 713 { 714 TRACE_SANITIZE (this); 715 716 if (!c->check_struct (this)) return_trace (false); 717 718 unsigned int len1 = valueFormat[0].get_len (); 719 unsigned int len2 = valueFormat[1].get_len (); 720 PairSet::sanitize_closure_t closure = { 721 this, 722 valueFormat, 723 len1, 724 1 + len1 + len2 725 }; 726 727 return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); 728 } 729 730 protected: 731 UINT16 format; /* Format identifier--format = 1 */ 732 OffsetTo<Coverage> 733 coverage; /* Offset to Coverage table--from 734 * beginning of subtable */ 735 ValueFormat valueFormat[2]; /* [0] Defines the types of data in 736 * ValueRecord1--for the first glyph 737 * in the pair--may be zero (0) */ 738 /* [1] Defines the types of data in 739 * ValueRecord2--for the second glyph 740 * in the pair--may be zero (0) */ 741 OffsetArrayOf<PairSet> 742 pairSet; /* Array of PairSet tables 743 * ordered by Coverage Index */ 744 public: 745 DEFINE_SIZE_ARRAY (10, pairSet); 746 }; 747 748 struct PairPosFormat2 749 { 750 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 751 { 752 TRACE_COLLECT_GLYPHS (this); 753 if (unlikely (!(this+coverage).add_coverage (c->input))) return; 754 if (unlikely (!(this+classDef2).add_coverage (c->input))) return; 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 buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); 782 const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; 783 valueFormat1.apply_value (c, this, v, buffer->cur_pos()); 784 valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); 785 786 buffer->idx = skippy_iter.idx; 787 if (len2) 788 buffer->idx++; 789 790 return_trace (true); 791 } 792 793 inline bool sanitize (hb_sanitize_context_t *c) const 794 { 795 TRACE_SANITIZE (this); 796 if (!(c->check_struct (this) 797 && coverage.sanitize (c, this) 798 && classDef1.sanitize (c, this) 799 && classDef2.sanitize (c, this))) return_trace (false); 800 801 unsigned int len1 = valueFormat1.get_len (); 802 unsigned int len2 = valueFormat2.get_len (); 803 unsigned int stride = len1 + len2; 804 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); 805 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; 806 return_trace (c->check_array (values, record_size, count) && 807 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && 808 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); 809 } 810 811 protected: 812 UINT16 format; /* Format identifier--format = 2 */ 813 OffsetTo<Coverage> 814 coverage; /* Offset to Coverage table--from 815 * beginning of subtable */ 816 ValueFormat valueFormat1; /* ValueRecord definition--for the 817 * first glyph of the pair--may be zero 818 * (0) */ 819 ValueFormat valueFormat2; /* ValueRecord definition--for the 820 * second glyph of the pair--may be 821 * zero (0) */ 822 OffsetTo<ClassDef> 823 classDef1; /* Offset to ClassDef table--from 824 * beginning of PairPos subtable--for 825 * the first glyph of the pair */ 826 OffsetTo<ClassDef> 827 classDef2; /* Offset to ClassDef table--from 828 * beginning of PairPos subtable--for 829 * the second glyph of the pair */ 830 UINT16 class1Count; /* Number of classes in ClassDef1 831 * table--includes Class0 */ 832 UINT16 class2Count; /* Number of classes in ClassDef2 833 * table--includes Class0 */ 834 ValueRecord values; /* Matrix of value pairs: 835 * class1-major, class2-minor, 836 * Each entry has value1 and value2 */ 837 public: 838 DEFINE_SIZE_ARRAY (16, values); 839 }; 840 841 struct PairPos 842 { 843 template <typename context_t> 844 inline typename context_t::return_t dispatch (context_t *c) const 845 { 846 TRACE_DISPATCH (this, u.format); 847 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 848 switch (u.format) { 849 case 1: return_trace (c->dispatch (u.format1)); 850 case 2: return_trace (c->dispatch (u.format2)); 851 default:return_trace (c->default_return_value ()); 852 } 853 } 854 855 protected: 856 union { 857 UINT16 format; /* Format identifier */ 858 PairPosFormat1 format1; 859 PairPosFormat2 format2; 860 } u; 861 }; 862 863 864 struct EntryExitRecord 865 { 866 friend struct CursivePosFormat1; 867 868 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 869 { 870 TRACE_SANITIZE (this); 871 return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); 872 } 873 874 protected: 875 OffsetTo<Anchor> 876 entryAnchor; /* Offset to EntryAnchor table--from 877 * beginning of CursivePos 878 * subtable--may be NULL */ 879 OffsetTo<Anchor> 880 exitAnchor; /* Offset to ExitAnchor table--from 881 * beginning of CursivePos 882 * subtable--may be NULL */ 883 public: 884 DEFINE_SIZE_STATIC (4); 885 }; 886 887 static void 888 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent); 889 890 struct CursivePosFormat1 891 { 892 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 893 { 894 TRACE_COLLECT_GLYPHS (this); 895 if (unlikely (!(this+coverage).add_coverage (c->input))) return; 896 } 897 898 inline const Coverage &get_coverage (void) const 899 { 900 return this+coverage; 901 } 902 903 inline bool apply (hb_apply_context_t *c) const 904 { 905 TRACE_APPLY (this); 906 hb_buffer_t *buffer = c->buffer; 907 908 const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; 909 if (!this_record.exitAnchor) return_trace (false); 910 911 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 912 skippy_iter.reset (buffer->idx, 1); 913 if (!skippy_iter.next ()) return_trace (false); 914 915 const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; 916 if (!next_record.entryAnchor) return_trace (false); 917 918 unsigned int i = buffer->idx; 919 unsigned int j = skippy_iter.idx; 920 921 buffer->unsafe_to_break (i, j); 922 hb_position_t entry_x, entry_y, exit_x, exit_y; 923 (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); 924 (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y); 925 926 hb_glyph_position_t *pos = buffer->pos; 927 928 hb_position_t d; 929 /* Main-direction adjustment */ 930 switch (c->direction) { 931 case HB_DIRECTION_LTR: 932 pos[i].x_advance = exit_x + pos[i].x_offset; 933 934 d = entry_x + pos[j].x_offset; 935 pos[j].x_advance -= d; 936 pos[j].x_offset -= d; 937 break; 938 case HB_DIRECTION_RTL: 939 d = exit_x + pos[i].x_offset; 940 pos[i].x_advance -= d; 941 pos[i].x_offset -= d; 942 943 pos[j].x_advance = entry_x + pos[j].x_offset; 944 break; 945 case HB_DIRECTION_TTB: 946 pos[i].y_advance = exit_y + pos[i].y_offset; 947 948 d = entry_y + pos[j].y_offset; 949 pos[j].y_advance -= d; 950 pos[j].y_offset -= d; 951 break; 952 case HB_DIRECTION_BTT: 953 d = exit_y + pos[i].y_offset; 954 pos[i].y_advance -= d; 955 pos[i].y_offset -= d; 956 957 pos[j].y_advance = entry_y; 958 break; 959 case HB_DIRECTION_INVALID: 960 default: 961 break; 962 } 963 964 /* Cross-direction adjustment */ 965 966 /* We attach child to parent (think graph theory and rooted trees whereas 967 * the root stays on baseline and each node aligns itself against its 968 * parent. 969 * 970 * Optimize things for the case of RightToLeft, as that's most common in 971 * Arabinc. */ 972 unsigned int child = i; 973 unsigned int parent = j; 974 hb_position_t x_offset = entry_x - exit_x; 975 hb_position_t y_offset = entry_y - exit_y; 976 if (!(c->lookup_props & LookupFlag::RightToLeft)) 977 { 978 unsigned int k = child; 979 child = parent; 980 parent = k; 981 x_offset = -x_offset; 982 y_offset = -y_offset; 983 } 984 985 /* If child was already connected to someone else, walk through its old 986 * chain and reverse the link direction, such that the whole tree of its 987 * previous connection now attaches to new parent. Watch out for case 988 * where new parent is on the path from old chain... 989 */ 990 reverse_cursive_minor_offset (pos, child, c->direction, parent); 991 992 pos[child].attach_type() = ATTACH_TYPE_CURSIVE; 993 pos[child].attach_chain() = (int) parent - (int) child; 994 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; 995 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) 996 pos[child].y_offset = y_offset; 997 else 998 pos[child].x_offset = x_offset; 999 1000 buffer->idx = j; 1001 return_trace (true); 1002 } 1003 1004 inline bool sanitize (hb_sanitize_context_t *c) const 1005 { 1006 TRACE_SANITIZE (this); 1007 return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); 1008 } 1009 1010 protected: 1011 UINT16 format; /* Format identifier--format = 1 */ 1012 OffsetTo<Coverage> 1013 coverage; /* Offset to Coverage table--from 1014 * beginning of subtable */ 1015 ArrayOf<EntryExitRecord> 1016 entryExitRecord; /* Array of EntryExit records--in 1017 * Coverage Index order */ 1018 public: 1019 DEFINE_SIZE_ARRAY (6, entryExitRecord); 1020 }; 1021 1022 struct CursivePos 1023 { 1024 template <typename context_t> 1025 inline typename context_t::return_t dispatch (context_t *c) const 1026 { 1027 TRACE_DISPATCH (this, u.format); 1028 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1029 switch (u.format) { 1030 case 1: return_trace (c->dispatch (u.format1)); 1031 default:return_trace (c->default_return_value ()); 1032 } 1033 } 1034 1035 protected: 1036 union { 1037 UINT16 format; /* Format identifier */ 1038 CursivePosFormat1 format1; 1039 } u; 1040 }; 1041 1042 1043 typedef AnchorMatrix BaseArray; /* base-major-- 1044 * in order of BaseCoverage Index--, 1045 * mark-minor-- 1046 * ordered by class--zero-based. */ 1047 1048 struct MarkBasePosFormat1 1049 { 1050 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1051 { 1052 TRACE_COLLECT_GLYPHS (this); 1053 if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; 1054 if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return; 1055 } 1056 1057 inline const Coverage &get_coverage (void) const 1058 { 1059 return this+markCoverage; 1060 } 1061 1062 inline bool apply (hb_apply_context_t *c) const 1063 { 1064 TRACE_APPLY (this); 1065 hb_buffer_t *buffer = c->buffer; 1066 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); 1067 if (likely (mark_index == NOT_COVERED)) return_trace (false); 1068 1069 /* Now we search backwards for a non-mark glyph */ 1070 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 1071 skippy_iter.reset (buffer->idx, 1); 1072 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); 1073 do { 1074 if (!skippy_iter.prev ()) return_trace (false); 1075 /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */ 1076 if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) || 1077 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) 1078 break; 1079 skippy_iter.reject (); 1080 } while (1); 1081 1082 /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ 1083 //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } 1084 1085 unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); 1086 if (base_index == NOT_COVERED) return_trace (false); 1087 1088 return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); 1089 } 1090 1091 inline bool sanitize (hb_sanitize_context_t *c) const 1092 { 1093 TRACE_SANITIZE (this); 1094 return_trace (c->check_struct (this) && 1095 markCoverage.sanitize (c, this) && 1096 baseCoverage.sanitize (c, this) && 1097 markArray.sanitize (c, this) && 1098 baseArray.sanitize (c, this, (unsigned int) classCount)); 1099 } 1100 1101 protected: 1102 UINT16 format; /* Format identifier--format = 1 */ 1103 OffsetTo<Coverage> 1104 markCoverage; /* Offset to MarkCoverage table--from 1105 * beginning of MarkBasePos subtable */ 1106 OffsetTo<Coverage> 1107 baseCoverage; /* Offset to BaseCoverage table--from 1108 * beginning of MarkBasePos subtable */ 1109 UINT16 classCount; /* Number of classes defined for marks */ 1110 OffsetTo<MarkArray> 1111 markArray; /* Offset to MarkArray table--from 1112 * beginning of MarkBasePos subtable */ 1113 OffsetTo<BaseArray> 1114 baseArray; /* Offset to BaseArray table--from 1115 * beginning of MarkBasePos subtable */ 1116 public: 1117 DEFINE_SIZE_STATIC (12); 1118 }; 1119 1120 struct MarkBasePos 1121 { 1122 template <typename context_t> 1123 inline typename context_t::return_t dispatch (context_t *c) const 1124 { 1125 TRACE_DISPATCH (this, u.format); 1126 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1127 switch (u.format) { 1128 case 1: return_trace (c->dispatch (u.format1)); 1129 default:return_trace (c->default_return_value ()); 1130 } 1131 } 1132 1133 protected: 1134 union { 1135 UINT16 format; /* Format identifier */ 1136 MarkBasePosFormat1 format1; 1137 } u; 1138 }; 1139 1140 1141 typedef AnchorMatrix LigatureAttach; /* component-major-- 1142 * in order of writing direction--, 1143 * mark-minor-- 1144 * ordered by class--zero-based. */ 1145 1146 typedef OffsetListOf<LigatureAttach> LigatureArray; 1147 /* Array of LigatureAttach 1148 * tables ordered by 1149 * LigatureCoverage Index */ 1150 1151 struct MarkLigPosFormat1 1152 { 1153 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1154 { 1155 TRACE_COLLECT_GLYPHS (this); 1156 if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; 1157 if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return; 1158 } 1159 1160 inline const Coverage &get_coverage (void) const 1161 { 1162 return this+markCoverage; 1163 } 1164 1165 inline bool apply (hb_apply_context_t *c) const 1166 { 1167 TRACE_APPLY (this); 1168 hb_buffer_t *buffer = c->buffer; 1169 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); 1170 if (likely (mark_index == NOT_COVERED)) return_trace (false); 1171 1172 /* Now we search backwards for a non-mark glyph */ 1173 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 1174 skippy_iter.reset (buffer->idx, 1); 1175 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); 1176 if (!skippy_iter.prev ()) return_trace (false); 1177 1178 /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ 1179 //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); } 1180 1181 unsigned int j = skippy_iter.idx; 1182 unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); 1183 if (lig_index == NOT_COVERED) return_trace (false); 1184 1185 const LigatureArray& lig_array = this+ligatureArray; 1186 const LigatureAttach& lig_attach = lig_array[lig_index]; 1187 1188 /* Find component to attach to */ 1189 unsigned int comp_count = lig_attach.rows; 1190 if (unlikely (!comp_count)) return_trace (false); 1191 1192 /* We must now check whether the ligature ID of the current mark glyph 1193 * is identical to the ligature ID of the found ligature. If yes, we 1194 * can directly use the component index. If not, we attach the mark 1195 * glyph to the last component of the ligature. */ 1196 unsigned int comp_index; 1197 unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); 1198 unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 1199 unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); 1200 if (lig_id && lig_id == mark_id && mark_comp > 0) 1201 comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1; 1202 else 1203 comp_index = comp_count - 1; 1204 1205 return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); 1206 } 1207 1208 inline bool sanitize (hb_sanitize_context_t *c) const 1209 { 1210 TRACE_SANITIZE (this); 1211 return_trace (c->check_struct (this) && 1212 markCoverage.sanitize (c, this) && 1213 ligatureCoverage.sanitize (c, this) && 1214 markArray.sanitize (c, this) && 1215 ligatureArray.sanitize (c, this, (unsigned int) classCount)); 1216 } 1217 1218 protected: 1219 UINT16 format; /* Format identifier--format = 1 */ 1220 OffsetTo<Coverage> 1221 markCoverage; /* Offset to Mark Coverage table--from 1222 * beginning of MarkLigPos subtable */ 1223 OffsetTo<Coverage> 1224 ligatureCoverage; /* Offset to Ligature Coverage 1225 * table--from beginning of MarkLigPos 1226 * subtable */ 1227 UINT16 classCount; /* Number of defined mark classes */ 1228 OffsetTo<MarkArray> 1229 markArray; /* Offset to MarkArray table--from 1230 * beginning of MarkLigPos subtable */ 1231 OffsetTo<LigatureArray> 1232 ligatureArray; /* Offset to LigatureArray table--from 1233 * beginning of MarkLigPos subtable */ 1234 public: 1235 DEFINE_SIZE_STATIC (12); 1236 }; 1237 1238 struct MarkLigPos 1239 { 1240 template <typename context_t> 1241 inline typename context_t::return_t dispatch (context_t *c) const 1242 { 1243 TRACE_DISPATCH (this, u.format); 1244 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1245 switch (u.format) { 1246 case 1: return_trace (c->dispatch (u.format1)); 1247 default:return_trace (c->default_return_value ()); 1248 } 1249 } 1250 1251 protected: 1252 union { 1253 UINT16 format; /* Format identifier */ 1254 MarkLigPosFormat1 format1; 1255 } u; 1256 }; 1257 1258 1259 typedef AnchorMatrix Mark2Array; /* mark2-major-- 1260 * in order of Mark2Coverage Index--, 1261 * mark1-minor-- 1262 * ordered by class--zero-based. */ 1263 1264 struct MarkMarkPosFormat1 1265 { 1266 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1267 { 1268 TRACE_COLLECT_GLYPHS (this); 1269 if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return; 1270 if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return; 1271 } 1272 1273 inline const Coverage &get_coverage (void) const 1274 { 1275 return this+mark1Coverage; 1276 } 1277 1278 inline bool apply (hb_apply_context_t *c) const 1279 { 1280 TRACE_APPLY (this); 1281 hb_buffer_t *buffer = c->buffer; 1282 unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint); 1283 if (likely (mark1_index == NOT_COVERED)) return_trace (false); 1284 1285 /* now we search backwards for a suitable mark glyph until a non-mark glyph */ 1286 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 1287 skippy_iter.reset (buffer->idx, 1); 1288 skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); 1289 if (!skippy_iter.prev ()) return_trace (false); 1290 1291 if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); } 1292 1293 unsigned int j = skippy_iter.idx; 1294 1295 unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur()); 1296 unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]); 1297 unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur()); 1298 unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]); 1299 1300 if (likely (id1 == id2)) { 1301 if (id1 == 0) /* Marks belonging to the same base. */ 1302 goto good; 1303 else if (comp1 == comp2) /* Marks belonging to the same ligature component. */ 1304 goto good; 1305 } else { 1306 /* If ligature ids don't match, it may be the case that one of the marks 1307 * itself is a ligature. In which case match. */ 1308 if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2)) 1309 goto good; 1310 } 1311 1312 /* Didn't match. */ 1313 return_trace (false); 1314 1315 good: 1316 unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); 1317 if (mark2_index == NOT_COVERED) return_trace (false); 1318 1319 return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); 1320 } 1321 1322 inline bool sanitize (hb_sanitize_context_t *c) const 1323 { 1324 TRACE_SANITIZE (this); 1325 return_trace (c->check_struct (this) && 1326 mark1Coverage.sanitize (c, this) && 1327 mark2Coverage.sanitize (c, this) && 1328 mark1Array.sanitize (c, this) && 1329 mark2Array.sanitize (c, this, (unsigned int) classCount)); 1330 } 1331 1332 protected: 1333 UINT16 format; /* Format identifier--format = 1 */ 1334 OffsetTo<Coverage> 1335 mark1Coverage; /* Offset to Combining Mark1 Coverage 1336 * table--from beginning of MarkMarkPos 1337 * subtable */ 1338 OffsetTo<Coverage> 1339 mark2Coverage; /* Offset to Combining Mark2 Coverage 1340 * table--from beginning of MarkMarkPos 1341 * subtable */ 1342 UINT16 classCount; /* Number of defined mark classes */ 1343 OffsetTo<MarkArray> 1344 mark1Array; /* Offset to Mark1Array table--from 1345 * beginning of MarkMarkPos subtable */ 1346 OffsetTo<Mark2Array> 1347 mark2Array; /* Offset to Mark2Array table--from 1348 * beginning of MarkMarkPos subtable */ 1349 public: 1350 DEFINE_SIZE_STATIC (12); 1351 }; 1352 1353 struct MarkMarkPos 1354 { 1355 template <typename context_t> 1356 inline typename context_t::return_t dispatch (context_t *c) const 1357 { 1358 TRACE_DISPATCH (this, u.format); 1359 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1360 switch (u.format) { 1361 case 1: return_trace (c->dispatch (u.format1)); 1362 default:return_trace (c->default_return_value ()); 1363 } 1364 } 1365 1366 protected: 1367 union { 1368 UINT16 format; /* Format identifier */ 1369 MarkMarkPosFormat1 format1; 1370 } u; 1371 }; 1372 1373 1374 struct ContextPos : Context {}; 1375 1376 struct ChainContextPos : ChainContext {}; 1377 1378 struct ExtensionPos : Extension<ExtensionPos> 1379 { 1380 typedef struct PosLookupSubTable LookupSubTable; 1381 }; 1382 1383 1384 1385 /* 1386 * PosLookup 1387 */ 1388 1389 1390 struct PosLookupSubTable 1391 { 1392 friend struct PosLookup; 1393 1394 enum Type { 1395 Single = 1, 1396 Pair = 2, 1397 Cursive = 3, 1398 MarkBase = 4, 1399 MarkLig = 5, 1400 MarkMark = 6, 1401 Context = 7, 1402 ChainContext = 8, 1403 Extension = 9 1404 }; 1405 1406 template <typename context_t> 1407 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const 1408 { 1409 TRACE_DISPATCH (this, lookup_type); 1410 if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ()); 1411 switch (lookup_type) { 1412 case Single: return_trace (u.single.dispatch (c)); 1413 case Pair: return_trace (u.pair.dispatch (c)); 1414 case Cursive: return_trace (u.cursive.dispatch (c)); 1415 case MarkBase: return_trace (u.markBase.dispatch (c)); 1416 case MarkLig: return_trace (u.markLig.dispatch (c)); 1417 case MarkMark: return_trace (u.markMark.dispatch (c)); 1418 case Context: return_trace (u.context.dispatch (c)); 1419 case ChainContext: return_trace (u.chainContext.dispatch (c)); 1420 case Extension: return_trace (u.extension.dispatch (c)); 1421 default: return_trace (c->default_return_value ()); 1422 } 1423 } 1424 1425 protected: 1426 union { 1427 UINT16 sub_format; 1428 SinglePos single; 1429 PairPos pair; 1430 CursivePos cursive; 1431 MarkBasePos markBase; 1432 MarkLigPos markLig; 1433 MarkMarkPos markMark; 1434 ContextPos context; 1435 ChainContextPos chainContext; 1436 ExtensionPos extension; 1437 } u; 1438 public: 1439 DEFINE_SIZE_UNION (2, sub_format); 1440 }; 1441 1442 1443 struct PosLookup : Lookup 1444 { 1445 inline const PosLookupSubTable& get_subtable (unsigned int i) const 1446 { return Lookup::get_subtable<PosLookupSubTable> (i); } 1447 1448 inline bool is_reverse (void) const 1449 { 1450 return false; 1451 } 1452 1453 inline bool apply (hb_apply_context_t *c) const 1454 { 1455 TRACE_APPLY (this); 1456 return_trace (dispatch (c)); 1457 } 1458 1459 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const 1460 { 1461 TRACE_COLLECT_GLYPHS (this); 1462 return_trace (dispatch (c)); 1463 } 1464 1465 template <typename set_t> 1466 inline void add_coverage (set_t *glyphs) const 1467 { 1468 hb_add_coverage_context_t<set_t> c (glyphs); 1469 dispatch (&c); 1470 } 1471 1472 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); 1473 1474 template <typename context_t> 1475 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); 1476 1477 template <typename context_t> 1478 inline typename context_t::return_t dispatch (context_t *c) const 1479 { return Lookup::dispatch<PosLookupSubTable> (c); } 1480 1481 inline bool sanitize (hb_sanitize_context_t *c) const 1482 { 1483 TRACE_SANITIZE (this); 1484 if (unlikely (!Lookup::sanitize (c))) return_trace (false); 1485 return_trace (dispatch (c)); 1486 } 1487 }; 1488 1489 typedef OffsetListOf<PosLookup> PosLookupList; 1490 1491 /* 1492 * GPOS -- The Glyph Positioning Table 1493 */ 1494 1495 struct GPOS : GSUBGPOS 1496 { 1497 static const hb_tag_t tableTag = HB_OT_TAG_GPOS; 1498 1499 inline const PosLookup& get_lookup (unsigned int i) const 1500 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } 1501 1502 static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); 1503 static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer); 1504 static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer); 1505 1506 inline bool sanitize (hb_sanitize_context_t *c) const 1507 { 1508 TRACE_SANITIZE (this); 1509 if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); 1510 const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList); 1511 return_trace (list.sanitize (c, this)); 1512 } 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 int chain = pos[i].attach_chain(), type = pos[i].attach_type(); 1520 if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE))) 1521 return; 1522 1523 pos[i].attach_chain() = 0; 1524 1525 unsigned int j = (int) i + chain; 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].attach_chain() = -chain; 1539 pos[j].attach_type() = type; 1540 } 1541 static void 1542 propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) 1543 { 1544 /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate 1545 * offset of glyph they are attached to. */ 1546 int chain = pos[i].attach_chain(), type = pos[i].attach_type(); 1547 if (likely (!chain)) 1548 return; 1549 1550 unsigned int j = (int) i + chain; 1551 1552 pos[i].attach_chain() = 0; 1553 1554 propagate_attachment_offsets (pos, j, direction); 1555 1556 assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE)); 1557 1558 if (type & ATTACH_TYPE_CURSIVE) 1559 { 1560 if (HB_DIRECTION_IS_HORIZONTAL (direction)) 1561 pos[i].y_offset += pos[j].y_offset; 1562 else 1563 pos[i].x_offset += pos[j].x_offset; 1564 } 1565 else /*if (type & ATTACH_TYPE_MARK)*/ 1566 { 1567 pos[i].x_offset += pos[j].x_offset; 1568 pos[i].y_offset += pos[j].y_offset; 1569 1570 assert (j < i); 1571 if (HB_DIRECTION_IS_FORWARD (direction)) 1572 for (unsigned int k = j; k < i; k++) { 1573 pos[i].x_offset -= pos[k].x_advance; 1574 pos[i].y_offset -= pos[k].y_advance; 1575 } 1576 else 1577 for (unsigned int k = j + 1; k < i + 1; k++) { 1578 pos[i].x_offset += pos[k].x_advance; 1579 pos[i].y_offset += pos[k].y_advance; 1580 } 1581 } 1582 } 1583 1584 void 1585 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) 1586 { 1587 unsigned int count = buffer->len; 1588 for (unsigned int i = 0; i < count; i++) 1589 buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0; 1590 } 1591 1592 void 1593 GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) 1594 { 1595 //_hb_buffer_assert_gsubgpos_vars (buffer); 1596 } 1597 1598 void 1599 GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) 1600 { 1601 _hb_buffer_assert_gsubgpos_vars (buffer); 1602 1603 unsigned int len; 1604 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len); 1605 hb_direction_t direction = buffer->props.direction; 1606 1607 /* Handle attachments */ 1608 if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT) 1609 for (unsigned int i = 0; i < len; i++) 1610 propagate_attachment_offsets (pos, i, direction); 1611 } 1612 1613 1614 /* Out-of-class implementation for methods recursing */ 1615 1616 template <typename context_t> 1617 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) 1618 { 1619 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); 1620 const PosLookup &l = gpos.get_lookup (lookup_index); 1621 return l.dispatch (c); 1622 } 1623 1624 /*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) 1625 { 1626 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); 1627 const PosLookup &l = gpos.get_lookup (lookup_index); 1628 unsigned int saved_lookup_props = c->lookup_props; 1629 unsigned int saved_lookup_index = c->lookup_index; 1630 c->set_lookup_index (lookup_index); 1631 c->set_lookup_props (l.get_props ()); 1632 bool ret = l.dispatch (c); 1633 c->set_lookup_index (saved_lookup_index); 1634 c->set_lookup_props (saved_lookup_props); 1635 return ret; 1636 } 1637 1638 1639 #undef attach_chain 1640 #undef attach_type 1641 1642 1643 } /* namespace OT */ 1644 1645 1646 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */ 1647