1 /* 2 * Copyright 2007,2008,2009,2010 Red Hat, Inc. 3 * Copyright 2010,2012 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_GSUBGPOS_HH 30 #define HB_OT_LAYOUT_GSUBGPOS_HH 31 32 #include "hb.hh" 33 #include "hb-buffer.hh" 34 #include "hb-map.hh" 35 #include "hb-set.hh" 36 #include "hb-ot-map.hh" 37 #include "hb-ot-layout-common.hh" 38 #include "hb-ot-layout-gdef-table.hh" 39 40 41 namespace OT { 42 43 44 struct hb_intersects_context_t : 45 hb_dispatch_context_t<hb_intersects_context_t, bool, 0> 46 { 47 const char *get_name () { return "INTERSECTS"; } 48 template <typename T> 49 return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); } 50 static return_t default_return_value () { return false; } 51 bool stop_sublookup_iteration (return_t r) const { return r; } 52 53 const hb_set_t *glyphs; 54 unsigned int debug_depth; 55 56 hb_intersects_context_t (const hb_set_t *glyphs_) : 57 glyphs (glyphs_), 58 debug_depth (0) {} 59 }; 60 61 struct hb_closure_context_t : 62 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE> 63 { 64 const char *get_name () { return "CLOSURE"; } 65 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); 66 template <typename T> 67 return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } 68 static return_t default_return_value () { return HB_VOID; } 69 void recurse (unsigned int lookup_index) 70 { 71 if (unlikely (nesting_level_left == 0 || !recurse_func)) 72 return; 73 74 nesting_level_left--; 75 recurse_func (this, lookup_index); 76 nesting_level_left++; 77 } 78 79 bool should_visit_lookup (unsigned int lookup_index) 80 { 81 if (is_lookup_done (lookup_index)) 82 return false; 83 done_lookups->set (lookup_index, glyphs->get_population ()); 84 return true; 85 } 86 87 bool is_lookup_done (unsigned int lookup_index) 88 { 89 /* Have we visited this lookup with the current set of glyphs? */ 90 return done_lookups->get (lookup_index) == glyphs->get_population (); 91 } 92 93 hb_face_t *face; 94 hb_set_t *glyphs; 95 hb_set_t out[1]; 96 recurse_func_t recurse_func; 97 unsigned int nesting_level_left; 98 unsigned int debug_depth; 99 100 hb_closure_context_t (hb_face_t *face_, 101 hb_set_t *glyphs_, 102 hb_map_t *done_lookups_, 103 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : 104 face (face_), 105 glyphs (glyphs_), 106 recurse_func (nullptr), 107 nesting_level_left (nesting_level_left_), 108 debug_depth (0), 109 done_lookups (done_lookups_) {} 110 111 ~hb_closure_context_t () { flush (); } 112 113 void set_recurse_func (recurse_func_t func) { recurse_func = func; } 114 115 void flush () 116 { 117 hb_set_union (glyphs, out); 118 hb_set_clear (out); 119 } 120 121 private: 122 hb_map_t *done_lookups; 123 }; 124 125 126 struct hb_would_apply_context_t : 127 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY> 128 { 129 const char *get_name () { return "WOULD_APPLY"; } 130 template <typename T> 131 return_t dispatch (const T &obj) { return obj.would_apply (this); } 132 static return_t default_return_value () { return false; } 133 bool stop_sublookup_iteration (return_t r) const { return r; } 134 135 hb_face_t *face; 136 const hb_codepoint_t *glyphs; 137 unsigned int len; 138 bool zero_context; 139 unsigned int debug_depth; 140 141 hb_would_apply_context_t (hb_face_t *face_, 142 const hb_codepoint_t *glyphs_, 143 unsigned int len_, 144 bool zero_context_) : 145 face (face_), 146 glyphs (glyphs_), 147 len (len_), 148 zero_context (zero_context_), 149 debug_depth (0) {} 150 }; 151 152 153 struct hb_collect_glyphs_context_t : 154 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS> 155 { 156 const char *get_name () { return "COLLECT_GLYPHS"; } 157 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); 158 template <typename T> 159 return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } 160 static return_t default_return_value () { return HB_VOID; } 161 void recurse (unsigned int lookup_index) 162 { 163 if (unlikely (nesting_level_left == 0 || !recurse_func)) 164 return; 165 166 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get 167 * past the previous check. For GSUB, we only want to collect the output 168 * glyphs in the recursion. If output is not requested, we can go home now. 169 * 170 * Note further, that the above is not exactly correct. A recursed lookup 171 * is allowed to match input that is not matched in the context, but that's 172 * not how most fonts are built. It's possible to relax that and recurse 173 * with all sets here if it proves to be an issue. 174 */ 175 176 if (output == hb_set_get_empty ()) 177 return; 178 179 /* Return if new lookup was recursed to before. */ 180 if (recursed_lookups->has (lookup_index)) 181 return; 182 183 hb_set_t *old_before = before; 184 hb_set_t *old_input = input; 185 hb_set_t *old_after = after; 186 before = input = after = hb_set_get_empty (); 187 188 nesting_level_left--; 189 recurse_func (this, lookup_index); 190 nesting_level_left++; 191 192 before = old_before; 193 input = old_input; 194 after = old_after; 195 196 recursed_lookups->add (lookup_index); 197 } 198 199 hb_face_t *face; 200 hb_set_t *before; 201 hb_set_t *input; 202 hb_set_t *after; 203 hb_set_t *output; 204 recurse_func_t recurse_func; 205 hb_set_t *recursed_lookups; 206 unsigned int nesting_level_left; 207 unsigned int debug_depth; 208 209 hb_collect_glyphs_context_t (hb_face_t *face_, 210 hb_set_t *glyphs_before, /* OUT. May be NULL */ 211 hb_set_t *glyphs_input, /* OUT. May be NULL */ 212 hb_set_t *glyphs_after, /* OUT. May be NULL */ 213 hb_set_t *glyphs_output, /* OUT. May be NULL */ 214 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : 215 face (face_), 216 before (glyphs_before ? glyphs_before : hb_set_get_empty ()), 217 input (glyphs_input ? glyphs_input : hb_set_get_empty ()), 218 after (glyphs_after ? glyphs_after : hb_set_get_empty ()), 219 output (glyphs_output ? glyphs_output : hb_set_get_empty ()), 220 recurse_func (nullptr), 221 recursed_lookups (hb_set_create ()), 222 nesting_level_left (nesting_level_left_), 223 debug_depth (0) {} 224 ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); } 225 226 void set_recurse_func (recurse_func_t func) { recurse_func = func; } 227 }; 228 229 230 231 template <typename set_t> 232 struct hb_add_coverage_context_t : 233 hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE> 234 { 235 const char *get_name () { return "GET_COVERAGE"; } 236 typedef const Coverage &return_t; 237 template <typename T> 238 return_t dispatch (const T &obj) { return obj.get_coverage (); } 239 static return_t default_return_value () { return Null(Coverage); } 240 bool stop_sublookup_iteration (return_t r) const 241 { 242 r.add_coverage (set); 243 return false; 244 } 245 246 hb_add_coverage_context_t (set_t *set_) : 247 set (set_), 248 debug_depth (0) {} 249 250 set_t *set; 251 unsigned int debug_depth; 252 }; 253 254 255 struct hb_ot_apply_context_t : 256 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY> 257 { 258 struct matcher_t 259 { 260 matcher_t () : 261 lookup_props (0), 262 ignore_zwnj (false), 263 ignore_zwj (false), 264 mask (-1), 265 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */ 266 syllable arg1(0), 267 #undef arg1 268 match_func (nullptr), 269 match_data (nullptr) {} 270 271 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data); 272 273 void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } 274 void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } 275 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } 276 void set_mask (hb_mask_t mask_) { mask = mask_; } 277 void set_syllable (uint8_t syllable_) { syllable = syllable_; } 278 void set_match_func (match_func_t match_func_, 279 const void *match_data_) 280 { match_func = match_func_; match_data = match_data_; } 281 282 enum may_match_t { 283 MATCH_NO, 284 MATCH_YES, 285 MATCH_MAYBE 286 }; 287 288 may_match_t may_match (const hb_glyph_info_t &info, 289 const HBUINT16 *glyph_data) const 290 { 291 if (!(info.mask & mask) || 292 (syllable && syllable != info.syllable ())) 293 return MATCH_NO; 294 295 if (match_func) 296 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO; 297 298 return MATCH_MAYBE; 299 } 300 301 enum may_skip_t { 302 SKIP_NO, 303 SKIP_YES, 304 SKIP_MAYBE 305 }; 306 307 may_skip_t may_skip (const hb_ot_apply_context_t *c, 308 const hb_glyph_info_t &info) const 309 { 310 if (!c->check_glyph_property (&info, lookup_props)) 311 return SKIP_YES; 312 313 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) && 314 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) && 315 (ignore_zwj || !_hb_glyph_info_is_zwj (&info)))) 316 return SKIP_MAYBE; 317 318 return SKIP_NO; 319 } 320 321 protected: 322 unsigned int lookup_props; 323 bool ignore_zwnj; 324 bool ignore_zwj; 325 hb_mask_t mask; 326 uint8_t syllable; 327 match_func_t match_func; 328 const void *match_data; 329 }; 330 331 struct skipping_iterator_t 332 { 333 void init (hb_ot_apply_context_t *c_, bool context_match = false) 334 { 335 c = c_; 336 match_glyph_data = nullptr; 337 matcher.set_match_func (nullptr, nullptr); 338 matcher.set_lookup_props (c->lookup_props); 339 /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */ 340 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj)); 341 /* Ignore ZWJ if we are matching context, or asked to. */ 342 matcher.set_ignore_zwj (context_match || c->auto_zwj); 343 matcher.set_mask (context_match ? -1 : c->lookup_mask); 344 } 345 void set_lookup_props (unsigned int lookup_props) 346 { 347 matcher.set_lookup_props (lookup_props); 348 } 349 void set_match_func (matcher_t::match_func_t match_func_, 350 const void *match_data_, 351 const HBUINT16 glyph_data[]) 352 { 353 matcher.set_match_func (match_func_, match_data_); 354 match_glyph_data = glyph_data; 355 } 356 357 void reset (unsigned int start_index_, 358 unsigned int num_items_) 359 { 360 idx = start_index_; 361 num_items = num_items_; 362 end = c->buffer->len; 363 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); 364 } 365 366 void reject () { num_items++; match_glyph_data--; } 367 368 matcher_t::may_skip_t 369 may_skip (const hb_glyph_info_t &info) const 370 { return matcher.may_skip (c, info); } 371 372 bool next () 373 { 374 assert (num_items > 0); 375 while (idx + num_items < end) 376 { 377 idx++; 378 const hb_glyph_info_t &info = c->buffer->info[idx]; 379 380 matcher_t::may_skip_t skip = matcher.may_skip (c, info); 381 if (unlikely (skip == matcher_t::SKIP_YES)) 382 continue; 383 384 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); 385 if (match == matcher_t::MATCH_YES || 386 (match == matcher_t::MATCH_MAYBE && 387 skip == matcher_t::SKIP_NO)) 388 { 389 num_items--; 390 match_glyph_data++; 391 return true; 392 } 393 394 if (skip == matcher_t::SKIP_NO) 395 return false; 396 } 397 return false; 398 } 399 bool prev () 400 { 401 assert (num_items > 0); 402 while (idx > num_items - 1) 403 { 404 idx--; 405 const hb_glyph_info_t &info = c->buffer->out_info[idx]; 406 407 matcher_t::may_skip_t skip = matcher.may_skip (c, info); 408 if (unlikely (skip == matcher_t::SKIP_YES)) 409 continue; 410 411 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); 412 if (match == matcher_t::MATCH_YES || 413 (match == matcher_t::MATCH_MAYBE && 414 skip == matcher_t::SKIP_NO)) 415 { 416 num_items--; 417 match_glyph_data++; 418 return true; 419 } 420 421 if (skip == matcher_t::SKIP_NO) 422 return false; 423 } 424 return false; 425 } 426 427 unsigned int idx; 428 protected: 429 hb_ot_apply_context_t *c; 430 matcher_t matcher; 431 const HBUINT16 *match_glyph_data; 432 433 unsigned int num_items; 434 unsigned int end; 435 }; 436 437 438 const char *get_name () { return "APPLY"; } 439 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index); 440 template <typename T> 441 return_t dispatch (const T &obj) { return obj.apply (this); } 442 static return_t default_return_value () { return false; } 443 bool stop_sublookup_iteration (return_t r) const { return r; } 444 return_t recurse (unsigned int sub_lookup_index) 445 { 446 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0)) 447 return default_return_value (); 448 449 nesting_level_left--; 450 bool ret = recurse_func (this, sub_lookup_index); 451 nesting_level_left++; 452 return ret; 453 } 454 455 skipping_iterator_t iter_input, iter_context; 456 457 hb_font_t *font; 458 hb_face_t *face; 459 hb_buffer_t *buffer; 460 recurse_func_t recurse_func; 461 const GDEF &gdef; 462 const VariationStore &var_store; 463 464 hb_direction_t direction; 465 hb_mask_t lookup_mask; 466 unsigned int table_index; /* GSUB/GPOS */ 467 unsigned int lookup_index; 468 unsigned int lookup_props; 469 unsigned int nesting_level_left; 470 unsigned int debug_depth; 471 472 bool has_glyph_classes; 473 bool auto_zwnj; 474 bool auto_zwj; 475 bool random; 476 477 uint32_t random_state; 478 479 480 hb_ot_apply_context_t (unsigned int table_index_, 481 hb_font_t *font_, 482 hb_buffer_t *buffer_) : 483 iter_input (), iter_context (), 484 font (font_), face (font->face), buffer (buffer_), 485 recurse_func (nullptr), 486 gdef (*face->table.GDEF->table), 487 var_store (gdef.get_var_store ()), 488 direction (buffer_->props.direction), 489 lookup_mask (1), 490 table_index (table_index_), 491 lookup_index ((unsigned int) -1), 492 lookup_props (0), 493 nesting_level_left (HB_MAX_NESTING_LEVEL), 494 debug_depth (0), 495 has_glyph_classes (gdef.has_glyph_classes ()), 496 auto_zwnj (true), 497 auto_zwj (true), 498 random (false), 499 random_state (1) { init_iters (); } 500 501 void init_iters () 502 { 503 iter_input.init (this, false); 504 iter_context.init (this, true); 505 } 506 507 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); } 508 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); } 509 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); } 510 void set_random (bool random_) { random = random_; } 511 void set_recurse_func (recurse_func_t func) { recurse_func = func; } 512 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } 513 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); } 514 515 uint32_t random_number () 516 { 517 /* http://www.cplusplus.com/reference/random/minstd_rand/ */ 518 random_state = random_state * 48271 % 2147483647; 519 return random_state; 520 } 521 522 bool match_properties_mark (hb_codepoint_t glyph, 523 unsigned int glyph_props, 524 unsigned int match_props) const 525 { 526 /* If using mark filtering sets, the high short of 527 * match_props has the set index. 528 */ 529 if (match_props & LookupFlag::UseMarkFilteringSet) 530 return gdef.mark_set_covers (match_props >> 16, glyph); 531 532 /* The second byte of match_props has the meaning 533 * "ignore marks of attachment type different than 534 * the attachment type specified." 535 */ 536 if (match_props & LookupFlag::MarkAttachmentType) 537 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType); 538 539 return true; 540 } 541 542 bool check_glyph_property (const hb_glyph_info_t *info, 543 unsigned int match_props) const 544 { 545 hb_codepoint_t glyph = info->codepoint; 546 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info); 547 548 /* Not covered, if, for example, glyph class is ligature and 549 * match_props includes LookupFlags::IgnoreLigatures 550 */ 551 if (glyph_props & match_props & LookupFlag::IgnoreFlags) 552 return false; 553 554 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) 555 return match_properties_mark (glyph, glyph_props, match_props); 556 557 return true; 558 } 559 560 void _set_glyph_props (hb_codepoint_t glyph_index, 561 unsigned int class_guess = 0, 562 bool ligature = false, 563 bool component = false) const 564 { 565 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) & 566 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; 567 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; 568 if (ligature) 569 { 570 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; 571 /* In the only place that the MULTIPLIED bit is used, Uniscribe 572 * seems to only care about the "last" transformation between 573 * Ligature and Multiple substitutions. Ie. if you ligate, expand, 574 * and ligate again, it forgives the multiplication and acts as 575 * if only ligation happened. As such, clear MULTIPLIED bit. 576 */ 577 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; 578 } 579 if (component) 580 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; 581 if (likely (has_glyph_classes)) 582 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index)); 583 else if (class_guess) 584 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess); 585 } 586 587 void replace_glyph (hb_codepoint_t glyph_index) const 588 { 589 _set_glyph_props (glyph_index); 590 buffer->replace_glyph (glyph_index); 591 } 592 void replace_glyph_inplace (hb_codepoint_t glyph_index) const 593 { 594 _set_glyph_props (glyph_index); 595 buffer->cur().codepoint = glyph_index; 596 } 597 void replace_glyph_with_ligature (hb_codepoint_t glyph_index, 598 unsigned int class_guess) const 599 { 600 _set_glyph_props (glyph_index, class_guess, true); 601 buffer->replace_glyph (glyph_index); 602 } 603 void output_glyph_for_component (hb_codepoint_t glyph_index, 604 unsigned int class_guess) const 605 { 606 _set_glyph_props (glyph_index, class_guess, false, true); 607 buffer->output_glyph (glyph_index); 608 } 609 }; 610 611 612 struct hb_get_subtables_context_t : 613 hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY> 614 { 615 template <typename Type> 616 static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c) 617 { 618 const Type *typed_obj = (const Type *) obj; 619 return typed_obj->apply (c); 620 } 621 622 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c); 623 624 struct hb_applicable_t 625 { 626 template <typename T> 627 void init (const T &obj_, hb_apply_func_t apply_func_) 628 { 629 obj = &obj_; 630 apply_func = apply_func_; 631 digest.init (); 632 obj_.get_coverage ().add_coverage (&digest); 633 } 634 635 bool apply (OT::hb_ot_apply_context_t *c) const 636 { 637 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c); 638 } 639 640 private: 641 const void *obj; 642 hb_apply_func_t apply_func; 643 hb_set_digest_t digest; 644 }; 645 646 typedef hb_vector_t<hb_applicable_t, 2> array_t; 647 648 /* Dispatch interface. */ 649 const char *get_name () { return "GET_SUBTABLES"; } 650 template <typename T> 651 return_t dispatch (const T &obj) 652 { 653 hb_applicable_t *entry = array.push(); 654 entry->init (obj, apply_to<T>); 655 return HB_VOID; 656 } 657 static return_t default_return_value () { return HB_VOID; } 658 659 hb_get_subtables_context_t (array_t &array_) : 660 array (array_), 661 debug_depth (0) {} 662 663 array_t &array; 664 unsigned int debug_depth; 665 }; 666 667 668 669 670 typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data); 671 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data); 672 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data); 673 674 struct ContextClosureFuncs 675 { 676 intersects_func_t intersects; 677 }; 678 struct ContextCollectGlyphsFuncs 679 { 680 collect_glyphs_func_t collect; 681 }; 682 struct ContextApplyFuncs 683 { 684 match_func_t match; 685 }; 686 687 688 static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED) 689 { 690 return glyphs->has (value); 691 } 692 static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data) 693 { 694 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 695 return class_def.intersects_class (glyphs, value); 696 } 697 static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data) 698 { 699 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 700 return (data+coverage).intersects (glyphs); 701 } 702 703 static inline bool intersects_array (const hb_set_t *glyphs, 704 unsigned int count, 705 const HBUINT16 values[], 706 intersects_func_t intersects_func, 707 const void *intersects_data) 708 { 709 for (unsigned int i = 0; i < count; i++) 710 if (likely (!intersects_func (glyphs, values[i], intersects_data))) 711 return false; 712 return true; 713 } 714 715 716 static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED) 717 { 718 glyphs->add (value); 719 } 720 static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data) 721 { 722 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 723 class_def.add_class (glyphs, value); 724 } 725 static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data) 726 { 727 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 728 (data+coverage).add_coverage (glyphs); 729 } 730 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, 731 hb_set_t *glyphs, 732 unsigned int count, 733 const HBUINT16 values[], 734 collect_glyphs_func_t collect_func, 735 const void *collect_data) 736 { 737 for (unsigned int i = 0; i < count; i++) 738 collect_func (glyphs, values[i], collect_data); 739 } 740 741 742 static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED) 743 { 744 return glyph_id == value; 745 } 746 static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data) 747 { 748 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 749 return class_def.get_class (glyph_id) == value; 750 } 751 static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data) 752 { 753 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 754 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; 755 } 756 757 static inline bool would_match_input (hb_would_apply_context_t *c, 758 unsigned int count, /* Including the first glyph (not matched) */ 759 const HBUINT16 input[], /* Array of input values--start with second glyph */ 760 match_func_t match_func, 761 const void *match_data) 762 { 763 if (count != c->len) 764 return false; 765 766 for (unsigned int i = 1; i < count; i++) 767 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data))) 768 return false; 769 770 return true; 771 } 772 static inline bool match_input (hb_ot_apply_context_t *c, 773 unsigned int count, /* Including the first glyph (not matched) */ 774 const HBUINT16 input[], /* Array of input values--start with second glyph */ 775 match_func_t match_func, 776 const void *match_data, 777 unsigned int *end_offset, 778 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], 779 unsigned int *p_total_component_count = nullptr) 780 { 781 TRACE_APPLY (nullptr); 782 783 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false); 784 785 hb_buffer_t *buffer = c->buffer; 786 787 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 788 skippy_iter.reset (buffer->idx, count - 1); 789 skippy_iter.set_match_func (match_func, match_data, input); 790 791 /* 792 * This is perhaps the trickiest part of OpenType... Remarks: 793 * 794 * - If all components of the ligature were marks, we call this a mark ligature. 795 * 796 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize 797 * it as a ligature glyph. 798 * 799 * - Ligatures cannot be formed across glyphs attached to different components 800 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and 801 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother. 802 * However, it would be wrong to ligate that SHADDA,FATHA sequence. 803 * There are a couple of exceptions to this: 804 * 805 * o If a ligature tries ligating with marks that belong to it itself, go ahead, 806 * assuming that the font designer knows what they are doing (otherwise it can 807 * break Indic stuff when a matra wants to ligate with a conjunct, 808 * 809 * o If two marks want to ligate and they belong to different components of the 810 * same ligature glyph, and said ligature glyph is to be ignored according to 811 * mark-filtering rules, then allow. 812 * https://github.com/harfbuzz/harfbuzz/issues/545 813 */ 814 815 unsigned int total_component_count = 0; 816 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 817 818 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 819 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); 820 821 enum { 822 LIGBASE_NOT_CHECKED, 823 LIGBASE_MAY_NOT_SKIP, 824 LIGBASE_MAY_SKIP 825 } ligbase = LIGBASE_NOT_CHECKED; 826 827 match_positions[0] = buffer->idx; 828 for (unsigned int i = 1; i < count; i++) 829 { 830 if (!skippy_iter.next ()) return_trace (false); 831 832 match_positions[i] = skippy_iter.idx; 833 834 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); 835 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); 836 837 if (first_lig_id && first_lig_comp) 838 { 839 /* If first component was attached to a previous ligature component, 840 * all subsequent components should be attached to the same ligature 841 * component, otherwise we shouldn't ligate them... */ 842 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) 843 { 844 /* ...unless, we are attached to a base ligature and that base 845 * ligature is ignorable. */ 846 if (ligbase == LIGBASE_NOT_CHECKED) 847 { 848 bool found = false; 849 const hb_glyph_info_t *out = buffer->out_info; 850 unsigned int j = buffer->out_len; 851 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id) 852 { 853 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0) 854 { 855 j--; 856 found = true; 857 break; 858 } 859 j--; 860 } 861 862 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES) 863 ligbase = LIGBASE_MAY_SKIP; 864 else 865 ligbase = LIGBASE_MAY_NOT_SKIP; 866 } 867 868 if (ligbase == LIGBASE_MAY_NOT_SKIP) 869 return_trace (false); 870 } 871 } 872 else 873 { 874 /* If first component was NOT attached to a previous ligature component, 875 * all subsequent components should also NOT be attached to any ligature 876 * component, unless they are attached to the first component itself! */ 877 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id)) 878 return_trace (false); 879 } 880 881 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); 882 } 883 884 *end_offset = skippy_iter.idx - buffer->idx + 1; 885 886 if (p_total_component_count) 887 *p_total_component_count = total_component_count; 888 889 return_trace (true); 890 } 891 static inline bool ligate_input (hb_ot_apply_context_t *c, 892 unsigned int count, /* Including the first glyph */ 893 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ 894 unsigned int match_length, 895 hb_codepoint_t lig_glyph, 896 unsigned int total_component_count) 897 { 898 TRACE_APPLY (nullptr); 899 900 hb_buffer_t *buffer = c->buffer; 901 902 buffer->merge_clusters (buffer->idx, buffer->idx + match_length); 903 904 /* - If a base and one or more marks ligate, consider that as a base, NOT 905 * ligature, such that all following marks can still attach to it. 906 * https://github.com/harfbuzz/harfbuzz/issues/1109 907 * 908 * - If all components of the ligature were marks, we call this a mark ligature. 909 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave 910 * the ligature to keep its old ligature id. This will allow it to attach to 911 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH, 912 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a 913 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature 914 * later, we don't want them to lose their ligature id/component, otherwise 915 * GPOS will fail to correctly position the mark ligature on top of the 916 * LAM,LAM,HEH ligature. See: 917 * https://bugzilla.gnome.org/show_bug.cgi?id=676343 918 * 919 * - If a ligature is formed of components that some of which are also ligatures 920 * themselves, and those ligature components had marks attached to *their* 921 * components, we have to attach the marks to the new ligature component 922 * positions! Now *that*'s tricky! And these marks may be following the 923 * last component of the whole sequence, so we should loop forward looking 924 * for them and update them. 925 * 926 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a 927 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature 928 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature 929 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to 930 * the new ligature with a component value of 2. 931 * 932 * This in fact happened to a font... See: 933 * https://bugzilla.gnome.org/show_bug.cgi?id=437633 934 */ 935 936 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]); 937 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]); 938 for (unsigned int i = 1; i < count; i++) 939 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]])) 940 { 941 is_base_ligature = false; 942 is_mark_ligature = false; 943 break; 944 } 945 bool is_ligature = !is_base_ligature && !is_mark_ligature; 946 947 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0; 948 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0; 949 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 950 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 951 unsigned int components_so_far = last_num_components; 952 953 if (is_ligature) 954 { 955 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count); 956 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 957 { 958 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER); 959 } 960 } 961 c->replace_glyph_with_ligature (lig_glyph, klass); 962 963 for (unsigned int i = 1; i < count; i++) 964 { 965 while (buffer->idx < match_positions[i] && buffer->successful) 966 { 967 if (is_ligature) 968 { 969 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); 970 if (this_comp == 0) 971 this_comp = last_num_components; 972 unsigned int new_lig_comp = components_so_far - last_num_components + 973 MIN (this_comp, last_num_components); 974 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp); 975 } 976 buffer->next_glyph (); 977 } 978 979 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 980 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 981 components_so_far += last_num_components; 982 983 /* Skip the base glyph */ 984 buffer->idx++; 985 } 986 987 if (!is_mark_ligature && last_lig_id) { 988 /* Re-adjust components for any marks following. */ 989 for (unsigned int i = buffer->idx; i < buffer->len; i++) { 990 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) { 991 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]); 992 if (!this_comp) 993 break; 994 unsigned int new_lig_comp = components_so_far - last_num_components + 995 MIN (this_comp, last_num_components); 996 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp); 997 } else 998 break; 999 } 1000 } 1001 return_trace (true); 1002 } 1003 1004 static inline bool match_backtrack (hb_ot_apply_context_t *c, 1005 unsigned int count, 1006 const HBUINT16 backtrack[], 1007 match_func_t match_func, 1008 const void *match_data, 1009 unsigned int *match_start) 1010 { 1011 TRACE_APPLY (nullptr); 1012 1013 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; 1014 skippy_iter.reset (c->buffer->backtrack_len (), count); 1015 skippy_iter.set_match_func (match_func, match_data, backtrack); 1016 1017 for (unsigned int i = 0; i < count; i++) 1018 if (!skippy_iter.prev ()) 1019 return_trace (false); 1020 1021 *match_start = skippy_iter.idx; 1022 1023 return_trace (true); 1024 } 1025 1026 static inline bool match_lookahead (hb_ot_apply_context_t *c, 1027 unsigned int count, 1028 const HBUINT16 lookahead[], 1029 match_func_t match_func, 1030 const void *match_data, 1031 unsigned int offset, 1032 unsigned int *end_index) 1033 { 1034 TRACE_APPLY (nullptr); 1035 1036 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; 1037 skippy_iter.reset (c->buffer->idx + offset - 1, count); 1038 skippy_iter.set_match_func (match_func, match_data, lookahead); 1039 1040 for (unsigned int i = 0; i < count; i++) 1041 if (!skippy_iter.next ()) 1042 return_trace (false); 1043 1044 *end_index = skippy_iter.idx + 1; 1045 1046 return_trace (true); 1047 } 1048 1049 1050 1051 struct LookupRecord 1052 { 1053 bool sanitize (hb_sanitize_context_t *c) const 1054 { 1055 TRACE_SANITIZE (this); 1056 return_trace (c->check_struct (this)); 1057 } 1058 1059 HBUINT16 sequenceIndex; /* Index into current glyph 1060 * sequence--first glyph = 0 */ 1061 HBUINT16 lookupListIndex; /* Lookup to apply to that 1062 * position--zero--based */ 1063 public: 1064 DEFINE_SIZE_STATIC (4); 1065 }; 1066 1067 template <typename context_t> 1068 static inline void recurse_lookups (context_t *c, 1069 unsigned int lookupCount, 1070 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) 1071 { 1072 for (unsigned int i = 0; i < lookupCount; i++) 1073 c->recurse (lookupRecord[i].lookupListIndex); 1074 } 1075 1076 static inline bool apply_lookup (hb_ot_apply_context_t *c, 1077 unsigned int count, /* Including the first glyph */ 1078 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ 1079 unsigned int lookupCount, 1080 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ 1081 unsigned int match_length) 1082 { 1083 TRACE_APPLY (nullptr); 1084 1085 hb_buffer_t *buffer = c->buffer; 1086 int end; 1087 1088 /* All positions are distance from beginning of *output* buffer. 1089 * Adjust. */ 1090 { 1091 unsigned int bl = buffer->backtrack_len (); 1092 end = bl + match_length; 1093 1094 int delta = bl - buffer->idx; 1095 /* Convert positions to new indexing. */ 1096 for (unsigned int j = 0; j < count; j++) 1097 match_positions[j] += delta; 1098 } 1099 1100 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++) 1101 { 1102 unsigned int idx = lookupRecord[i].sequenceIndex; 1103 if (idx >= count) 1104 continue; 1105 1106 /* Don't recurse to ourself at same position. 1107 * Note that this test is too naive, it doesn't catch longer loops. */ 1108 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index) 1109 continue; 1110 1111 if (unlikely (!buffer->move_to (match_positions[idx]))) 1112 break; 1113 1114 if (unlikely (buffer->max_ops <= 0)) 1115 break; 1116 1117 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); 1118 if (!c->recurse (lookupRecord[i].lookupListIndex)) 1119 continue; 1120 1121 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len (); 1122 int delta = new_len - orig_len; 1123 1124 if (!delta) 1125 continue; 1126 1127 /* Recursed lookup changed buffer len. Adjust. 1128 * 1129 * TODO: 1130 * 1131 * Right now, if buffer length increased by n, we assume n new glyphs 1132 * were added right after the current position, and if buffer length 1133 * was decreased by n, we assume n match positions after the current 1134 * one where removed. The former (buffer length increased) case is 1135 * fine, but the decrease case can be improved in at least two ways, 1136 * both of which are significant: 1137 * 1138 * - If recursed-to lookup is MultipleSubst and buffer length 1139 * decreased, then it's current match position that was deleted, 1140 * NOT the one after it. 1141 * 1142 * - If buffer length was decreased by n, it does not necessarily 1143 * mean that n match positions where removed, as there might 1144 * have been marks and default-ignorables in the sequence. We 1145 * should instead drop match positions between current-position 1146 * and current-position + n instead. 1147 * 1148 * It should be possible to construct tests for both of these cases. 1149 */ 1150 1151 end += delta; 1152 if (end <= int (match_positions[idx])) 1153 { 1154 /* End might end up being smaller than match_positions[idx] if the recursed 1155 * lookup ended up removing many items, more than we have had matched. 1156 * Just never rewind end back and get out of here. 1157 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */ 1158 end = match_positions[idx]; 1159 /* There can't be any further changes. */ 1160 break; 1161 } 1162 1163 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */ 1164 1165 if (delta > 0) 1166 { 1167 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH)) 1168 break; 1169 } 1170 else 1171 { 1172 /* NOTE: delta is negative. */ 1173 delta = MAX (delta, (int) next - (int) count); 1174 next -= delta; 1175 } 1176 1177 /* Shift! */ 1178 memmove (match_positions + next + delta, match_positions + next, 1179 (count - next) * sizeof (match_positions[0])); 1180 next += delta; 1181 count += delta; 1182 1183 /* Fill in new entries. */ 1184 for (unsigned int j = idx + 1; j < next; j++) 1185 match_positions[j] = match_positions[j - 1] + 1; 1186 1187 /* And fixup the rest. */ 1188 for (; next < count; next++) 1189 match_positions[next] += delta; 1190 } 1191 1192 buffer->move_to (end); 1193 1194 return_trace (true); 1195 } 1196 1197 1198 1199 /* Contextual lookups */ 1200 1201 struct ContextClosureLookupContext 1202 { 1203 ContextClosureFuncs funcs; 1204 const void *intersects_data; 1205 }; 1206 1207 struct ContextCollectGlyphsLookupContext 1208 { 1209 ContextCollectGlyphsFuncs funcs; 1210 const void *collect_data; 1211 }; 1212 1213 struct ContextApplyLookupContext 1214 { 1215 ContextApplyFuncs funcs; 1216 const void *match_data; 1217 }; 1218 1219 static inline bool context_intersects (const hb_set_t *glyphs, 1220 unsigned int inputCount, /* Including the first glyph (not matched) */ 1221 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1222 ContextClosureLookupContext &lookup_context) 1223 { 1224 return intersects_array (glyphs, 1225 inputCount ? inputCount - 1 : 0, input, 1226 lookup_context.funcs.intersects, lookup_context.intersects_data); 1227 } 1228 1229 static inline void context_closure_lookup (hb_closure_context_t *c, 1230 unsigned int inputCount, /* Including the first glyph (not matched) */ 1231 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1232 unsigned int lookupCount, 1233 const LookupRecord lookupRecord[], 1234 ContextClosureLookupContext &lookup_context) 1235 { 1236 if (context_intersects (c->glyphs, 1237 inputCount, input, 1238 lookup_context)) 1239 recurse_lookups (c, 1240 lookupCount, lookupRecord); 1241 } 1242 1243 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 1244 unsigned int inputCount, /* Including the first glyph (not matched) */ 1245 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1246 unsigned int lookupCount, 1247 const LookupRecord lookupRecord[], 1248 ContextCollectGlyphsLookupContext &lookup_context) 1249 { 1250 collect_array (c, c->input, 1251 inputCount ? inputCount - 1 : 0, input, 1252 lookup_context.funcs.collect, lookup_context.collect_data); 1253 recurse_lookups (c, 1254 lookupCount, lookupRecord); 1255 } 1256 1257 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, 1258 unsigned int inputCount, /* Including the first glyph (not matched) */ 1259 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1260 unsigned int lookupCount HB_UNUSED, 1261 const LookupRecord lookupRecord[] HB_UNUSED, 1262 ContextApplyLookupContext &lookup_context) 1263 { 1264 return would_match_input (c, 1265 inputCount, input, 1266 lookup_context.funcs.match, lookup_context.match_data); 1267 } 1268 static inline bool context_apply_lookup (hb_ot_apply_context_t *c, 1269 unsigned int inputCount, /* Including the first glyph (not matched) */ 1270 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1271 unsigned int lookupCount, 1272 const LookupRecord lookupRecord[], 1273 ContextApplyLookupContext &lookup_context) 1274 { 1275 unsigned int match_length = 0; 1276 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; 1277 return match_input (c, 1278 inputCount, input, 1279 lookup_context.funcs.match, lookup_context.match_data, 1280 &match_length, match_positions) 1281 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length), 1282 apply_lookup (c, 1283 inputCount, match_positions, 1284 lookupCount, lookupRecord, 1285 match_length)); 1286 } 1287 1288 struct Rule 1289 { 1290 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const 1291 { 1292 return context_intersects (glyphs, 1293 inputCount, inputZ.arrayZ, 1294 lookup_context); 1295 } 1296 1297 void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 1298 { 1299 TRACE_CLOSURE (this); 1300 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> > 1301 (inputZ.as_array ((inputCount ? inputCount - 1 : 0))); 1302 context_closure_lookup (c, 1303 inputCount, inputZ.arrayZ, 1304 lookupCount, lookupRecord.arrayZ, 1305 lookup_context); 1306 } 1307 1308 void collect_glyphs (hb_collect_glyphs_context_t *c, 1309 ContextCollectGlyphsLookupContext &lookup_context) const 1310 { 1311 TRACE_COLLECT_GLYPHS (this); 1312 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> > 1313 (inputZ.as_array (inputCount ? inputCount - 1 : 0)); 1314 context_collect_glyphs_lookup (c, 1315 inputCount, inputZ.arrayZ, 1316 lookupCount, lookupRecord.arrayZ, 1317 lookup_context); 1318 } 1319 1320 bool would_apply (hb_would_apply_context_t *c, 1321 ContextApplyLookupContext &lookup_context) const 1322 { 1323 TRACE_WOULD_APPLY (this); 1324 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> > 1325 (inputZ.as_array (inputCount ? inputCount - 1 : 0)); 1326 return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context)); 1327 } 1328 1329 bool apply (hb_ot_apply_context_t *c, 1330 ContextApplyLookupContext &lookup_context) const 1331 { 1332 TRACE_APPLY (this); 1333 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> > 1334 (inputZ.as_array (inputCount ? inputCount - 1 : 0)); 1335 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context)); 1336 } 1337 1338 public: 1339 bool sanitize (hb_sanitize_context_t *c) const 1340 { 1341 TRACE_SANITIZE (this); 1342 return_trace (inputCount.sanitize (c) && 1343 lookupCount.sanitize (c) && 1344 c->check_range (inputZ.arrayZ, 1345 inputZ.item_size * (inputCount ? inputCount - 1 : 0) + 1346 LookupRecord::static_size * lookupCount)); 1347 } 1348 1349 protected: 1350 HBUINT16 inputCount; /* Total number of glyphs in input 1351 * glyph sequence--includes the first 1352 * glyph */ 1353 HBUINT16 lookupCount; /* Number of LookupRecords */ 1354 UnsizedArrayOf<HBUINT16> 1355 inputZ; /* Array of match inputs--start with 1356 * second glyph */ 1357 /*UnsizedArrayOf<LookupRecord> 1358 lookupRecordX;*/ /* Array of LookupRecords--in 1359 * design order */ 1360 public: 1361 DEFINE_SIZE_ARRAY (4, inputZ); 1362 }; 1363 1364 struct RuleSet 1365 { 1366 bool intersects (const hb_set_t *glyphs, 1367 ContextClosureLookupContext &lookup_context) const 1368 { 1369 unsigned int num_rules = rule.len; 1370 for (unsigned int i = 0; i < num_rules; i++) 1371 if ((this+rule[i]).intersects (glyphs, lookup_context)) 1372 return true; 1373 return false; 1374 } 1375 1376 void closure (hb_closure_context_t *c, 1377 ContextClosureLookupContext &lookup_context) const 1378 { 1379 TRACE_CLOSURE (this); 1380 unsigned int num_rules = rule.len; 1381 for (unsigned int i = 0; i < num_rules; i++) 1382 (this+rule[i]).closure (c, lookup_context); 1383 } 1384 1385 void collect_glyphs (hb_collect_glyphs_context_t *c, 1386 ContextCollectGlyphsLookupContext &lookup_context) const 1387 { 1388 TRACE_COLLECT_GLYPHS (this); 1389 unsigned int num_rules = rule.len; 1390 for (unsigned int i = 0; i < num_rules; i++) 1391 (this+rule[i]).collect_glyphs (c, lookup_context); 1392 } 1393 1394 bool would_apply (hb_would_apply_context_t *c, 1395 ContextApplyLookupContext &lookup_context) const 1396 { 1397 TRACE_WOULD_APPLY (this); 1398 unsigned int num_rules = rule.len; 1399 for (unsigned int i = 0; i < num_rules; i++) 1400 { 1401 if ((this+rule[i]).would_apply (c, lookup_context)) 1402 return_trace (true); 1403 } 1404 return_trace (false); 1405 } 1406 1407 bool apply (hb_ot_apply_context_t *c, 1408 ContextApplyLookupContext &lookup_context) const 1409 { 1410 TRACE_APPLY (this); 1411 unsigned int num_rules = rule.len; 1412 for (unsigned int i = 0; i < num_rules; i++) 1413 { 1414 if ((this+rule[i]).apply (c, lookup_context)) 1415 return_trace (true); 1416 } 1417 return_trace (false); 1418 } 1419 1420 bool sanitize (hb_sanitize_context_t *c) const 1421 { 1422 TRACE_SANITIZE (this); 1423 return_trace (rule.sanitize (c, this)); 1424 } 1425 1426 protected: 1427 OffsetArrayOf<Rule> 1428 rule; /* Array of Rule tables 1429 * ordered by preference */ 1430 public: 1431 DEFINE_SIZE_ARRAY (2, rule); 1432 }; 1433 1434 1435 struct ContextFormat1 1436 { 1437 bool intersects (const hb_set_t *glyphs) const 1438 { 1439 struct ContextClosureLookupContext lookup_context = { 1440 {intersects_glyph}, 1441 nullptr 1442 }; 1443 1444 unsigned int count = ruleSet.len; 1445 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) 1446 { 1447 if (unlikely (iter.get_coverage () >= count)) 1448 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ 1449 if (glyphs->has (iter.get_glyph ()) && 1450 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) 1451 return true; 1452 } 1453 return false; 1454 } 1455 1456 void closure (hb_closure_context_t *c) const 1457 { 1458 TRACE_CLOSURE (this); 1459 1460 struct ContextClosureLookupContext lookup_context = { 1461 {intersects_glyph}, 1462 nullptr 1463 }; 1464 1465 unsigned int count = ruleSet.len; 1466 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) 1467 { 1468 if (unlikely (iter.get_coverage () >= count)) 1469 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ 1470 if (c->glyphs->has (iter.get_glyph ())) 1471 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); 1472 } 1473 } 1474 1475 void collect_glyphs (hb_collect_glyphs_context_t *c) const 1476 { 1477 TRACE_COLLECT_GLYPHS (this); 1478 (this+coverage).add_coverage (c->input); 1479 1480 struct ContextCollectGlyphsLookupContext lookup_context = { 1481 {collect_glyph}, 1482 nullptr 1483 }; 1484 1485 unsigned int count = ruleSet.len; 1486 for (unsigned int i = 0; i < count; i++) 1487 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1488 } 1489 1490 bool would_apply (hb_would_apply_context_t *c) const 1491 { 1492 TRACE_WOULD_APPLY (this); 1493 1494 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 1495 struct ContextApplyLookupContext lookup_context = { 1496 {match_glyph}, 1497 nullptr 1498 }; 1499 return_trace (rule_set.would_apply (c, lookup_context)); 1500 } 1501 1502 const Coverage &get_coverage () const { return this+coverage; } 1503 1504 bool apply (hb_ot_apply_context_t *c) const 1505 { 1506 TRACE_APPLY (this); 1507 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1508 if (likely (index == NOT_COVERED)) 1509 return_trace (false); 1510 1511 const RuleSet &rule_set = this+ruleSet[index]; 1512 struct ContextApplyLookupContext lookup_context = { 1513 {match_glyph}, 1514 nullptr 1515 }; 1516 return_trace (rule_set.apply (c, lookup_context)); 1517 } 1518 1519 bool subset (hb_subset_context_t *c) const 1520 { 1521 TRACE_SUBSET (this); 1522 // TODO(subset) 1523 return_trace (false); 1524 } 1525 1526 bool sanitize (hb_sanitize_context_t *c) const 1527 { 1528 TRACE_SANITIZE (this); 1529 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1530 } 1531 1532 protected: 1533 HBUINT16 format; /* Format identifier--format = 1 */ 1534 OffsetTo<Coverage> 1535 coverage; /* Offset to Coverage table--from 1536 * beginning of table */ 1537 OffsetArrayOf<RuleSet> 1538 ruleSet; /* Array of RuleSet tables 1539 * ordered by Coverage Index */ 1540 public: 1541 DEFINE_SIZE_ARRAY (6, ruleSet); 1542 }; 1543 1544 1545 struct ContextFormat2 1546 { 1547 bool intersects (const hb_set_t *glyphs) const 1548 { 1549 if (!(this+coverage).intersects (glyphs)) 1550 return false; 1551 1552 const ClassDef &class_def = this+classDef; 1553 1554 struct ContextClosureLookupContext lookup_context = { 1555 {intersects_class}, 1556 &class_def 1557 }; 1558 1559 unsigned int count = ruleSet.len; 1560 for (unsigned int i = 0; i < count; i++) 1561 if (class_def.intersects_class (glyphs, i) && 1562 (this+ruleSet[i]).intersects (glyphs, lookup_context)) 1563 return true; 1564 1565 return false; 1566 } 1567 1568 void closure (hb_closure_context_t *c) const 1569 { 1570 TRACE_CLOSURE (this); 1571 if (!(this+coverage).intersects (c->glyphs)) 1572 return; 1573 1574 const ClassDef &class_def = this+classDef; 1575 1576 struct ContextClosureLookupContext lookup_context = { 1577 {intersects_class}, 1578 &class_def 1579 }; 1580 1581 unsigned int count = ruleSet.len; 1582 for (unsigned int i = 0; i < count; i++) 1583 if (class_def.intersects_class (c->glyphs, i)) { 1584 const RuleSet &rule_set = this+ruleSet[i]; 1585 rule_set.closure (c, lookup_context); 1586 } 1587 } 1588 1589 void collect_glyphs (hb_collect_glyphs_context_t *c) const 1590 { 1591 TRACE_COLLECT_GLYPHS (this); 1592 (this+coverage).add_coverage (c->input); 1593 1594 const ClassDef &class_def = this+classDef; 1595 struct ContextCollectGlyphsLookupContext lookup_context = { 1596 {collect_class}, 1597 &class_def 1598 }; 1599 1600 unsigned int count = ruleSet.len; 1601 for (unsigned int i = 0; i < count; i++) 1602 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1603 } 1604 1605 bool would_apply (hb_would_apply_context_t *c) const 1606 { 1607 TRACE_WOULD_APPLY (this); 1608 1609 const ClassDef &class_def = this+classDef; 1610 unsigned int index = class_def.get_class (c->glyphs[0]); 1611 const RuleSet &rule_set = this+ruleSet[index]; 1612 struct ContextApplyLookupContext lookup_context = { 1613 {match_class}, 1614 &class_def 1615 }; 1616 return_trace (rule_set.would_apply (c, lookup_context)); 1617 } 1618 1619 const Coverage &get_coverage () const { return this+coverage; } 1620 1621 bool apply (hb_ot_apply_context_t *c) const 1622 { 1623 TRACE_APPLY (this); 1624 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1625 if (likely (index == NOT_COVERED)) return_trace (false); 1626 1627 const ClassDef &class_def = this+classDef; 1628 index = class_def.get_class (c->buffer->cur().codepoint); 1629 const RuleSet &rule_set = this+ruleSet[index]; 1630 struct ContextApplyLookupContext lookup_context = { 1631 {match_class}, 1632 &class_def 1633 }; 1634 return_trace (rule_set.apply (c, lookup_context)); 1635 } 1636 1637 bool subset (hb_subset_context_t *c) const 1638 { 1639 TRACE_SUBSET (this); 1640 // TODO(subset) 1641 return_trace (false); 1642 } 1643 1644 bool sanitize (hb_sanitize_context_t *c) const 1645 { 1646 TRACE_SANITIZE (this); 1647 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); 1648 } 1649 1650 protected: 1651 HBUINT16 format; /* Format identifier--format = 2 */ 1652 OffsetTo<Coverage> 1653 coverage; /* Offset to Coverage table--from 1654 * beginning of table */ 1655 OffsetTo<ClassDef> 1656 classDef; /* Offset to glyph ClassDef table--from 1657 * beginning of table */ 1658 OffsetArrayOf<RuleSet> 1659 ruleSet; /* Array of RuleSet tables 1660 * ordered by class */ 1661 public: 1662 DEFINE_SIZE_ARRAY (8, ruleSet); 1663 }; 1664 1665 1666 struct ContextFormat3 1667 { 1668 bool intersects (const hb_set_t *glyphs) const 1669 { 1670 if (!(this+coverageZ[0]).intersects (glyphs)) 1671 return false; 1672 1673 struct ContextClosureLookupContext lookup_context = { 1674 {intersects_coverage}, 1675 this 1676 }; 1677 return context_intersects (glyphs, 1678 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), 1679 lookup_context); 1680 } 1681 1682 void closure (hb_closure_context_t *c) const 1683 { 1684 TRACE_CLOSURE (this); 1685 if (!(this+coverageZ[0]).intersects (c->glyphs)) 1686 return; 1687 1688 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); 1689 struct ContextClosureLookupContext lookup_context = { 1690 {intersects_coverage}, 1691 this 1692 }; 1693 context_closure_lookup (c, 1694 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), 1695 lookupCount, lookupRecord, 1696 lookup_context); 1697 } 1698 1699 void collect_glyphs (hb_collect_glyphs_context_t *c) const 1700 { 1701 TRACE_COLLECT_GLYPHS (this); 1702 (this+coverageZ[0]).add_coverage (c->input); 1703 1704 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); 1705 struct ContextCollectGlyphsLookupContext lookup_context = { 1706 {collect_coverage}, 1707 this 1708 }; 1709 1710 context_collect_glyphs_lookup (c, 1711 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), 1712 lookupCount, lookupRecord, 1713 lookup_context); 1714 } 1715 1716 bool would_apply (hb_would_apply_context_t *c) const 1717 { 1718 TRACE_WOULD_APPLY (this); 1719 1720 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); 1721 struct ContextApplyLookupContext lookup_context = { 1722 {match_coverage}, 1723 this 1724 }; 1725 return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context)); 1726 } 1727 1728 const Coverage &get_coverage () const { return this+coverageZ[0]; } 1729 1730 bool apply (hb_ot_apply_context_t *c) const 1731 { 1732 TRACE_APPLY (this); 1733 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint); 1734 if (likely (index == NOT_COVERED)) return_trace (false); 1735 1736 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); 1737 struct ContextApplyLookupContext lookup_context = { 1738 {match_coverage}, 1739 this 1740 }; 1741 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context)); 1742 } 1743 1744 bool subset (hb_subset_context_t *c) const 1745 { 1746 TRACE_SUBSET (this); 1747 // TODO(subset) 1748 return_trace (false); 1749 } 1750 1751 bool sanitize (hb_sanitize_context_t *c) const 1752 { 1753 TRACE_SANITIZE (this); 1754 if (!c->check_struct (this)) return_trace (false); 1755 unsigned int count = glyphCount; 1756 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */ 1757 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false); 1758 for (unsigned int i = 0; i < count; i++) 1759 if (!coverageZ[i].sanitize (c, this)) return_trace (false); 1760 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); 1761 return_trace (c->check_array (lookupRecord, lookupCount)); 1762 } 1763 1764 protected: 1765 HBUINT16 format; /* Format identifier--format = 3 */ 1766 HBUINT16 glyphCount; /* Number of glyphs in the input glyph 1767 * sequence */ 1768 HBUINT16 lookupCount; /* Number of LookupRecords */ 1769 UnsizedArrayOf<OffsetTo<Coverage> > 1770 coverageZ; /* Array of offsets to Coverage 1771 * table in glyph sequence order */ 1772 /*UnsizedArrayOf<LookupRecord> 1773 lookupRecordX;*/ /* Array of LookupRecords--in 1774 * design order */ 1775 public: 1776 DEFINE_SIZE_ARRAY (6, coverageZ); 1777 }; 1778 1779 struct Context 1780 { 1781 template <typename context_t> 1782 typename context_t::return_t dispatch (context_t *c) const 1783 { 1784 TRACE_DISPATCH (this, u.format); 1785 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1786 switch (u.format) { 1787 case 1: return_trace (c->dispatch (u.format1)); 1788 case 2: return_trace (c->dispatch (u.format2)); 1789 case 3: return_trace (c->dispatch (u.format3)); 1790 default:return_trace (c->default_return_value ()); 1791 } 1792 } 1793 1794 protected: 1795 union { 1796 HBUINT16 format; /* Format identifier */ 1797 ContextFormat1 format1; 1798 ContextFormat2 format2; 1799 ContextFormat3 format3; 1800 } u; 1801 }; 1802 1803 1804 /* Chaining Contextual lookups */ 1805 1806 struct ChainContextClosureLookupContext 1807 { 1808 ContextClosureFuncs funcs; 1809 const void *intersects_data[3]; 1810 }; 1811 1812 struct ChainContextCollectGlyphsLookupContext 1813 { 1814 ContextCollectGlyphsFuncs funcs; 1815 const void *collect_data[3]; 1816 }; 1817 1818 struct ChainContextApplyLookupContext 1819 { 1820 ContextApplyFuncs funcs; 1821 const void *match_data[3]; 1822 }; 1823 1824 static inline bool chain_context_intersects (const hb_set_t *glyphs, 1825 unsigned int backtrackCount, 1826 const HBUINT16 backtrack[], 1827 unsigned int inputCount, /* Including the first glyph (not matched) */ 1828 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1829 unsigned int lookaheadCount, 1830 const HBUINT16 lookahead[], 1831 ChainContextClosureLookupContext &lookup_context) 1832 { 1833 return intersects_array (glyphs, 1834 backtrackCount, backtrack, 1835 lookup_context.funcs.intersects, lookup_context.intersects_data[0]) 1836 && intersects_array (glyphs, 1837 inputCount ? inputCount - 1 : 0, input, 1838 lookup_context.funcs.intersects, lookup_context.intersects_data[1]) 1839 && intersects_array (glyphs, 1840 lookaheadCount, lookahead, 1841 lookup_context.funcs.intersects, lookup_context.intersects_data[2]); 1842 } 1843 1844 static inline void chain_context_closure_lookup (hb_closure_context_t *c, 1845 unsigned int backtrackCount, 1846 const HBUINT16 backtrack[], 1847 unsigned int inputCount, /* Including the first glyph (not matched) */ 1848 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1849 unsigned int lookaheadCount, 1850 const HBUINT16 lookahead[], 1851 unsigned int lookupCount, 1852 const LookupRecord lookupRecord[], 1853 ChainContextClosureLookupContext &lookup_context) 1854 { 1855 if (chain_context_intersects (c->glyphs, 1856 backtrackCount, backtrack, 1857 inputCount, input, 1858 lookaheadCount, lookahead, 1859 lookup_context)) 1860 recurse_lookups (c, 1861 lookupCount, lookupRecord); 1862 } 1863 1864 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 1865 unsigned int backtrackCount, 1866 const HBUINT16 backtrack[], 1867 unsigned int inputCount, /* Including the first glyph (not matched) */ 1868 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1869 unsigned int lookaheadCount, 1870 const HBUINT16 lookahead[], 1871 unsigned int lookupCount, 1872 const LookupRecord lookupRecord[], 1873 ChainContextCollectGlyphsLookupContext &lookup_context) 1874 { 1875 collect_array (c, c->before, 1876 backtrackCount, backtrack, 1877 lookup_context.funcs.collect, lookup_context.collect_data[0]); 1878 collect_array (c, c->input, 1879 inputCount ? inputCount - 1 : 0, input, 1880 lookup_context.funcs.collect, lookup_context.collect_data[1]); 1881 collect_array (c, c->after, 1882 lookaheadCount, lookahead, 1883 lookup_context.funcs.collect, lookup_context.collect_data[2]); 1884 recurse_lookups (c, 1885 lookupCount, lookupRecord); 1886 } 1887 1888 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, 1889 unsigned int backtrackCount, 1890 const HBUINT16 backtrack[] HB_UNUSED, 1891 unsigned int inputCount, /* Including the first glyph (not matched) */ 1892 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1893 unsigned int lookaheadCount, 1894 const HBUINT16 lookahead[] HB_UNUSED, 1895 unsigned int lookupCount HB_UNUSED, 1896 const LookupRecord lookupRecord[] HB_UNUSED, 1897 ChainContextApplyLookupContext &lookup_context) 1898 { 1899 return (c->zero_context ? !backtrackCount && !lookaheadCount : true) 1900 && would_match_input (c, 1901 inputCount, input, 1902 lookup_context.funcs.match, lookup_context.match_data[1]); 1903 } 1904 1905 static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, 1906 unsigned int backtrackCount, 1907 const HBUINT16 backtrack[], 1908 unsigned int inputCount, /* Including the first glyph (not matched) */ 1909 const HBUINT16 input[], /* Array of input values--start with second glyph */ 1910 unsigned int lookaheadCount, 1911 const HBUINT16 lookahead[], 1912 unsigned int lookupCount, 1913 const LookupRecord lookupRecord[], 1914 ChainContextApplyLookupContext &lookup_context) 1915 { 1916 unsigned int start_index = 0, match_length = 0, end_index = 0; 1917 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; 1918 return match_input (c, 1919 inputCount, input, 1920 lookup_context.funcs.match, lookup_context.match_data[1], 1921 &match_length, match_positions) 1922 && match_backtrack (c, 1923 backtrackCount, backtrack, 1924 lookup_context.funcs.match, lookup_context.match_data[0], 1925 &start_index) 1926 && match_lookahead (c, 1927 lookaheadCount, lookahead, 1928 lookup_context.funcs.match, lookup_context.match_data[2], 1929 match_length, &end_index) 1930 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index), 1931 apply_lookup (c, 1932 inputCount, match_positions, 1933 lookupCount, lookupRecord, 1934 match_length)); 1935 } 1936 1937 struct ChainRule 1938 { 1939 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const 1940 { 1941 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); 1942 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); 1943 return chain_context_intersects (glyphs, 1944 backtrack.len, backtrack.arrayZ, 1945 input.lenP1, input.arrayZ, 1946 lookahead.len, lookahead.arrayZ, 1947 lookup_context); 1948 } 1949 1950 void closure (hb_closure_context_t *c, 1951 ChainContextClosureLookupContext &lookup_context) const 1952 { 1953 TRACE_CLOSURE (this); 1954 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); 1955 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); 1956 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1957 chain_context_closure_lookup (c, 1958 backtrack.len, backtrack.arrayZ, 1959 input.lenP1, input.arrayZ, 1960 lookahead.len, lookahead.arrayZ, 1961 lookup.len, lookup.arrayZ, 1962 lookup_context); 1963 } 1964 1965 void collect_glyphs (hb_collect_glyphs_context_t *c, 1966 ChainContextCollectGlyphsLookupContext &lookup_context) const 1967 { 1968 TRACE_COLLECT_GLYPHS (this); 1969 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); 1970 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); 1971 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1972 chain_context_collect_glyphs_lookup (c, 1973 backtrack.len, backtrack.arrayZ, 1974 input.lenP1, input.arrayZ, 1975 lookahead.len, lookahead.arrayZ, 1976 lookup.len, lookup.arrayZ, 1977 lookup_context); 1978 } 1979 1980 bool would_apply (hb_would_apply_context_t *c, 1981 ChainContextApplyLookupContext &lookup_context) const 1982 { 1983 TRACE_WOULD_APPLY (this); 1984 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); 1985 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); 1986 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1987 return_trace (chain_context_would_apply_lookup (c, 1988 backtrack.len, backtrack.arrayZ, 1989 input.lenP1, input.arrayZ, 1990 lookahead.len, lookahead.arrayZ, lookup.len, 1991 lookup.arrayZ, lookup_context)); 1992 } 1993 1994 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1995 { 1996 TRACE_APPLY (this); 1997 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); 1998 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); 1999 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2000 return_trace (chain_context_apply_lookup (c, 2001 backtrack.len, backtrack.arrayZ, 2002 input.lenP1, input.arrayZ, 2003 lookahead.len, lookahead.arrayZ, lookup.len, 2004 lookup.arrayZ, lookup_context)); 2005 } 2006 2007 bool sanitize (hb_sanitize_context_t *c) const 2008 { 2009 TRACE_SANITIZE (this); 2010 if (!backtrack.sanitize (c)) return_trace (false); 2011 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack); 2012 if (!input.sanitize (c)) return_trace (false); 2013 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input); 2014 if (!lookahead.sanitize (c)) return_trace (false); 2015 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2016 return_trace (lookup.sanitize (c)); 2017 } 2018 2019 protected: 2020 ArrayOf<HBUINT16> 2021 backtrack; /* Array of backtracking values 2022 * (to be matched before the input 2023 * sequence) */ 2024 HeadlessArrayOf<HBUINT16> 2025 inputX; /* Array of input values (start with 2026 * second glyph) */ 2027 ArrayOf<HBUINT16> 2028 lookaheadX; /* Array of lookahead values's (to be 2029 * matched after the input sequence) */ 2030 ArrayOf<LookupRecord> 2031 lookupX; /* Array of LookupRecords--in 2032 * design order) */ 2033 public: 2034 DEFINE_SIZE_MIN (8); 2035 }; 2036 2037 struct ChainRuleSet 2038 { 2039 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const 2040 { 2041 unsigned int num_rules = rule.len; 2042 for (unsigned int i = 0; i < num_rules; i++) 2043 if ((this+rule[i]).intersects (glyphs, lookup_context)) 2044 return true; 2045 return false; 2046 } 2047 void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 2048 { 2049 TRACE_CLOSURE (this); 2050 unsigned int num_rules = rule.len; 2051 for (unsigned int i = 0; i < num_rules; i++) 2052 (this+rule[i]).closure (c, lookup_context); 2053 } 2054 2055 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const 2056 { 2057 TRACE_COLLECT_GLYPHS (this); 2058 unsigned int num_rules = rule.len; 2059 for (unsigned int i = 0; i < num_rules; i++) 2060 (this+rule[i]).collect_glyphs (c, lookup_context); 2061 } 2062 2063 bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 2064 { 2065 TRACE_WOULD_APPLY (this); 2066 unsigned int num_rules = rule.len; 2067 for (unsigned int i = 0; i < num_rules; i++) 2068 if ((this+rule[i]).would_apply (c, lookup_context)) 2069 return_trace (true); 2070 2071 return_trace (false); 2072 } 2073 2074 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 2075 { 2076 TRACE_APPLY (this); 2077 unsigned int num_rules = rule.len; 2078 for (unsigned int i = 0; i < num_rules; i++) 2079 if ((this+rule[i]).apply (c, lookup_context)) 2080 return_trace (true); 2081 2082 return_trace (false); 2083 } 2084 2085 bool sanitize (hb_sanitize_context_t *c) const 2086 { 2087 TRACE_SANITIZE (this); 2088 return_trace (rule.sanitize (c, this)); 2089 } 2090 2091 protected: 2092 OffsetArrayOf<ChainRule> 2093 rule; /* Array of ChainRule tables 2094 * ordered by preference */ 2095 public: 2096 DEFINE_SIZE_ARRAY (2, rule); 2097 }; 2098 2099 struct ChainContextFormat1 2100 { 2101 bool intersects (const hb_set_t *glyphs) const 2102 { 2103 struct ChainContextClosureLookupContext lookup_context = { 2104 {intersects_glyph}, 2105 {nullptr, nullptr, nullptr} 2106 }; 2107 2108 unsigned int count = ruleSet.len; 2109 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) 2110 { 2111 if (unlikely (iter.get_coverage () >= count)) 2112 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ 2113 if (glyphs->has (iter.get_glyph ()) && 2114 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) 2115 return true; 2116 } 2117 return false; 2118 } 2119 2120 void closure (hb_closure_context_t *c) const 2121 { 2122 TRACE_CLOSURE (this); 2123 2124 struct ChainContextClosureLookupContext lookup_context = { 2125 {intersects_glyph}, 2126 {nullptr, nullptr, nullptr} 2127 }; 2128 2129 unsigned int count = ruleSet.len; 2130 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) 2131 { 2132 if (unlikely (iter.get_coverage () >= count)) 2133 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ 2134 if (c->glyphs->has (iter.get_glyph ())) 2135 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); 2136 } 2137 } 2138 2139 void collect_glyphs (hb_collect_glyphs_context_t *c) const 2140 { 2141 TRACE_COLLECT_GLYPHS (this); 2142 (this+coverage).add_coverage (c->input); 2143 2144 struct ChainContextCollectGlyphsLookupContext lookup_context = { 2145 {collect_glyph}, 2146 {nullptr, nullptr, nullptr} 2147 }; 2148 2149 unsigned int count = ruleSet.len; 2150 for (unsigned int i = 0; i < count; i++) 2151 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 2152 } 2153 2154 bool would_apply (hb_would_apply_context_t *c) const 2155 { 2156 TRACE_WOULD_APPLY (this); 2157 2158 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 2159 struct ChainContextApplyLookupContext lookup_context = { 2160 {match_glyph}, 2161 {nullptr, nullptr, nullptr} 2162 }; 2163 return_trace (rule_set.would_apply (c, lookup_context)); 2164 } 2165 2166 const Coverage &get_coverage () const { return this+coverage; } 2167 2168 bool apply (hb_ot_apply_context_t *c) const 2169 { 2170 TRACE_APPLY (this); 2171 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 2172 if (likely (index == NOT_COVERED)) return_trace (false); 2173 2174 const ChainRuleSet &rule_set = this+ruleSet[index]; 2175 struct ChainContextApplyLookupContext lookup_context = { 2176 {match_glyph}, 2177 {nullptr, nullptr, nullptr} 2178 }; 2179 return_trace (rule_set.apply (c, lookup_context)); 2180 } 2181 2182 bool subset (hb_subset_context_t *c) const 2183 { 2184 TRACE_SUBSET (this); 2185 // TODO(subset) 2186 return_trace (false); 2187 } 2188 2189 bool sanitize (hb_sanitize_context_t *c) const 2190 { 2191 TRACE_SANITIZE (this); 2192 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 2193 } 2194 2195 protected: 2196 HBUINT16 format; /* Format identifier--format = 1 */ 2197 OffsetTo<Coverage> 2198 coverage; /* Offset to Coverage table--from 2199 * beginning of table */ 2200 OffsetArrayOf<ChainRuleSet> 2201 ruleSet; /* Array of ChainRuleSet tables 2202 * ordered by Coverage Index */ 2203 public: 2204 DEFINE_SIZE_ARRAY (6, ruleSet); 2205 }; 2206 2207 struct ChainContextFormat2 2208 { 2209 bool intersects (const hb_set_t *glyphs) const 2210 { 2211 if (!(this+coverage).intersects (glyphs)) 2212 return false; 2213 2214 const ClassDef &backtrack_class_def = this+backtrackClassDef; 2215 const ClassDef &input_class_def = this+inputClassDef; 2216 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 2217 2218 struct ChainContextClosureLookupContext lookup_context = { 2219 {intersects_class}, 2220 {&backtrack_class_def, 2221 &input_class_def, 2222 &lookahead_class_def} 2223 }; 2224 2225 unsigned int count = ruleSet.len; 2226 for (unsigned int i = 0; i < count; i++) 2227 if (input_class_def.intersects_class (glyphs, i) && 2228 (this+ruleSet[i]).intersects (glyphs, lookup_context)) 2229 return true; 2230 2231 return false; 2232 } 2233 void closure (hb_closure_context_t *c) const 2234 { 2235 TRACE_CLOSURE (this); 2236 if (!(this+coverage).intersects (c->glyphs)) 2237 return; 2238 2239 const ClassDef &backtrack_class_def = this+backtrackClassDef; 2240 const ClassDef &input_class_def = this+inputClassDef; 2241 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 2242 2243 struct ChainContextClosureLookupContext lookup_context = { 2244 {intersects_class}, 2245 {&backtrack_class_def, 2246 &input_class_def, 2247 &lookahead_class_def} 2248 }; 2249 2250 unsigned int count = ruleSet.len; 2251 for (unsigned int i = 0; i < count; i++) 2252 if (input_class_def.intersects_class (c->glyphs, i)) { 2253 const ChainRuleSet &rule_set = this+ruleSet[i]; 2254 rule_set.closure (c, lookup_context); 2255 } 2256 } 2257 2258 void collect_glyphs (hb_collect_glyphs_context_t *c) const 2259 { 2260 TRACE_COLLECT_GLYPHS (this); 2261 (this+coverage).add_coverage (c->input); 2262 2263 const ClassDef &backtrack_class_def = this+backtrackClassDef; 2264 const ClassDef &input_class_def = this+inputClassDef; 2265 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 2266 2267 struct ChainContextCollectGlyphsLookupContext lookup_context = { 2268 {collect_class}, 2269 {&backtrack_class_def, 2270 &input_class_def, 2271 &lookahead_class_def} 2272 }; 2273 2274 unsigned int count = ruleSet.len; 2275 for (unsigned int i = 0; i < count; i++) 2276 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 2277 } 2278 2279 bool would_apply (hb_would_apply_context_t *c) const 2280 { 2281 TRACE_WOULD_APPLY (this); 2282 2283 const ClassDef &backtrack_class_def = this+backtrackClassDef; 2284 const ClassDef &input_class_def = this+inputClassDef; 2285 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 2286 2287 unsigned int index = input_class_def.get_class (c->glyphs[0]); 2288 const ChainRuleSet &rule_set = this+ruleSet[index]; 2289 struct ChainContextApplyLookupContext lookup_context = { 2290 {match_class}, 2291 {&backtrack_class_def, 2292 &input_class_def, 2293 &lookahead_class_def} 2294 }; 2295 return_trace (rule_set.would_apply (c, lookup_context)); 2296 } 2297 2298 const Coverage &get_coverage () const { return this+coverage; } 2299 2300 bool apply (hb_ot_apply_context_t *c) const 2301 { 2302 TRACE_APPLY (this); 2303 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 2304 if (likely (index == NOT_COVERED)) return_trace (false); 2305 2306 const ClassDef &backtrack_class_def = this+backtrackClassDef; 2307 const ClassDef &input_class_def = this+inputClassDef; 2308 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 2309 2310 index = input_class_def.get_class (c->buffer->cur().codepoint); 2311 const ChainRuleSet &rule_set = this+ruleSet[index]; 2312 struct ChainContextApplyLookupContext lookup_context = { 2313 {match_class}, 2314 {&backtrack_class_def, 2315 &input_class_def, 2316 &lookahead_class_def} 2317 }; 2318 return_trace (rule_set.apply (c, lookup_context)); 2319 } 2320 2321 bool subset (hb_subset_context_t *c) const 2322 { 2323 TRACE_SUBSET (this); 2324 // TODO(subset) 2325 return_trace (false); 2326 } 2327 2328 bool sanitize (hb_sanitize_context_t *c) const 2329 { 2330 TRACE_SANITIZE (this); 2331 return_trace (coverage.sanitize (c, this) && 2332 backtrackClassDef.sanitize (c, this) && 2333 inputClassDef.sanitize (c, this) && 2334 lookaheadClassDef.sanitize (c, this) && 2335 ruleSet.sanitize (c, this)); 2336 } 2337 2338 protected: 2339 HBUINT16 format; /* Format identifier--format = 2 */ 2340 OffsetTo<Coverage> 2341 coverage; /* Offset to Coverage table--from 2342 * beginning of table */ 2343 OffsetTo<ClassDef> 2344 backtrackClassDef; /* Offset to glyph ClassDef table 2345 * containing backtrack sequence 2346 * data--from beginning of table */ 2347 OffsetTo<ClassDef> 2348 inputClassDef; /* Offset to glyph ClassDef 2349 * table containing input sequence 2350 * data--from beginning of table */ 2351 OffsetTo<ClassDef> 2352 lookaheadClassDef; /* Offset to glyph ClassDef table 2353 * containing lookahead sequence 2354 * data--from beginning of table */ 2355 OffsetArrayOf<ChainRuleSet> 2356 ruleSet; /* Array of ChainRuleSet tables 2357 * ordered by class */ 2358 public: 2359 DEFINE_SIZE_ARRAY (12, ruleSet); 2360 }; 2361 2362 struct ChainContextFormat3 2363 { 2364 bool intersects (const hb_set_t *glyphs) const 2365 { 2366 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2367 2368 if (!(this+input[0]).intersects (glyphs)) 2369 return false; 2370 2371 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2372 struct ChainContextClosureLookupContext lookup_context = { 2373 {intersects_coverage}, 2374 {this, this, this} 2375 }; 2376 return chain_context_intersects (glyphs, 2377 backtrack.len, (const HBUINT16 *) backtrack.arrayZ, 2378 input.len, (const HBUINT16 *) input.arrayZ + 1, 2379 lookahead.len, (const HBUINT16 *) lookahead.arrayZ, 2380 lookup_context); 2381 } 2382 2383 void closure (hb_closure_context_t *c) const 2384 { 2385 TRACE_CLOSURE (this); 2386 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2387 2388 if (!(this+input[0]).intersects (c->glyphs)) 2389 return; 2390 2391 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2392 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2393 struct ChainContextClosureLookupContext lookup_context = { 2394 {intersects_coverage}, 2395 {this, this, this} 2396 }; 2397 chain_context_closure_lookup (c, 2398 backtrack.len, (const HBUINT16 *) backtrack.arrayZ, 2399 input.len, (const HBUINT16 *) input.arrayZ + 1, 2400 lookahead.len, (const HBUINT16 *) lookahead.arrayZ, 2401 lookup.len, lookup.arrayZ, 2402 lookup_context); 2403 } 2404 2405 void collect_glyphs (hb_collect_glyphs_context_t *c) const 2406 { 2407 TRACE_COLLECT_GLYPHS (this); 2408 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2409 2410 (this+input[0]).add_coverage (c->input); 2411 2412 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2413 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2414 struct ChainContextCollectGlyphsLookupContext lookup_context = { 2415 {collect_coverage}, 2416 {this, this, this} 2417 }; 2418 chain_context_collect_glyphs_lookup (c, 2419 backtrack.len, (const HBUINT16 *) backtrack.arrayZ, 2420 input.len, (const HBUINT16 *) input.arrayZ + 1, 2421 lookahead.len, (const HBUINT16 *) lookahead.arrayZ, 2422 lookup.len, lookup.arrayZ, 2423 lookup_context); 2424 } 2425 2426 bool would_apply (hb_would_apply_context_t *c) const 2427 { 2428 TRACE_WOULD_APPLY (this); 2429 2430 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2431 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2432 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2433 struct ChainContextApplyLookupContext lookup_context = { 2434 {match_coverage}, 2435 {this, this, this} 2436 }; 2437 return_trace (chain_context_would_apply_lookup (c, 2438 backtrack.len, (const HBUINT16 *) backtrack.arrayZ, 2439 input.len, (const HBUINT16 *) input.arrayZ + 1, 2440 lookahead.len, (const HBUINT16 *) lookahead.arrayZ, 2441 lookup.len, lookup.arrayZ, lookup_context)); 2442 } 2443 2444 const Coverage &get_coverage () const 2445 { 2446 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2447 return this+input[0]; 2448 } 2449 2450 bool apply (hb_ot_apply_context_t *c) const 2451 { 2452 TRACE_APPLY (this); 2453 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2454 2455 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint); 2456 if (likely (index == NOT_COVERED)) return_trace (false); 2457 2458 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2459 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2460 struct ChainContextApplyLookupContext lookup_context = { 2461 {match_coverage}, 2462 {this, this, this} 2463 }; 2464 return_trace (chain_context_apply_lookup (c, 2465 backtrack.len, (const HBUINT16 *) backtrack.arrayZ, 2466 input.len, (const HBUINT16 *) input.arrayZ + 1, 2467 lookahead.len, (const HBUINT16 *) lookahead.arrayZ, 2468 lookup.len, lookup.arrayZ, lookup_context)); 2469 } 2470 2471 bool subset (hb_subset_context_t *c) const 2472 { 2473 TRACE_SUBSET (this); 2474 // TODO(subset) 2475 return_trace (false); 2476 } 2477 2478 bool sanitize (hb_sanitize_context_t *c) const 2479 { 2480 TRACE_SANITIZE (this); 2481 if (!backtrack.sanitize (c, this)) return_trace (false); 2482 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2483 if (!input.sanitize (c, this)) return_trace (false); 2484 if (!input.len) return_trace (false); /* To be consistent with Context. */ 2485 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2486 if (!lookahead.sanitize (c, this)) return_trace (false); 2487 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2488 return_trace (lookup.sanitize (c)); 2489 } 2490 2491 protected: 2492 HBUINT16 format; /* Format identifier--format = 3 */ 2493 OffsetArrayOf<Coverage> 2494 backtrack; /* Array of coverage tables 2495 * in backtracking sequence, in glyph 2496 * sequence order */ 2497 OffsetArrayOf<Coverage> 2498 inputX ; /* Array of coverage 2499 * tables in input sequence, in glyph 2500 * sequence order */ 2501 OffsetArrayOf<Coverage> 2502 lookaheadX; /* Array of coverage tables 2503 * in lookahead sequence, in glyph 2504 * sequence order */ 2505 ArrayOf<LookupRecord> 2506 lookupX; /* Array of LookupRecords--in 2507 * design order) */ 2508 public: 2509 DEFINE_SIZE_MIN (10); 2510 }; 2511 2512 struct ChainContext 2513 { 2514 template <typename context_t> 2515 typename context_t::return_t dispatch (context_t *c) const 2516 { 2517 TRACE_DISPATCH (this, u.format); 2518 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 2519 switch (u.format) { 2520 case 1: return_trace (c->dispatch (u.format1)); 2521 case 2: return_trace (c->dispatch (u.format2)); 2522 case 3: return_trace (c->dispatch (u.format3)); 2523 default:return_trace (c->default_return_value ()); 2524 } 2525 } 2526 2527 protected: 2528 union { 2529 HBUINT16 format; /* Format identifier */ 2530 ChainContextFormat1 format1; 2531 ChainContextFormat2 format2; 2532 ChainContextFormat3 format3; 2533 } u; 2534 }; 2535 2536 2537 template <typename T> 2538 struct ExtensionFormat1 2539 { 2540 unsigned int get_type () const { return extensionLookupType; } 2541 2542 template <typename X> 2543 const X& get_subtable () const 2544 { 2545 unsigned int offset = extensionOffset; 2546 if (unlikely (!offset)) return Null(typename T::SubTable); 2547 return StructAtOffset<typename T::SubTable> (this, offset); 2548 } 2549 2550 template <typename context_t> 2551 typename context_t::return_t dispatch (context_t *c) const 2552 { 2553 TRACE_DISPATCH (this, format); 2554 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ()); 2555 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ())); 2556 } 2557 2558 /* This is called from may_dispatch() above with hb_sanitize_context_t. */ 2559 bool sanitize (hb_sanitize_context_t *c) const 2560 { 2561 TRACE_SANITIZE (this); 2562 return_trace (c->check_struct (this) && 2563 extensionOffset != 0 && 2564 extensionLookupType != T::SubTable::Extension); 2565 } 2566 2567 protected: 2568 HBUINT16 format; /* Format identifier. Set to 1. */ 2569 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced 2570 * by ExtensionOffset (i.e. the 2571 * extension subtable). */ 2572 HBUINT32 extensionOffset; /* Offset to the extension subtable, 2573 * of lookup type subtable. */ 2574 public: 2575 DEFINE_SIZE_STATIC (8); 2576 }; 2577 2578 template <typename T> 2579 struct Extension 2580 { 2581 unsigned int get_type () const 2582 { 2583 switch (u.format) { 2584 case 1: return u.format1.get_type (); 2585 default:return 0; 2586 } 2587 } 2588 template <typename X> 2589 const X& get_subtable () const 2590 { 2591 switch (u.format) { 2592 case 1: return u.format1.template get_subtable<typename T::SubTable> (); 2593 default:return Null(typename T::SubTable); 2594 } 2595 } 2596 2597 template <typename context_t> 2598 typename context_t::return_t dispatch (context_t *c) const 2599 { 2600 TRACE_DISPATCH (this, u.format); 2601 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 2602 switch (u.format) { 2603 case 1: return_trace (u.format1.dispatch (c)); 2604 default:return_trace (c->default_return_value ()); 2605 } 2606 } 2607 2608 protected: 2609 union { 2610 HBUINT16 format; /* Format identifier */ 2611 ExtensionFormat1<T> format1; 2612 } u; 2613 }; 2614 2615 2616 /* 2617 * GSUB/GPOS Common 2618 */ 2619 2620 struct hb_ot_layout_lookup_accelerator_t 2621 { 2622 template <typename TLookup> 2623 void init (const TLookup &lookup) 2624 { 2625 digest.init (); 2626 lookup.add_coverage (&digest); 2627 2628 subtables.init (); 2629 OT::hb_get_subtables_context_t c_get_subtables (subtables); 2630 lookup.dispatch (&c_get_subtables); 2631 } 2632 void fini () { subtables.fini (); } 2633 2634 bool may_have (hb_codepoint_t g) const 2635 { return digest.may_have (g); } 2636 2637 bool apply (hb_ot_apply_context_t *c) const 2638 { 2639 for (unsigned int i = 0; i < subtables.len; i++) 2640 if (subtables[i].apply (c)) 2641 return true; 2642 return false; 2643 } 2644 2645 private: 2646 hb_set_digest_t digest; 2647 hb_get_subtables_context_t::array_t subtables; 2648 }; 2649 2650 struct GSUBGPOS 2651 { 2652 bool has_data () const { return version.to_int (); } 2653 unsigned int get_script_count () const 2654 { return (this+scriptList).len; } 2655 const Tag& get_script_tag (unsigned int i) const 2656 { return (this+scriptList).get_tag (i); } 2657 unsigned int get_script_tags (unsigned int start_offset, 2658 unsigned int *script_count /* IN/OUT */, 2659 hb_tag_t *script_tags /* OUT */) const 2660 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } 2661 const Script& get_script (unsigned int i) const 2662 { return (this+scriptList)[i]; } 2663 bool find_script_index (hb_tag_t tag, unsigned int *index) const 2664 { return (this+scriptList).find_index (tag, index); } 2665 2666 unsigned int get_feature_count () const 2667 { return (this+featureList).len; } 2668 hb_tag_t get_feature_tag (unsigned int i) const 2669 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); } 2670 unsigned int get_feature_tags (unsigned int start_offset, 2671 unsigned int *feature_count /* IN/OUT */, 2672 hb_tag_t *feature_tags /* OUT */) const 2673 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } 2674 const Feature& get_feature (unsigned int i) const 2675 { return (this+featureList)[i]; } 2676 bool find_feature_index (hb_tag_t tag, unsigned int *index) const 2677 { return (this+featureList).find_index (tag, index); } 2678 2679 unsigned int get_lookup_count () const 2680 { return (this+lookupList).len; } 2681 const Lookup& get_lookup (unsigned int i) const 2682 { return (this+lookupList)[i]; } 2683 2684 bool find_variations_index (const int *coords, unsigned int num_coords, 2685 unsigned int *index) const 2686 { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations)) 2687 .find_index (coords, num_coords, index); } 2688 const Feature& get_feature_variation (unsigned int feature_index, 2689 unsigned int variations_index) const 2690 { 2691 if (FeatureVariations::NOT_FOUND_INDEX != variations_index && 2692 version.to_int () >= 0x00010001u) 2693 { 2694 const Feature *feature = (this+featureVars).find_substitute (variations_index, 2695 feature_index); 2696 if (feature) 2697 return *feature; 2698 } 2699 return get_feature (feature_index); 2700 } 2701 2702 template <typename TLookup> 2703 bool subset (hb_subset_context_t *c) const 2704 { 2705 TRACE_SUBSET (this); 2706 struct GSUBGPOS *out = c->serializer->embed (*this); 2707 if (unlikely (!out)) return_trace (false); 2708 2709 out->scriptList.serialize_subset (c, this+scriptList, out); 2710 out->featureList.serialize_subset (c, this+featureList, out); 2711 2712 typedef OffsetListOf<TLookup> TLookupList; 2713 /* TODO Use intersects() to count how many subtables survive? */ 2714 CastR<OffsetTo<TLookupList> > (out->lookupList) 2715 .serialize_subset (c, 2716 this+CastR<const OffsetTo<TLookupList> > (lookupList), 2717 out); 2718 2719 if (version.to_int () >= 0x00010001u) 2720 out->featureVars.serialize_subset (c, this+featureVars, out); 2721 2722 return_trace (true); 2723 } 2724 2725 unsigned int get_size () const 2726 { 2727 return min_size + 2728 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0); 2729 } 2730 2731 template <typename TLookup> 2732 bool sanitize (hb_sanitize_context_t *c) const 2733 { 2734 TRACE_SANITIZE (this); 2735 typedef OffsetListOf<TLookup> TLookupList; 2736 return_trace (version.sanitize (c) && 2737 likely (version.major == 1) && 2738 scriptList.sanitize (c, this) && 2739 featureList.sanitize (c, this) && 2740 CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) && 2741 (version.to_int () < 0x00010001u || featureVars.sanitize (c, this))); 2742 } 2743 2744 template <typename T> 2745 struct accelerator_t 2746 { 2747 void init (hb_face_t *face) 2748 { 2749 this->table = hb_sanitize_context_t().reference_table<T> (face); 2750 if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face))) 2751 { 2752 hb_blob_destroy (this->table.get_blob ()); 2753 this->table = hb_blob_get_empty (); 2754 } 2755 2756 this->lookup_count = table->get_lookup_count (); 2757 2758 this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t)); 2759 if (unlikely (!this->accels)) 2760 this->lookup_count = 0; 2761 2762 for (unsigned int i = 0; i < this->lookup_count; i++) 2763 this->accels[i].init (table->get_lookup (i)); 2764 } 2765 2766 void fini () 2767 { 2768 for (unsigned int i = 0; i < this->lookup_count; i++) 2769 this->accels[i].fini (); 2770 free (this->accels); 2771 this->table.destroy (); 2772 } 2773 2774 hb_blob_ptr_t<T> table; 2775 unsigned int lookup_count; 2776 hb_ot_layout_lookup_accelerator_t *accels; 2777 }; 2778 2779 protected: 2780 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set 2781 * to 0x00010000u */ 2782 OffsetTo<ScriptList> 2783 scriptList; /* ScriptList table */ 2784 OffsetTo<FeatureList> 2785 featureList; /* FeatureList table */ 2786 OffsetTo<LookupList> 2787 lookupList; /* LookupList table */ 2788 LOffsetTo<FeatureVariations> 2789 featureVars; /* Offset to Feature Variations 2790 table--from beginning of table 2791 * (may be NULL). Introduced 2792 * in version 0x00010001. */ 2793 public: 2794 DEFINE_SIZE_MIN (10); 2795 }; 2796 2797 2798 } /* namespace OT */ 2799 2800 2801 #endif /* HB_OT_LAYOUT_GSUBGPOS_HH */ 2802