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