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