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