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_PRIVATE_HH 30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH 31 32 #include "hb-buffer-private.hh" 33 #include "hb-ot-layout-gdef-table.hh" 34 #include "hb-set-private.hh" 35 36 37 namespace OT { 38 39 40 41 #define TRACE_DISPATCH(this) \ 42 hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ 43 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 44 ""); 45 46 #ifndef HB_DEBUG_CLOSURE 47 #define HB_DEBUG_CLOSURE (HB_DEBUG+0) 48 #endif 49 50 #define TRACE_CLOSURE(this) \ 51 hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \ 52 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 53 ""); 54 55 struct hb_closure_context_t 56 { 57 inline const char *get_name (void) { return "CLOSURE"; } 58 static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE; 59 typedef hb_void_t return_t; 60 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); 61 template <typename T> 62 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } 63 static return_t default_return_value (void) { return HB_VOID; } 64 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } 65 return_t recurse (unsigned int lookup_index) 66 { 67 if (unlikely (nesting_level_left == 0 || !recurse_func)) 68 return default_return_value (); 69 70 nesting_level_left--; 71 recurse_func (this, lookup_index); 72 nesting_level_left++; 73 return HB_VOID; 74 } 75 76 hb_face_t *face; 77 hb_set_t *glyphs; 78 recurse_func_t recurse_func; 79 unsigned int nesting_level_left; 80 unsigned int debug_depth; 81 82 hb_closure_context_t (hb_face_t *face_, 83 hb_set_t *glyphs_, 84 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : 85 face (face_), 86 glyphs (glyphs_), 87 recurse_func (NULL), 88 nesting_level_left (nesting_level_left_), 89 debug_depth (0) {} 90 91 void set_recurse_func (recurse_func_t func) { recurse_func = func; } 92 }; 93 94 95 96 #ifndef HB_DEBUG_WOULD_APPLY 97 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) 98 #endif 99 100 #define TRACE_WOULD_APPLY(this) \ 101 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \ 102 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 103 "%d glyphs", c->len); 104 105 struct hb_would_apply_context_t 106 { 107 inline const char *get_name (void) { return "WOULD_APPLY"; } 108 static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY; 109 typedef bool return_t; 110 template <typename T> 111 inline return_t dispatch (const T &obj) { return obj.would_apply (this); } 112 static return_t default_return_value (void) { return false; } 113 bool stop_sublookup_iteration (return_t r) const { return r; } 114 115 hb_face_t *face; 116 const hb_codepoint_t *glyphs; 117 unsigned int len; 118 bool zero_context; 119 unsigned int debug_depth; 120 121 hb_would_apply_context_t (hb_face_t *face_, 122 const hb_codepoint_t *glyphs_, 123 unsigned int len_, 124 bool zero_context_) : 125 face (face_), 126 glyphs (glyphs_), 127 len (len_), 128 zero_context (zero_context_), 129 debug_depth (0) {} 130 }; 131 132 133 134 #ifndef HB_DEBUG_COLLECT_GLYPHS 135 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0) 136 #endif 137 138 #define TRACE_COLLECT_GLYPHS(this) \ 139 hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \ 140 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 141 ""); 142 143 struct hb_collect_glyphs_context_t 144 { 145 inline const char *get_name (void) { return "COLLECT_GLYPHS"; } 146 static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS; 147 typedef hb_void_t return_t; 148 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); 149 template <typename T> 150 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } 151 static return_t default_return_value (void) { return HB_VOID; } 152 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } 153 return_t recurse (unsigned int lookup_index) 154 { 155 if (unlikely (nesting_level_left == 0 || !recurse_func)) 156 return default_return_value (); 157 158 /* Note that GPOS sets recurse_func to NULL already, so it doesn't get 159 * past the previous check. For GSUB, we only want to collect the output 160 * glyphs in the recursion. If output is not requested, we can go home now. 161 * 162 * Note further, that the above is not exactly correct. A recursed lookup 163 * is allowed to match input that is not matched in the context, but that's 164 * not how most fonts are built. It's possible to relax that and recurse 165 * with all sets here if it proves to be an issue. 166 */ 167 168 if (output == hb_set_get_empty ()) 169 return HB_VOID; 170 171 hb_set_t *old_before = before; 172 hb_set_t *old_input = input; 173 hb_set_t *old_after = after; 174 before = input = after = hb_set_get_empty (); 175 176 nesting_level_left--; 177 recurse_func (this, lookup_index); 178 nesting_level_left++; 179 180 before = old_before; 181 input = old_input; 182 after = old_after; 183 184 return HB_VOID; 185 } 186 187 hb_face_t *face; 188 hb_set_t *before; 189 hb_set_t *input; 190 hb_set_t *after; 191 hb_set_t *output; 192 recurse_func_t recurse_func; 193 unsigned int nesting_level_left; 194 unsigned int debug_depth; 195 196 hb_collect_glyphs_context_t (hb_face_t *face_, 197 hb_set_t *glyphs_before, /* OUT. May be NULL */ 198 hb_set_t *glyphs_input, /* OUT. May be NULL */ 199 hb_set_t *glyphs_after, /* OUT. May be NULL */ 200 hb_set_t *glyphs_output, /* OUT. May be NULL */ 201 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : 202 face (face_), 203 before (glyphs_before ? glyphs_before : hb_set_get_empty ()), 204 input (glyphs_input ? glyphs_input : hb_set_get_empty ()), 205 after (glyphs_after ? glyphs_after : hb_set_get_empty ()), 206 output (glyphs_output ? glyphs_output : hb_set_get_empty ()), 207 recurse_func (NULL), 208 nesting_level_left (nesting_level_left_), 209 debug_depth (0) {} 210 211 void set_recurse_func (recurse_func_t func) { recurse_func = func; } 212 }; 213 214 215 216 struct hb_get_coverage_context_t 217 { 218 inline const char *get_name (void) { return "GET_COVERAGE"; } 219 static const unsigned int max_debug_depth = 0; 220 typedef const Coverage &return_t; 221 template <typename T> 222 inline return_t dispatch (const T &obj) { return obj.get_coverage (); } 223 static return_t default_return_value (void) { return Null(Coverage); } 224 225 hb_get_coverage_context_t (void) : 226 debug_depth (0) {} 227 228 unsigned int debug_depth; 229 }; 230 231 232 233 #ifndef HB_DEBUG_APPLY 234 #define HB_DEBUG_APPLY (HB_DEBUG+0) 235 #endif 236 237 #define TRACE_APPLY(this) \ 238 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ 239 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 240 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); 241 242 struct hb_apply_context_t 243 { 244 inline const char *get_name (void) { return "APPLY"; } 245 static const unsigned int max_debug_depth = HB_DEBUG_APPLY; 246 typedef bool return_t; 247 typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index); 248 template <typename T> 249 inline return_t dispatch (const T &obj) { return obj.apply (this); } 250 static return_t default_return_value (void) { return false; } 251 bool stop_sublookup_iteration (return_t r) const { return r; } 252 return_t recurse (unsigned int lookup_index) 253 { 254 if (unlikely (nesting_level_left == 0 || !recurse_func)) 255 return default_return_value (); 256 257 nesting_level_left--; 258 bool ret = recurse_func (this, lookup_index); 259 nesting_level_left++; 260 return ret; 261 } 262 263 unsigned int table_index; /* GSUB/GPOS */ 264 hb_font_t *font; 265 hb_face_t *face; 266 hb_buffer_t *buffer; 267 hb_direction_t direction; 268 hb_mask_t lookup_mask; 269 bool auto_zwj; 270 recurse_func_t recurse_func; 271 unsigned int nesting_level_left; 272 unsigned int lookup_props; 273 const GDEF &gdef; 274 bool has_glyph_classes; 275 unsigned int debug_depth; 276 277 278 hb_apply_context_t (unsigned int table_index_, 279 hb_font_t *font_, 280 hb_buffer_t *buffer_) : 281 table_index (table_index_), 282 font (font_), face (font->face), buffer (buffer_), 283 direction (buffer_->props.direction), 284 lookup_mask (1), 285 auto_zwj (true), 286 recurse_func (NULL), 287 nesting_level_left (MAX_NESTING_LEVEL), 288 lookup_props (0), 289 gdef (*hb_ot_layout_from_face (face)->gdef), 290 has_glyph_classes (gdef.has_glyph_classes ()), 291 debug_depth (0) {} 292 293 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; } 294 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; } 295 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } 296 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } 297 inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); } 298 299 struct matcher_t 300 { 301 inline matcher_t (void) : 302 lookup_props (0), 303 ignore_zwnj (false), 304 ignore_zwj (false), 305 mask (-1), 306 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */ 307 syllable arg1(0), 308 #undef arg1 309 match_func (NULL), 310 match_data (NULL) {}; 311 312 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); 313 314 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } 315 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } 316 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } 317 inline void set_mask (hb_mask_t mask_) { mask = mask_; } 318 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; } 319 inline void set_match_func (match_func_t match_func_, 320 const void *match_data_) 321 { match_func = match_func_; match_data = match_data_; } 322 323 enum may_match_t { 324 MATCH_NO, 325 MATCH_YES, 326 MATCH_MAYBE 327 }; 328 329 inline may_match_t may_match (const hb_glyph_info_t &info, 330 const USHORT *glyph_data) const 331 { 332 if (!(info.mask & mask) || 333 (syllable && syllable != info.syllable ())) 334 return MATCH_NO; 335 336 if (match_func) 337 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO; 338 339 return MATCH_MAYBE; 340 } 341 342 enum may_skip_t { 343 SKIP_NO, 344 SKIP_YES, 345 SKIP_MAYBE 346 }; 347 348 inline may_skip_t 349 may_skip (const hb_apply_context_t *c, 350 const hb_glyph_info_t &info) const 351 { 352 if (!c->check_glyph_property (&info, lookup_props)) 353 return SKIP_YES; 354 355 if (unlikely (_hb_glyph_info_is_default_ignorable (&info) && 356 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) && 357 (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) && 358 !_hb_glyph_info_ligated (&info))) 359 return SKIP_MAYBE; 360 361 return SKIP_NO; 362 } 363 364 protected: 365 unsigned int lookup_props; 366 bool ignore_zwnj; 367 bool ignore_zwj; 368 hb_mask_t mask; 369 uint8_t syllable; 370 match_func_t match_func; 371 const void *match_data; 372 }; 373 374 struct skipping_forward_iterator_t 375 { 376 inline skipping_forward_iterator_t (hb_apply_context_t *c_, 377 unsigned int start_index_, 378 unsigned int num_items_, 379 bool context_match = false) : 380 idx (start_index_), 381 c (c_), 382 match_glyph_data (NULL), 383 num_items (num_items_), 384 end (c->buffer->len) 385 { 386 matcher.set_lookup_props (c->lookup_props); 387 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ 388 matcher.set_ignore_zwnj (context_match || c->table_index == 1); 389 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ 390 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj); 391 if (!context_match) 392 matcher.set_mask (c->lookup_mask); 393 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); 394 } 395 inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } 396 inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); } 397 inline void set_match_func (matcher_t::match_func_t match_func, 398 const void *match_data, 399 const USHORT glyph_data[]) 400 { 401 matcher.set_match_func (match_func, match_data); 402 match_glyph_data = glyph_data; 403 } 404 405 inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); } 406 inline void reject (void) { num_items++; match_glyph_data--; } 407 inline bool next (void) 408 { 409 assert (num_items > 0); 410 while (!has_no_chance ()) 411 { 412 idx++; 413 const hb_glyph_info_t &info = c->buffer->info[idx]; 414 415 matcher_t::may_skip_t skip = matcher.may_skip (c, info); 416 if (unlikely (skip == matcher_t::SKIP_YES)) 417 continue; 418 419 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); 420 if (match == matcher_t::MATCH_YES || 421 (match == matcher_t::MATCH_MAYBE && 422 skip == matcher_t::SKIP_NO)) 423 { 424 num_items--; 425 match_glyph_data++; 426 return true; 427 } 428 429 if (skip == matcher_t::SKIP_NO) 430 return false; 431 } 432 return false; 433 } 434 435 unsigned int idx; 436 protected: 437 hb_apply_context_t *c; 438 matcher_t matcher; 439 const USHORT *match_glyph_data; 440 441 unsigned int num_items; 442 unsigned int end; 443 }; 444 445 struct skipping_backward_iterator_t 446 { 447 inline skipping_backward_iterator_t (hb_apply_context_t *c_, 448 unsigned int start_index_, 449 unsigned int num_items_, 450 bool context_match = false) : 451 idx (start_index_), 452 c (c_), 453 match_glyph_data (NULL), 454 num_items (num_items_) 455 { 456 matcher.set_lookup_props (c->lookup_props); 457 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ 458 matcher.set_ignore_zwnj (context_match || c->table_index == 1); 459 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ 460 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj); 461 if (!context_match) 462 matcher.set_mask (c->lookup_mask); 463 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); 464 } 465 inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } 466 inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); } 467 inline void set_match_func (matcher_t::match_func_t match_func, 468 const void *match_data, 469 const USHORT glyph_data[]) 470 { 471 matcher.set_match_func (match_func, match_data); 472 match_glyph_data = glyph_data; 473 } 474 475 inline bool has_no_chance (void) const { return unlikely (idx < num_items); } 476 inline void reject (void) { num_items++; } 477 inline bool prev (void) 478 { 479 assert (num_items > 0); 480 while (!has_no_chance ()) 481 { 482 idx--; 483 const hb_glyph_info_t &info = c->buffer->out_info[idx]; 484 485 matcher_t::may_skip_t skip = matcher.may_skip (c, info); 486 if (unlikely (skip == matcher_t::SKIP_YES)) 487 continue; 488 489 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); 490 if (match == matcher_t::MATCH_YES || 491 (match == matcher_t::MATCH_MAYBE && 492 skip == matcher_t::SKIP_NO)) 493 { 494 num_items--; 495 match_glyph_data++; 496 return true; 497 } 498 499 if (skip == matcher_t::SKIP_NO) 500 return false; 501 } 502 return false; 503 } 504 505 unsigned int idx; 506 protected: 507 hb_apply_context_t *c; 508 matcher_t matcher; 509 const USHORT *match_glyph_data; 510 511 unsigned int num_items; 512 }; 513 514 inline bool 515 match_properties_mark (hb_codepoint_t glyph, 516 unsigned int glyph_props, 517 unsigned int lookup_props) const 518 { 519 /* If using mark filtering sets, the high short of 520 * lookup_props has the set index. 521 */ 522 if (lookup_props & LookupFlag::UseMarkFilteringSet) 523 return gdef.mark_set_covers (lookup_props >> 16, glyph); 524 525 /* The second byte of lookup_props has the meaning 526 * "ignore marks of attachment type different than 527 * the attachment type specified." 528 */ 529 if (lookup_props & LookupFlag::MarkAttachmentType) 530 return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType); 531 532 return true; 533 } 534 535 inline bool 536 check_glyph_property (const hb_glyph_info_t *info, 537 unsigned int lookup_props) const 538 { 539 hb_codepoint_t glyph = info->codepoint; 540 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info); 541 542 /* Not covered, if, for example, glyph class is ligature and 543 * lookup_props includes LookupFlags::IgnoreLigatures 544 */ 545 if (glyph_props & lookup_props & LookupFlag::IgnoreFlags) 546 return false; 547 548 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) 549 return match_properties_mark (glyph, glyph_props, lookup_props); 550 551 return true; 552 } 553 554 inline void _set_glyph_props (hb_codepoint_t glyph_index, 555 unsigned int class_guess = 0, 556 bool ligature = false, 557 bool component = false) const 558 { 559 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) & 560 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; 561 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; 562 if (ligature) 563 { 564 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; 565 /* In the only place that the MULTIPLIED bit is used, Uniscribe 566 * seems to only care about the "last" transformation between 567 * Ligature and Multiple substitions. Ie. if you ligate, expand, 568 * and ligate again, it forgives the multiplication and acts as 569 * if only ligation happened. As such, clear MULTIPLIED bit. 570 */ 571 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; 572 } 573 if (component) 574 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; 575 if (likely (has_glyph_classes)) 576 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index)); 577 else if (class_guess) 578 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess); 579 } 580 581 inline void replace_glyph (hb_codepoint_t glyph_index) const 582 { 583 _set_glyph_props (glyph_index); 584 buffer->replace_glyph (glyph_index); 585 } 586 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const 587 { 588 _set_glyph_props (glyph_index); 589 buffer->cur().codepoint = glyph_index; 590 } 591 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index, 592 unsigned int class_guess) const 593 { 594 _set_glyph_props (glyph_index, class_guess, true); 595 buffer->replace_glyph (glyph_index); 596 } 597 inline void output_glyph_for_component (hb_codepoint_t glyph_index, 598 unsigned int class_guess) const 599 { 600 _set_glyph_props (glyph_index, class_guess, false, true); 601 buffer->output_glyph (glyph_index); 602 } 603 }; 604 605 606 607 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); 608 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); 609 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); 610 611 struct ContextClosureFuncs 612 { 613 intersects_func_t intersects; 614 }; 615 struct ContextCollectGlyphsFuncs 616 { 617 collect_glyphs_func_t collect; 618 }; 619 struct ContextApplyFuncs 620 { 621 match_func_t match; 622 }; 623 624 625 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) 626 { 627 return glyphs->has (value); 628 } 629 static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data) 630 { 631 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 632 return class_def.intersects_class (glyphs, value); 633 } 634 static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) 635 { 636 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 637 return (data+coverage).intersects (glyphs); 638 } 639 640 static inline bool intersects_array (hb_closure_context_t *c, 641 unsigned int count, 642 const USHORT values[], 643 intersects_func_t intersects_func, 644 const void *intersects_data) 645 { 646 for (unsigned int i = 0; i < count; i++) 647 if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) 648 return false; 649 return true; 650 } 651 652 653 static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) 654 { 655 glyphs->add (value); 656 } 657 static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data) 658 { 659 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 660 class_def.add_class (glyphs, value); 661 } 662 static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) 663 { 664 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 665 (data+coverage).add_coverage (glyphs); 666 } 667 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, 668 hb_set_t *glyphs, 669 unsigned int count, 670 const USHORT values[], 671 collect_glyphs_func_t collect_func, 672 const void *collect_data) 673 { 674 for (unsigned int i = 0; i < count; i++) 675 collect_func (glyphs, values[i], collect_data); 676 } 677 678 679 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED) 680 { 681 return glyph_id == value; 682 } 683 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 684 { 685 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 686 return class_def.get_class (glyph_id) == value; 687 } 688 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 689 { 690 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 691 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; 692 } 693 694 static inline bool would_match_input (hb_would_apply_context_t *c, 695 unsigned int count, /* Including the first glyph (not matched) */ 696 const USHORT input[], /* Array of input values--start with second glyph */ 697 match_func_t match_func, 698 const void *match_data) 699 { 700 if (count != c->len) 701 return false; 702 703 for (unsigned int i = 1; i < count; i++) 704 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data))) 705 return false; 706 707 return true; 708 } 709 static inline bool match_input (hb_apply_context_t *c, 710 unsigned int count, /* Including the first glyph (not matched) */ 711 const USHORT input[], /* Array of input values--start with second glyph */ 712 match_func_t match_func, 713 const void *match_data, 714 unsigned int *end_offset, 715 unsigned int match_positions[MAX_CONTEXT_LENGTH], 716 bool *p_is_mark_ligature = NULL, 717 unsigned int *p_total_component_count = NULL) 718 { 719 TRACE_APPLY (NULL); 720 721 if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false); 722 723 hb_buffer_t *buffer = c->buffer; 724 725 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1); 726 skippy_iter.set_match_func (match_func, match_data, input); 727 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 728 729 /* 730 * This is perhaps the trickiest part of OpenType... Remarks: 731 * 732 * - If all components of the ligature were marks, we call this a mark ligature. 733 * 734 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize 735 * it as a ligature glyph. 736 * 737 * - Ligatures cannot be formed across glyphs attached to different components 738 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and 739 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother. 740 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o 741 * There is an exception to this: If a ligature tries ligating with marks that 742 * belong to it itself, go ahead, assuming that the font designer knows what 743 * they are doing (otherwise it can break Indic stuff when a matra wants to 744 * ligate with a conjunct...) 745 */ 746 747 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur()); 748 749 unsigned int total_component_count = 0; 750 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 751 752 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 753 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); 754 755 match_positions[0] = buffer->idx; 756 for (unsigned int i = 1; i < count; i++) 757 { 758 if (!skippy_iter.next ()) return TRACE_RETURN (false); 759 760 match_positions[i] = skippy_iter.idx; 761 762 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); 763 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); 764 765 if (first_lig_id && first_lig_comp) { 766 /* If first component was attached to a previous ligature component, 767 * all subsequent components should be attached to the same ligature 768 * component, otherwise we shouldn't ligate them. */ 769 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) 770 return TRACE_RETURN (false); 771 } else { 772 /* If first component was NOT attached to a previous ligature component, 773 * all subsequent components should also NOT be attached to any ligature 774 * component, unless they are attached to the first component itself! */ 775 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id)) 776 return TRACE_RETURN (false); 777 } 778 779 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]); 780 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); 781 } 782 783 *end_offset = skippy_iter.idx - buffer->idx + 1; 784 785 if (p_is_mark_ligature) 786 *p_is_mark_ligature = is_mark_ligature; 787 788 if (p_total_component_count) 789 *p_total_component_count = total_component_count; 790 791 return TRACE_RETURN (true); 792 } 793 static inline void ligate_input (hb_apply_context_t *c, 794 unsigned int count, /* Including the first glyph */ 795 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ 796 unsigned int match_length, 797 hb_codepoint_t lig_glyph, 798 bool is_mark_ligature, 799 unsigned int total_component_count) 800 { 801 TRACE_APPLY (NULL); 802 803 hb_buffer_t *buffer = c->buffer; 804 805 buffer->merge_clusters (buffer->idx, buffer->idx + match_length); 806 807 /* 808 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave 809 * the ligature to keep its old ligature id. This will allow it to attach to 810 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH, 811 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a 812 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature 813 * later, we don't want them to lose their ligature id/component, otherwise 814 * GPOS will fail to correctly position the mark ligature on top of the 815 * LAM,LAM,HEH ligature. See: 816 * https://bugzilla.gnome.org/show_bug.cgi?id=676343 817 * 818 * - If a ligature is formed of components that some of which are also ligatures 819 * themselves, and those ligature components had marks attached to *their* 820 * components, we have to attach the marks to the new ligature component 821 * positions! Now *that*'s tricky! And these marks may be following the 822 * last component of the whole sequence, so we should loop forward looking 823 * for them and update them. 824 * 825 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a 826 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature 827 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature 828 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to 829 * the new ligature with a component value of 2. 830 * 831 * This in fact happened to a font... See: 832 * https://bugzilla.gnome.org/show_bug.cgi?id=437633 833 */ 834 835 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; 836 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer); 837 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 838 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 839 unsigned int components_so_far = last_num_components; 840 841 if (!is_mark_ligature) 842 { 843 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count); 844 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 845 { 846 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER); 847 _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0); 848 } 849 } 850 c->replace_glyph_with_ligature (lig_glyph, klass); 851 852 for (unsigned int i = 1; i < count; i++) 853 { 854 while (buffer->idx < match_positions[i]) 855 { 856 if (!is_mark_ligature) { 857 unsigned int new_lig_comp = components_so_far - last_num_components + 858 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components); 859 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp); 860 } 861 buffer->next_glyph (); 862 } 863 864 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 865 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 866 components_so_far += last_num_components; 867 868 /* Skip the base glyph */ 869 buffer->idx++; 870 } 871 872 if (!is_mark_ligature && last_lig_id) { 873 /* Re-adjust components for any marks following. */ 874 for (unsigned int i = buffer->idx; i < buffer->len; i++) { 875 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) { 876 unsigned int new_lig_comp = components_so_far - last_num_components + 877 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components); 878 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp); 879 } else 880 break; 881 } 882 } 883 TRACE_RETURN (true); 884 } 885 886 static inline bool match_backtrack (hb_apply_context_t *c, 887 unsigned int count, 888 const USHORT backtrack[], 889 match_func_t match_func, 890 const void *match_data) 891 { 892 TRACE_APPLY (NULL); 893 894 hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true); 895 skippy_iter.set_match_func (match_func, match_data, backtrack); 896 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 897 898 for (unsigned int i = 0; i < count; i++) 899 if (!skippy_iter.prev ()) 900 return TRACE_RETURN (false); 901 902 return TRACE_RETURN (true); 903 } 904 905 static inline bool match_lookahead (hb_apply_context_t *c, 906 unsigned int count, 907 const USHORT lookahead[], 908 match_func_t match_func, 909 const void *match_data, 910 unsigned int offset) 911 { 912 TRACE_APPLY (NULL); 913 914 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true); 915 skippy_iter.set_match_func (match_func, match_data, lookahead); 916 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 917 918 for (unsigned int i = 0; i < count; i++) 919 if (!skippy_iter.next ()) 920 return TRACE_RETURN (false); 921 922 return TRACE_RETURN (true); 923 } 924 925 926 927 struct LookupRecord 928 { 929 inline bool sanitize (hb_sanitize_context_t *c) { 930 TRACE_SANITIZE (this); 931 return TRACE_RETURN (c->check_struct (this)); 932 } 933 934 USHORT sequenceIndex; /* Index into current glyph 935 * sequence--first glyph = 0 */ 936 USHORT lookupListIndex; /* Lookup to apply to that 937 * position--zero--based */ 938 public: 939 DEFINE_SIZE_STATIC (4); 940 }; 941 942 943 template <typename context_t> 944 static inline void recurse_lookups (context_t *c, 945 unsigned int lookupCount, 946 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) 947 { 948 for (unsigned int i = 0; i < lookupCount; i++) 949 c->recurse (lookupRecord[i].lookupListIndex); 950 } 951 952 static inline bool apply_lookup (hb_apply_context_t *c, 953 unsigned int count, /* Including the first glyph */ 954 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ 955 unsigned int lookupCount, 956 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ 957 unsigned int match_length) 958 { 959 TRACE_APPLY (NULL); 960 961 hb_buffer_t *buffer = c->buffer; 962 unsigned int end; 963 964 /* All positions are distance from beginning of *output* buffer. 965 * Adjust. */ 966 { 967 unsigned int bl = buffer->backtrack_len (); 968 end = bl + match_length; 969 970 int delta = bl - buffer->idx; 971 /* Convert positions to new indexing. */ 972 for (unsigned int j = 0; j < count; j++) 973 match_positions[j] += delta; 974 } 975 976 for (unsigned int i = 0; i < lookupCount; i++) 977 { 978 unsigned int idx = lookupRecord[i].sequenceIndex; 979 if (idx >= count) 980 continue; 981 982 buffer->move_to (match_positions[idx]); 983 984 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); 985 if (!c->recurse (lookupRecord[i].lookupListIndex)) 986 continue; 987 988 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len (); 989 int delta = new_len - orig_len; 990 991 if (!delta) 992 continue; 993 994 /* Recursed lookup changed buffer len. Adjust. */ 995 996 /* end can't go back past the current match position. 997 * Note: this is only true because we do NOT allow MultipleSubst 998 * with zero sequence len. */ 999 end = MAX ((int) match_positions[idx] + 1, int (end) + delta); 1000 1001 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */ 1002 1003 if (delta > 0) 1004 { 1005 if (unlikely (delta + count > MAX_CONTEXT_LENGTH)) 1006 break; 1007 } 1008 else 1009 { 1010 /* NOTE: delta is negative. */ 1011 delta = MAX (delta, (int) next - (int) count); 1012 next -= delta; 1013 } 1014 1015 /* Shift! */ 1016 memmove (match_positions + next + delta, match_positions + next, 1017 (count - next) * sizeof (match_positions[0])); 1018 next += delta; 1019 count += delta; 1020 1021 /* Fill in new entries. */ 1022 for (unsigned int j = idx + 1; j < next; j++) 1023 match_positions[j] = match_positions[j - 1] + 1; 1024 1025 /* And fixup the rest. */ 1026 for (; next < count; next++) 1027 match_positions[next] += delta; 1028 } 1029 1030 buffer->move_to (end); 1031 1032 return TRACE_RETURN (true); 1033 } 1034 1035 1036 1037 /* Contextual lookups */ 1038 1039 struct ContextClosureLookupContext 1040 { 1041 ContextClosureFuncs funcs; 1042 const void *intersects_data; 1043 }; 1044 1045 struct ContextCollectGlyphsLookupContext 1046 { 1047 ContextCollectGlyphsFuncs funcs; 1048 const void *collect_data; 1049 }; 1050 1051 struct ContextApplyLookupContext 1052 { 1053 ContextApplyFuncs funcs; 1054 const void *match_data; 1055 }; 1056 1057 static inline void context_closure_lookup (hb_closure_context_t *c, 1058 unsigned int inputCount, /* Including the first glyph (not matched) */ 1059 const USHORT input[], /* Array of input values--start with second glyph */ 1060 unsigned int lookupCount, 1061 const LookupRecord lookupRecord[], 1062 ContextClosureLookupContext &lookup_context) 1063 { 1064 if (intersects_array (c, 1065 inputCount ? inputCount - 1 : 0, input, 1066 lookup_context.funcs.intersects, lookup_context.intersects_data)) 1067 recurse_lookups (c, 1068 lookupCount, lookupRecord); 1069 } 1070 1071 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 1072 unsigned int inputCount, /* Including the first glyph (not matched) */ 1073 const USHORT input[], /* Array of input values--start with second glyph */ 1074 unsigned int lookupCount, 1075 const LookupRecord lookupRecord[], 1076 ContextCollectGlyphsLookupContext &lookup_context) 1077 { 1078 collect_array (c, c->input, 1079 inputCount ? inputCount - 1 : 0, input, 1080 lookup_context.funcs.collect, lookup_context.collect_data); 1081 recurse_lookups (c, 1082 lookupCount, lookupRecord); 1083 } 1084 1085 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, 1086 unsigned int inputCount, /* Including the first glyph (not matched) */ 1087 const USHORT input[], /* Array of input values--start with second glyph */ 1088 unsigned int lookupCount HB_UNUSED, 1089 const LookupRecord lookupRecord[] HB_UNUSED, 1090 ContextApplyLookupContext &lookup_context) 1091 { 1092 return would_match_input (c, 1093 inputCount, input, 1094 lookup_context.funcs.match, lookup_context.match_data); 1095 } 1096 static inline bool context_apply_lookup (hb_apply_context_t *c, 1097 unsigned int inputCount, /* Including the first glyph (not matched) */ 1098 const USHORT input[], /* Array of input values--start with second glyph */ 1099 unsigned int lookupCount, 1100 const LookupRecord lookupRecord[], 1101 ContextApplyLookupContext &lookup_context) 1102 { 1103 unsigned int match_length = 0; 1104 unsigned int match_positions[MAX_CONTEXT_LENGTH]; 1105 return match_input (c, 1106 inputCount, input, 1107 lookup_context.funcs.match, lookup_context.match_data, 1108 &match_length, match_positions) 1109 && apply_lookup (c, 1110 inputCount, match_positions, 1111 lookupCount, lookupRecord, 1112 match_length); 1113 } 1114 1115 struct Rule 1116 { 1117 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 1118 { 1119 TRACE_CLOSURE (this); 1120 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1121 context_closure_lookup (c, 1122 inputCount, input, 1123 lookupCount, lookupRecord, 1124 lookup_context); 1125 } 1126 1127 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const 1128 { 1129 TRACE_COLLECT_GLYPHS (this); 1130 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1131 context_collect_glyphs_lookup (c, 1132 inputCount, input, 1133 lookupCount, lookupRecord, 1134 lookup_context); 1135 } 1136 1137 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1138 { 1139 TRACE_WOULD_APPLY (this); 1140 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1141 return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); 1142 } 1143 1144 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1145 { 1146 TRACE_APPLY (this); 1147 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1148 return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); 1149 } 1150 1151 public: 1152 inline bool sanitize (hb_sanitize_context_t *c) { 1153 TRACE_SANITIZE (this); 1154 return inputCount.sanitize (c) 1155 && lookupCount.sanitize (c) 1156 && c->check_range (input, 1157 input[0].static_size * inputCount 1158 + lookupRecordX[0].static_size * lookupCount); 1159 } 1160 1161 protected: 1162 USHORT inputCount; /* Total number of glyphs in input 1163 * glyph sequence--includes the first 1164 * glyph */ 1165 USHORT lookupCount; /* Number of LookupRecords */ 1166 USHORT input[VAR]; /* Array of match inputs--start with 1167 * second glyph */ 1168 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 1169 * design order */ 1170 public: 1171 DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX); 1172 }; 1173 1174 struct RuleSet 1175 { 1176 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 1177 { 1178 TRACE_CLOSURE (this); 1179 unsigned int num_rules = rule.len; 1180 for (unsigned int i = 0; i < num_rules; i++) 1181 (this+rule[i]).closure (c, lookup_context); 1182 } 1183 1184 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const 1185 { 1186 TRACE_COLLECT_GLYPHS (this); 1187 unsigned int num_rules = rule.len; 1188 for (unsigned int i = 0; i < num_rules; i++) 1189 (this+rule[i]).collect_glyphs (c, lookup_context); 1190 } 1191 1192 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1193 { 1194 TRACE_WOULD_APPLY (this); 1195 unsigned int num_rules = rule.len; 1196 for (unsigned int i = 0; i < num_rules; i++) 1197 { 1198 if ((this+rule[i]).would_apply (c, lookup_context)) 1199 return TRACE_RETURN (true); 1200 } 1201 return TRACE_RETURN (false); 1202 } 1203 1204 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1205 { 1206 TRACE_APPLY (this); 1207 unsigned int num_rules = rule.len; 1208 for (unsigned int i = 0; i < num_rules; i++) 1209 { 1210 if ((this+rule[i]).apply (c, lookup_context)) 1211 return TRACE_RETURN (true); 1212 } 1213 return TRACE_RETURN (false); 1214 } 1215 1216 inline bool sanitize (hb_sanitize_context_t *c) { 1217 TRACE_SANITIZE (this); 1218 return TRACE_RETURN (rule.sanitize (c, this)); 1219 } 1220 1221 protected: 1222 OffsetArrayOf<Rule> 1223 rule; /* Array of Rule tables 1224 * ordered by preference */ 1225 public: 1226 DEFINE_SIZE_ARRAY (2, rule); 1227 }; 1228 1229 1230 struct ContextFormat1 1231 { 1232 inline void closure (hb_closure_context_t *c) const 1233 { 1234 TRACE_CLOSURE (this); 1235 1236 const Coverage &cov = (this+coverage); 1237 1238 struct ContextClosureLookupContext lookup_context = { 1239 {intersects_glyph}, 1240 NULL 1241 }; 1242 1243 unsigned int count = ruleSet.len; 1244 for (unsigned int i = 0; i < count; i++) 1245 if (cov.intersects_coverage (c->glyphs, i)) { 1246 const RuleSet &rule_set = this+ruleSet[i]; 1247 rule_set.closure (c, lookup_context); 1248 } 1249 } 1250 1251 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1252 { 1253 TRACE_COLLECT_GLYPHS (this); 1254 (this+coverage).add_coverage (c->input); 1255 1256 struct ContextCollectGlyphsLookupContext lookup_context = { 1257 {collect_glyph}, 1258 NULL 1259 }; 1260 1261 unsigned int count = ruleSet.len; 1262 for (unsigned int i = 0; i < count; i++) 1263 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1264 } 1265 1266 inline bool would_apply (hb_would_apply_context_t *c) const 1267 { 1268 TRACE_WOULD_APPLY (this); 1269 1270 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 1271 struct ContextApplyLookupContext lookup_context = { 1272 {match_glyph}, 1273 NULL 1274 }; 1275 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1276 } 1277 1278 inline const Coverage &get_coverage (void) const 1279 { 1280 return this+coverage; 1281 } 1282 1283 inline bool apply (hb_apply_context_t *c) const 1284 { 1285 TRACE_APPLY (this); 1286 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1287 if (likely (index == NOT_COVERED)) 1288 return TRACE_RETURN (false); 1289 1290 const RuleSet &rule_set = this+ruleSet[index]; 1291 struct ContextApplyLookupContext lookup_context = { 1292 {match_glyph}, 1293 NULL 1294 }; 1295 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1296 } 1297 1298 inline bool sanitize (hb_sanitize_context_t *c) { 1299 TRACE_SANITIZE (this); 1300 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1301 } 1302 1303 protected: 1304 USHORT format; /* Format identifier--format = 1 */ 1305 OffsetTo<Coverage> 1306 coverage; /* Offset to Coverage table--from 1307 * beginning of table */ 1308 OffsetArrayOf<RuleSet> 1309 ruleSet; /* Array of RuleSet tables 1310 * ordered by Coverage Index */ 1311 public: 1312 DEFINE_SIZE_ARRAY (6, ruleSet); 1313 }; 1314 1315 1316 struct ContextFormat2 1317 { 1318 inline void closure (hb_closure_context_t *c) const 1319 { 1320 TRACE_CLOSURE (this); 1321 if (!(this+coverage).intersects (c->glyphs)) 1322 return; 1323 1324 const ClassDef &class_def = this+classDef; 1325 1326 struct ContextClosureLookupContext lookup_context = { 1327 {intersects_class}, 1328 &class_def 1329 }; 1330 1331 unsigned int count = ruleSet.len; 1332 for (unsigned int i = 0; i < count; i++) 1333 if (class_def.intersects_class (c->glyphs, i)) { 1334 const RuleSet &rule_set = this+ruleSet[i]; 1335 rule_set.closure (c, lookup_context); 1336 } 1337 } 1338 1339 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1340 { 1341 TRACE_COLLECT_GLYPHS (this); 1342 (this+coverage).add_coverage (c->input); 1343 1344 const ClassDef &class_def = this+classDef; 1345 struct ContextCollectGlyphsLookupContext lookup_context = { 1346 {collect_class}, 1347 &class_def 1348 }; 1349 1350 unsigned int count = ruleSet.len; 1351 for (unsigned int i = 0; i < count; i++) 1352 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1353 } 1354 1355 inline bool would_apply (hb_would_apply_context_t *c) const 1356 { 1357 TRACE_WOULD_APPLY (this); 1358 1359 const ClassDef &class_def = this+classDef; 1360 unsigned int index = class_def.get_class (c->glyphs[0]); 1361 const RuleSet &rule_set = this+ruleSet[index]; 1362 struct ContextApplyLookupContext lookup_context = { 1363 {match_class}, 1364 &class_def 1365 }; 1366 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1367 } 1368 1369 inline const Coverage &get_coverage (void) const 1370 { 1371 return this+coverage; 1372 } 1373 1374 inline bool apply (hb_apply_context_t *c) const 1375 { 1376 TRACE_APPLY (this); 1377 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1378 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1379 1380 const ClassDef &class_def = this+classDef; 1381 index = class_def.get_class (c->buffer->cur().codepoint); 1382 const RuleSet &rule_set = this+ruleSet[index]; 1383 struct ContextApplyLookupContext lookup_context = { 1384 {match_class}, 1385 &class_def 1386 }; 1387 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1388 } 1389 1390 inline bool sanitize (hb_sanitize_context_t *c) { 1391 TRACE_SANITIZE (this); 1392 return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); 1393 } 1394 1395 protected: 1396 USHORT format; /* Format identifier--format = 2 */ 1397 OffsetTo<Coverage> 1398 coverage; /* Offset to Coverage table--from 1399 * beginning of table */ 1400 OffsetTo<ClassDef> 1401 classDef; /* Offset to glyph ClassDef table--from 1402 * beginning of table */ 1403 OffsetArrayOf<RuleSet> 1404 ruleSet; /* Array of RuleSet tables 1405 * ordered by class */ 1406 public: 1407 DEFINE_SIZE_ARRAY (8, ruleSet); 1408 }; 1409 1410 1411 struct ContextFormat3 1412 { 1413 inline void closure (hb_closure_context_t *c) const 1414 { 1415 TRACE_CLOSURE (this); 1416 if (!(this+coverage[0]).intersects (c->glyphs)) 1417 return; 1418 1419 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1420 struct ContextClosureLookupContext lookup_context = { 1421 {intersects_coverage}, 1422 this 1423 }; 1424 context_closure_lookup (c, 1425 glyphCount, (const USHORT *) (coverage + 1), 1426 lookupCount, lookupRecord, 1427 lookup_context); 1428 } 1429 1430 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1431 { 1432 TRACE_COLLECT_GLYPHS (this); 1433 (this+coverage[0]).add_coverage (c->input); 1434 1435 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1436 struct ContextCollectGlyphsLookupContext lookup_context = { 1437 {collect_coverage}, 1438 this 1439 }; 1440 1441 context_collect_glyphs_lookup (c, 1442 glyphCount, (const USHORT *) (coverage + 1), 1443 lookupCount, lookupRecord, 1444 lookup_context); 1445 } 1446 1447 inline bool would_apply (hb_would_apply_context_t *c) const 1448 { 1449 TRACE_WOULD_APPLY (this); 1450 1451 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1452 struct ContextApplyLookupContext lookup_context = { 1453 {match_coverage}, 1454 this 1455 }; 1456 return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); 1457 } 1458 1459 inline const Coverage &get_coverage (void) const 1460 { 1461 return this+coverage[0]; 1462 } 1463 1464 inline bool apply (hb_apply_context_t *c) const 1465 { 1466 TRACE_APPLY (this); 1467 unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint); 1468 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1469 1470 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1471 struct ContextApplyLookupContext lookup_context = { 1472 {match_coverage}, 1473 this 1474 }; 1475 return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); 1476 } 1477 1478 inline bool sanitize (hb_sanitize_context_t *c) { 1479 TRACE_SANITIZE (this); 1480 if (!c->check_struct (this)) return TRACE_RETURN (false); 1481 unsigned int count = glyphCount; 1482 if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false); 1483 for (unsigned int i = 0; i < count; i++) 1484 if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false); 1485 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count); 1486 return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); 1487 } 1488 1489 protected: 1490 USHORT format; /* Format identifier--format = 3 */ 1491 USHORT glyphCount; /* Number of glyphs in the input glyph 1492 * sequence */ 1493 USHORT lookupCount; /* Number of LookupRecords */ 1494 OffsetTo<Coverage> 1495 coverage[VAR]; /* Array of offsets to Coverage 1496 * table in glyph sequence order */ 1497 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 1498 * design order */ 1499 public: 1500 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX); 1501 }; 1502 1503 struct Context 1504 { 1505 template <typename context_t> 1506 inline typename context_t::return_t dispatch (context_t *c) const 1507 { 1508 TRACE_DISPATCH (this); 1509 switch (u.format) { 1510 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1511 case 2: return TRACE_RETURN (c->dispatch (u.format2)); 1512 case 3: return TRACE_RETURN (c->dispatch (u.format3)); 1513 default:return TRACE_RETURN (c->default_return_value ()); 1514 } 1515 } 1516 1517 inline bool sanitize (hb_sanitize_context_t *c) { 1518 TRACE_SANITIZE (this); 1519 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1520 switch (u.format) { 1521 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1522 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1523 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1524 default:return TRACE_RETURN (true); 1525 } 1526 } 1527 1528 protected: 1529 union { 1530 USHORT format; /* Format identifier */ 1531 ContextFormat1 format1; 1532 ContextFormat2 format2; 1533 ContextFormat3 format3; 1534 } u; 1535 }; 1536 1537 1538 /* Chaining Contextual lookups */ 1539 1540 struct ChainContextClosureLookupContext 1541 { 1542 ContextClosureFuncs funcs; 1543 const void *intersects_data[3]; 1544 }; 1545 1546 struct ChainContextCollectGlyphsLookupContext 1547 { 1548 ContextCollectGlyphsFuncs funcs; 1549 const void *collect_data[3]; 1550 }; 1551 1552 struct ChainContextApplyLookupContext 1553 { 1554 ContextApplyFuncs funcs; 1555 const void *match_data[3]; 1556 }; 1557 1558 static inline void chain_context_closure_lookup (hb_closure_context_t *c, 1559 unsigned int backtrackCount, 1560 const USHORT backtrack[], 1561 unsigned int inputCount, /* Including the first glyph (not matched) */ 1562 const USHORT input[], /* Array of input values--start with second glyph */ 1563 unsigned int lookaheadCount, 1564 const USHORT lookahead[], 1565 unsigned int lookupCount, 1566 const LookupRecord lookupRecord[], 1567 ChainContextClosureLookupContext &lookup_context) 1568 { 1569 if (intersects_array (c, 1570 backtrackCount, backtrack, 1571 lookup_context.funcs.intersects, lookup_context.intersects_data[0]) 1572 && intersects_array (c, 1573 inputCount ? inputCount - 1 : 0, input, 1574 lookup_context.funcs.intersects, lookup_context.intersects_data[1]) 1575 && intersects_array (c, 1576 lookaheadCount, lookahead, 1577 lookup_context.funcs.intersects, lookup_context.intersects_data[2])) 1578 recurse_lookups (c, 1579 lookupCount, lookupRecord); 1580 } 1581 1582 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 1583 unsigned int backtrackCount, 1584 const USHORT backtrack[], 1585 unsigned int inputCount, /* Including the first glyph (not matched) */ 1586 const USHORT input[], /* Array of input values--start with second glyph */ 1587 unsigned int lookaheadCount, 1588 const USHORT lookahead[], 1589 unsigned int lookupCount, 1590 const LookupRecord lookupRecord[], 1591 ChainContextCollectGlyphsLookupContext &lookup_context) 1592 { 1593 collect_array (c, c->before, 1594 backtrackCount, backtrack, 1595 lookup_context.funcs.collect, lookup_context.collect_data[0]); 1596 collect_array (c, c->input, 1597 inputCount ? inputCount - 1 : 0, input, 1598 lookup_context.funcs.collect, lookup_context.collect_data[1]); 1599 collect_array (c, c->after, 1600 lookaheadCount, lookahead, 1601 lookup_context.funcs.collect, lookup_context.collect_data[2]); 1602 recurse_lookups (c, 1603 lookupCount, lookupRecord); 1604 } 1605 1606 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, 1607 unsigned int backtrackCount, 1608 const USHORT backtrack[] HB_UNUSED, 1609 unsigned int inputCount, /* Including the first glyph (not matched) */ 1610 const USHORT input[], /* Array of input values--start with second glyph */ 1611 unsigned int lookaheadCount, 1612 const USHORT lookahead[] HB_UNUSED, 1613 unsigned int lookupCount HB_UNUSED, 1614 const LookupRecord lookupRecord[] HB_UNUSED, 1615 ChainContextApplyLookupContext &lookup_context) 1616 { 1617 return (c->zero_context ? !backtrackCount && !lookaheadCount : true) 1618 && would_match_input (c, 1619 inputCount, input, 1620 lookup_context.funcs.match, lookup_context.match_data[1]); 1621 } 1622 1623 static inline bool chain_context_apply_lookup (hb_apply_context_t *c, 1624 unsigned int backtrackCount, 1625 const USHORT backtrack[], 1626 unsigned int inputCount, /* Including the first glyph (not matched) */ 1627 const USHORT input[], /* Array of input values--start with second glyph */ 1628 unsigned int lookaheadCount, 1629 const USHORT lookahead[], 1630 unsigned int lookupCount, 1631 const LookupRecord lookupRecord[], 1632 ChainContextApplyLookupContext &lookup_context) 1633 { 1634 unsigned int match_length = 0; 1635 unsigned int match_positions[MAX_CONTEXT_LENGTH]; 1636 return match_input (c, 1637 inputCount, input, 1638 lookup_context.funcs.match, lookup_context.match_data[1], 1639 &match_length, match_positions) 1640 && match_backtrack (c, 1641 backtrackCount, backtrack, 1642 lookup_context.funcs.match, lookup_context.match_data[0]) 1643 && match_lookahead (c, 1644 lookaheadCount, lookahead, 1645 lookup_context.funcs.match, lookup_context.match_data[2], 1646 match_length) 1647 && apply_lookup (c, 1648 inputCount, match_positions, 1649 lookupCount, lookupRecord, 1650 match_length); 1651 } 1652 1653 struct ChainRule 1654 { 1655 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1656 { 1657 TRACE_CLOSURE (this); 1658 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1659 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1660 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1661 chain_context_closure_lookup (c, 1662 backtrack.len, backtrack.array, 1663 input.len, input.array, 1664 lookahead.len, lookahead.array, 1665 lookup.len, lookup.array, 1666 lookup_context); 1667 } 1668 1669 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const 1670 { 1671 TRACE_COLLECT_GLYPHS (this); 1672 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1673 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1674 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1675 chain_context_collect_glyphs_lookup (c, 1676 backtrack.len, backtrack.array, 1677 input.len, input.array, 1678 lookahead.len, lookahead.array, 1679 lookup.len, lookup.array, 1680 lookup_context); 1681 } 1682 1683 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1684 { 1685 TRACE_WOULD_APPLY (this); 1686 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1687 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1688 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1689 return TRACE_RETURN (chain_context_would_apply_lookup (c, 1690 backtrack.len, backtrack.array, 1691 input.len, input.array, 1692 lookahead.len, lookahead.array, lookup.len, 1693 lookup.array, lookup_context)); 1694 } 1695 1696 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1697 { 1698 TRACE_APPLY (this); 1699 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1700 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1701 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1702 return TRACE_RETURN (chain_context_apply_lookup (c, 1703 backtrack.len, backtrack.array, 1704 input.len, input.array, 1705 lookahead.len, lookahead.array, lookup.len, 1706 lookup.array, lookup_context)); 1707 } 1708 1709 inline bool sanitize (hb_sanitize_context_t *c) { 1710 TRACE_SANITIZE (this); 1711 if (!backtrack.sanitize (c)) return TRACE_RETURN (false); 1712 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1713 if (!input.sanitize (c)) return TRACE_RETURN (false); 1714 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1715 if (!lookahead.sanitize (c)) return TRACE_RETURN (false); 1716 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1717 return TRACE_RETURN (lookup.sanitize (c)); 1718 } 1719 1720 protected: 1721 ArrayOf<USHORT> 1722 backtrack; /* Array of backtracking values 1723 * (to be matched before the input 1724 * sequence) */ 1725 HeadlessArrayOf<USHORT> 1726 inputX; /* Array of input values (start with 1727 * second glyph) */ 1728 ArrayOf<USHORT> 1729 lookaheadX; /* Array of lookahead values's (to be 1730 * matched after the input sequence) */ 1731 ArrayOf<LookupRecord> 1732 lookupX; /* Array of LookupRecords--in 1733 * design order) */ 1734 public: 1735 DEFINE_SIZE_MIN (8); 1736 }; 1737 1738 struct ChainRuleSet 1739 { 1740 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1741 { 1742 TRACE_CLOSURE (this); 1743 unsigned int num_rules = rule.len; 1744 for (unsigned int i = 0; i < num_rules; i++) 1745 (this+rule[i]).closure (c, lookup_context); 1746 } 1747 1748 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const 1749 { 1750 TRACE_COLLECT_GLYPHS (this); 1751 unsigned int num_rules = rule.len; 1752 for (unsigned int i = 0; i < num_rules; i++) 1753 (this+rule[i]).collect_glyphs (c, lookup_context); 1754 } 1755 1756 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1757 { 1758 TRACE_WOULD_APPLY (this); 1759 unsigned int num_rules = rule.len; 1760 for (unsigned int i = 0; i < num_rules; i++) 1761 if ((this+rule[i]).would_apply (c, lookup_context)) 1762 return TRACE_RETURN (true); 1763 1764 return TRACE_RETURN (false); 1765 } 1766 1767 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1768 { 1769 TRACE_APPLY (this); 1770 unsigned int num_rules = rule.len; 1771 for (unsigned int i = 0; i < num_rules; i++) 1772 if ((this+rule[i]).apply (c, lookup_context)) 1773 return TRACE_RETURN (true); 1774 1775 return TRACE_RETURN (false); 1776 } 1777 1778 inline bool sanitize (hb_sanitize_context_t *c) { 1779 TRACE_SANITIZE (this); 1780 return TRACE_RETURN (rule.sanitize (c, this)); 1781 } 1782 1783 protected: 1784 OffsetArrayOf<ChainRule> 1785 rule; /* Array of ChainRule tables 1786 * ordered by preference */ 1787 public: 1788 DEFINE_SIZE_ARRAY (2, rule); 1789 }; 1790 1791 struct ChainContextFormat1 1792 { 1793 inline void closure (hb_closure_context_t *c) const 1794 { 1795 TRACE_CLOSURE (this); 1796 const Coverage &cov = (this+coverage); 1797 1798 struct ChainContextClosureLookupContext lookup_context = { 1799 {intersects_glyph}, 1800 {NULL, NULL, NULL} 1801 }; 1802 1803 unsigned int count = ruleSet.len; 1804 for (unsigned int i = 0; i < count; i++) 1805 if (cov.intersects_coverage (c->glyphs, i)) { 1806 const ChainRuleSet &rule_set = this+ruleSet[i]; 1807 rule_set.closure (c, lookup_context); 1808 } 1809 } 1810 1811 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1812 { 1813 TRACE_COLLECT_GLYPHS (this); 1814 (this+coverage).add_coverage (c->input); 1815 1816 struct ChainContextCollectGlyphsLookupContext lookup_context = { 1817 {collect_glyph}, 1818 {NULL, NULL, NULL} 1819 }; 1820 1821 unsigned int count = ruleSet.len; 1822 for (unsigned int i = 0; i < count; i++) 1823 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1824 } 1825 1826 inline bool would_apply (hb_would_apply_context_t *c) const 1827 { 1828 TRACE_WOULD_APPLY (this); 1829 1830 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 1831 struct ChainContextApplyLookupContext lookup_context = { 1832 {match_glyph}, 1833 {NULL, NULL, NULL} 1834 }; 1835 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1836 } 1837 1838 inline const Coverage &get_coverage (void) const 1839 { 1840 return this+coverage; 1841 } 1842 1843 inline bool apply (hb_apply_context_t *c) const 1844 { 1845 TRACE_APPLY (this); 1846 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1847 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1848 1849 const ChainRuleSet &rule_set = this+ruleSet[index]; 1850 struct ChainContextApplyLookupContext lookup_context = { 1851 {match_glyph}, 1852 {NULL, NULL, NULL} 1853 }; 1854 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1855 } 1856 1857 inline bool sanitize (hb_sanitize_context_t *c) { 1858 TRACE_SANITIZE (this); 1859 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1860 } 1861 1862 protected: 1863 USHORT format; /* Format identifier--format = 1 */ 1864 OffsetTo<Coverage> 1865 coverage; /* Offset to Coverage table--from 1866 * beginning of table */ 1867 OffsetArrayOf<ChainRuleSet> 1868 ruleSet; /* Array of ChainRuleSet tables 1869 * ordered by Coverage Index */ 1870 public: 1871 DEFINE_SIZE_ARRAY (6, ruleSet); 1872 }; 1873 1874 struct ChainContextFormat2 1875 { 1876 inline void closure (hb_closure_context_t *c) const 1877 { 1878 TRACE_CLOSURE (this); 1879 if (!(this+coverage).intersects (c->glyphs)) 1880 return; 1881 1882 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1883 const ClassDef &input_class_def = this+inputClassDef; 1884 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1885 1886 struct ChainContextClosureLookupContext lookup_context = { 1887 {intersects_class}, 1888 {&backtrack_class_def, 1889 &input_class_def, 1890 &lookahead_class_def} 1891 }; 1892 1893 unsigned int count = ruleSet.len; 1894 for (unsigned int i = 0; i < count; i++) 1895 if (input_class_def.intersects_class (c->glyphs, i)) { 1896 const ChainRuleSet &rule_set = this+ruleSet[i]; 1897 rule_set.closure (c, lookup_context); 1898 } 1899 } 1900 1901 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1902 { 1903 TRACE_COLLECT_GLYPHS (this); 1904 (this+coverage).add_coverage (c->input); 1905 1906 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1907 const ClassDef &input_class_def = this+inputClassDef; 1908 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1909 1910 struct ChainContextCollectGlyphsLookupContext lookup_context = { 1911 {collect_class}, 1912 {&backtrack_class_def, 1913 &input_class_def, 1914 &lookahead_class_def} 1915 }; 1916 1917 unsigned int count = ruleSet.len; 1918 for (unsigned int i = 0; i < count; i++) 1919 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1920 } 1921 1922 inline bool would_apply (hb_would_apply_context_t *c) const 1923 { 1924 TRACE_WOULD_APPLY (this); 1925 1926 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1927 const ClassDef &input_class_def = this+inputClassDef; 1928 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1929 1930 unsigned int index = input_class_def.get_class (c->glyphs[0]); 1931 const ChainRuleSet &rule_set = this+ruleSet[index]; 1932 struct ChainContextApplyLookupContext lookup_context = { 1933 {match_class}, 1934 {&backtrack_class_def, 1935 &input_class_def, 1936 &lookahead_class_def} 1937 }; 1938 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1939 } 1940 1941 inline const Coverage &get_coverage (void) const 1942 { 1943 return this+coverage; 1944 } 1945 1946 inline bool apply (hb_apply_context_t *c) const 1947 { 1948 TRACE_APPLY (this); 1949 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1950 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1951 1952 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1953 const ClassDef &input_class_def = this+inputClassDef; 1954 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1955 1956 index = input_class_def.get_class (c->buffer->cur().codepoint); 1957 const ChainRuleSet &rule_set = this+ruleSet[index]; 1958 struct ChainContextApplyLookupContext lookup_context = { 1959 {match_class}, 1960 {&backtrack_class_def, 1961 &input_class_def, 1962 &lookahead_class_def} 1963 }; 1964 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1965 } 1966 1967 inline bool sanitize (hb_sanitize_context_t *c) { 1968 TRACE_SANITIZE (this); 1969 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && 1970 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && 1971 ruleSet.sanitize (c, this)); 1972 } 1973 1974 protected: 1975 USHORT format; /* Format identifier--format = 2 */ 1976 OffsetTo<Coverage> 1977 coverage; /* Offset to Coverage table--from 1978 * beginning of table */ 1979 OffsetTo<ClassDef> 1980 backtrackClassDef; /* Offset to glyph ClassDef table 1981 * containing backtrack sequence 1982 * data--from beginning of table */ 1983 OffsetTo<ClassDef> 1984 inputClassDef; /* Offset to glyph ClassDef 1985 * table containing input sequence 1986 * data--from beginning of table */ 1987 OffsetTo<ClassDef> 1988 lookaheadClassDef; /* Offset to glyph ClassDef table 1989 * containing lookahead sequence 1990 * data--from beginning of table */ 1991 OffsetArrayOf<ChainRuleSet> 1992 ruleSet; /* Array of ChainRuleSet tables 1993 * ordered by class */ 1994 public: 1995 DEFINE_SIZE_ARRAY (12, ruleSet); 1996 }; 1997 1998 struct ChainContextFormat3 1999 { 2000 inline void closure (hb_closure_context_t *c) const 2001 { 2002 TRACE_CLOSURE (this); 2003 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2004 2005 if (!(this+input[0]).intersects (c->glyphs)) 2006 return; 2007 2008 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2009 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2010 struct ChainContextClosureLookupContext lookup_context = { 2011 {intersects_coverage}, 2012 {this, this, this} 2013 }; 2014 chain_context_closure_lookup (c, 2015 backtrack.len, (const USHORT *) backtrack.array, 2016 input.len, (const USHORT *) input.array + 1, 2017 lookahead.len, (const USHORT *) lookahead.array, 2018 lookup.len, lookup.array, 2019 lookup_context); 2020 } 2021 2022 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 2023 { 2024 TRACE_COLLECT_GLYPHS (this); 2025 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2026 2027 (this+input[0]).add_coverage (c->input); 2028 2029 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2030 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2031 struct ChainContextCollectGlyphsLookupContext lookup_context = { 2032 {collect_coverage}, 2033 {this, this, this} 2034 }; 2035 chain_context_collect_glyphs_lookup (c, 2036 backtrack.len, (const USHORT *) backtrack.array, 2037 input.len, (const USHORT *) input.array + 1, 2038 lookahead.len, (const USHORT *) lookahead.array, 2039 lookup.len, lookup.array, 2040 lookup_context); 2041 } 2042 2043 inline bool would_apply (hb_would_apply_context_t *c) const 2044 { 2045 TRACE_WOULD_APPLY (this); 2046 2047 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2048 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2049 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2050 struct ChainContextApplyLookupContext lookup_context = { 2051 {match_coverage}, 2052 {this, this, this} 2053 }; 2054 return TRACE_RETURN (chain_context_would_apply_lookup (c, 2055 backtrack.len, (const USHORT *) backtrack.array, 2056 input.len, (const USHORT *) input.array + 1, 2057 lookahead.len, (const USHORT *) lookahead.array, 2058 lookup.len, lookup.array, lookup_context)); 2059 } 2060 2061 inline const Coverage &get_coverage (void) const 2062 { 2063 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2064 return this+input[0]; 2065 } 2066 2067 inline bool apply (hb_apply_context_t *c) const 2068 { 2069 TRACE_APPLY (this); 2070 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2071 2072 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint); 2073 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 2074 2075 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2076 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2077 struct ChainContextApplyLookupContext lookup_context = { 2078 {match_coverage}, 2079 {this, this, this} 2080 }; 2081 return TRACE_RETURN (chain_context_apply_lookup (c, 2082 backtrack.len, (const USHORT *) backtrack.array, 2083 input.len, (const USHORT *) input.array + 1, 2084 lookahead.len, (const USHORT *) lookahead.array, 2085 lookup.len, lookup.array, lookup_context)); 2086 } 2087 2088 inline bool sanitize (hb_sanitize_context_t *c) { 2089 TRACE_SANITIZE (this); 2090 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); 2091 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2092 if (!input.sanitize (c, this)) return TRACE_RETURN (false); 2093 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2094 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false); 2095 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2096 return TRACE_RETURN (lookup.sanitize (c)); 2097 } 2098 2099 protected: 2100 USHORT format; /* Format identifier--format = 3 */ 2101 OffsetArrayOf<Coverage> 2102 backtrack; /* Array of coverage tables 2103 * in backtracking sequence, in glyph 2104 * sequence order */ 2105 OffsetArrayOf<Coverage> 2106 inputX ; /* Array of coverage 2107 * tables in input sequence, in glyph 2108 * sequence order */ 2109 OffsetArrayOf<Coverage> 2110 lookaheadX; /* Array of coverage tables 2111 * in lookahead sequence, in glyph 2112 * sequence order */ 2113 ArrayOf<LookupRecord> 2114 lookupX; /* Array of LookupRecords--in 2115 * design order) */ 2116 public: 2117 DEFINE_SIZE_MIN (10); 2118 }; 2119 2120 struct ChainContext 2121 { 2122 template <typename context_t> 2123 inline typename context_t::return_t dispatch (context_t *c) const 2124 { 2125 TRACE_DISPATCH (this); 2126 switch (u.format) { 2127 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 2128 case 2: return TRACE_RETURN (c->dispatch (u.format2)); 2129 case 3: return TRACE_RETURN (c->dispatch (u.format3)); 2130 default:return TRACE_RETURN (c->default_return_value ()); 2131 } 2132 } 2133 2134 inline bool sanitize (hb_sanitize_context_t *c) { 2135 TRACE_SANITIZE (this); 2136 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 2137 switch (u.format) { 2138 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 2139 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 2140 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 2141 default:return TRACE_RETURN (true); 2142 } 2143 } 2144 2145 protected: 2146 union { 2147 USHORT format; /* Format identifier */ 2148 ChainContextFormat1 format1; 2149 ChainContextFormat2 format2; 2150 ChainContextFormat3 format3; 2151 } u; 2152 }; 2153 2154 2155 struct ExtensionFormat1 2156 { 2157 inline unsigned int get_type (void) const { return extensionLookupType; } 2158 inline unsigned int get_offset (void) const { return extensionOffset; } 2159 2160 inline bool sanitize (hb_sanitize_context_t *c) { 2161 TRACE_SANITIZE (this); 2162 return TRACE_RETURN (c->check_struct (this)); 2163 } 2164 2165 protected: 2166 USHORT format; /* Format identifier. Set to 1. */ 2167 USHORT extensionLookupType; /* Lookup type of subtable referenced 2168 * by ExtensionOffset (i.e. the 2169 * extension subtable). */ 2170 ULONG extensionOffset; /* Offset to the extension subtable, 2171 * of lookup type subtable. */ 2172 public: 2173 DEFINE_SIZE_STATIC (8); 2174 }; 2175 2176 template <typename T> 2177 struct Extension 2178 { 2179 inline unsigned int get_type (void) const 2180 { 2181 switch (u.format) { 2182 case 1: return u.format1.get_type (); 2183 default:return 0; 2184 } 2185 } 2186 inline unsigned int get_offset (void) const 2187 { 2188 switch (u.format) { 2189 case 1: return u.format1.get_offset (); 2190 default:return 0; 2191 } 2192 } 2193 2194 template <typename X> 2195 inline const X& get_subtable (void) const 2196 { 2197 unsigned int offset = get_offset (); 2198 if (unlikely (!offset)) return Null(typename T::LookupSubTable); 2199 return StructAtOffset<typename T::LookupSubTable> (this, offset); 2200 } 2201 2202 template <typename context_t> 2203 inline typename context_t::return_t dispatch (context_t *c) const 2204 { 2205 return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()); 2206 } 2207 2208 inline bool sanitize_self (hb_sanitize_context_t *c) { 2209 TRACE_SANITIZE (this); 2210 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 2211 switch (u.format) { 2212 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 2213 default:return TRACE_RETURN (true); 2214 } 2215 } 2216 2217 inline bool sanitize (hb_sanitize_context_t *c) { 2218 TRACE_SANITIZE (this); 2219 if (!sanitize_self (c)) return TRACE_RETURN (false); 2220 unsigned int offset = get_offset (); 2221 if (unlikely (!offset)) return TRACE_RETURN (true); 2222 return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ())); 2223 } 2224 2225 protected: 2226 union { 2227 USHORT format; /* Format identifier */ 2228 ExtensionFormat1 format1; 2229 } u; 2230 }; 2231 2232 2233 /* 2234 * GSUB/GPOS Common 2235 */ 2236 2237 struct GSUBGPOS 2238 { 2239 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; 2240 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; 2241 2242 inline unsigned int get_script_count (void) const 2243 { return (this+scriptList).len; } 2244 inline const Tag& get_script_tag (unsigned int i) const 2245 { return (this+scriptList).get_tag (i); } 2246 inline unsigned int get_script_tags (unsigned int start_offset, 2247 unsigned int *script_count /* IN/OUT */, 2248 hb_tag_t *script_tags /* OUT */) const 2249 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } 2250 inline const Script& get_script (unsigned int i) const 2251 { return (this+scriptList)[i]; } 2252 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const 2253 { return (this+scriptList).find_index (tag, index); } 2254 2255 inline unsigned int get_feature_count (void) const 2256 { return (this+featureList).len; } 2257 inline hb_tag_t get_feature_tag (unsigned int i) const 2258 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); } 2259 inline unsigned int get_feature_tags (unsigned int start_offset, 2260 unsigned int *feature_count /* IN/OUT */, 2261 hb_tag_t *feature_tags /* OUT */) const 2262 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } 2263 inline const Feature& get_feature (unsigned int i) const 2264 { return (this+featureList)[i]; } 2265 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const 2266 { return (this+featureList).find_index (tag, index); } 2267 2268 inline unsigned int get_lookup_count (void) const 2269 { return (this+lookupList).len; } 2270 inline const Lookup& get_lookup (unsigned int i) const 2271 { return (this+lookupList)[i]; } 2272 2273 inline bool sanitize (hb_sanitize_context_t *c) { 2274 TRACE_SANITIZE (this); 2275 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && 2276 scriptList.sanitize (c, this) && 2277 featureList.sanitize (c, this) && 2278 lookupList.sanitize (c, this)); 2279 } 2280 2281 protected: 2282 FixedVersion version; /* Version of the GSUB/GPOS table--initially set 2283 * to 0x00010000u */ 2284 OffsetTo<ScriptList> 2285 scriptList; /* ScriptList table */ 2286 OffsetTo<FeatureList> 2287 featureList; /* FeatureList table */ 2288 OffsetTo<LookupList> 2289 lookupList; /* LookupList table */ 2290 public: 2291 DEFINE_SIZE_STATIC (10); 2292 }; 2293 2294 2295 } /* namespace OT */ 2296 2297 2298 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ 2299