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