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 (!count) return TRACE_RETURN (false); /* We want to access coverage[0] freely. */ 1483 if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false); 1484 for (unsigned int i = 0; i < count; i++) 1485 if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false); 1486 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count); 1487 return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); 1488 } 1489 1490 protected: 1491 USHORT format; /* Format identifier--format = 3 */ 1492 USHORT glyphCount; /* Number of glyphs in the input glyph 1493 * sequence */ 1494 USHORT lookupCount; /* Number of LookupRecords */ 1495 OffsetTo<Coverage> 1496 coverage[VAR]; /* Array of offsets to Coverage 1497 * table in glyph sequence order */ 1498 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 1499 * design order */ 1500 public: 1501 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX); 1502 }; 1503 1504 struct Context 1505 { 1506 template <typename context_t> 1507 inline typename context_t::return_t dispatch (context_t *c) const 1508 { 1509 TRACE_DISPATCH (this); 1510 switch (u.format) { 1511 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1512 case 2: return TRACE_RETURN (c->dispatch (u.format2)); 1513 case 3: return TRACE_RETURN (c->dispatch (u.format3)); 1514 default:return TRACE_RETURN (c->default_return_value ()); 1515 } 1516 } 1517 1518 inline bool sanitize (hb_sanitize_context_t *c) { 1519 TRACE_SANITIZE (this); 1520 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1521 switch (u.format) { 1522 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1523 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1524 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1525 default:return TRACE_RETURN (true); 1526 } 1527 } 1528 1529 protected: 1530 union { 1531 USHORT format; /* Format identifier */ 1532 ContextFormat1 format1; 1533 ContextFormat2 format2; 1534 ContextFormat3 format3; 1535 } u; 1536 }; 1537 1538 1539 /* Chaining Contextual lookups */ 1540 1541 struct ChainContextClosureLookupContext 1542 { 1543 ContextClosureFuncs funcs; 1544 const void *intersects_data[3]; 1545 }; 1546 1547 struct ChainContextCollectGlyphsLookupContext 1548 { 1549 ContextCollectGlyphsFuncs funcs; 1550 const void *collect_data[3]; 1551 }; 1552 1553 struct ChainContextApplyLookupContext 1554 { 1555 ContextApplyFuncs funcs; 1556 const void *match_data[3]; 1557 }; 1558 1559 static inline void chain_context_closure_lookup (hb_closure_context_t *c, 1560 unsigned int backtrackCount, 1561 const USHORT backtrack[], 1562 unsigned int inputCount, /* Including the first glyph (not matched) */ 1563 const USHORT input[], /* Array of input values--start with second glyph */ 1564 unsigned int lookaheadCount, 1565 const USHORT lookahead[], 1566 unsigned int lookupCount, 1567 const LookupRecord lookupRecord[], 1568 ChainContextClosureLookupContext &lookup_context) 1569 { 1570 if (intersects_array (c, 1571 backtrackCount, backtrack, 1572 lookup_context.funcs.intersects, lookup_context.intersects_data[0]) 1573 && intersects_array (c, 1574 inputCount ? inputCount - 1 : 0, input, 1575 lookup_context.funcs.intersects, lookup_context.intersects_data[1]) 1576 && intersects_array (c, 1577 lookaheadCount, lookahead, 1578 lookup_context.funcs.intersects, lookup_context.intersects_data[2])) 1579 recurse_lookups (c, 1580 lookupCount, lookupRecord); 1581 } 1582 1583 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 1584 unsigned int backtrackCount, 1585 const USHORT backtrack[], 1586 unsigned int inputCount, /* Including the first glyph (not matched) */ 1587 const USHORT input[], /* Array of input values--start with second glyph */ 1588 unsigned int lookaheadCount, 1589 const USHORT lookahead[], 1590 unsigned int lookupCount, 1591 const LookupRecord lookupRecord[], 1592 ChainContextCollectGlyphsLookupContext &lookup_context) 1593 { 1594 collect_array (c, c->before, 1595 backtrackCount, backtrack, 1596 lookup_context.funcs.collect, lookup_context.collect_data[0]); 1597 collect_array (c, c->input, 1598 inputCount ? inputCount - 1 : 0, input, 1599 lookup_context.funcs.collect, lookup_context.collect_data[1]); 1600 collect_array (c, c->after, 1601 lookaheadCount, lookahead, 1602 lookup_context.funcs.collect, lookup_context.collect_data[2]); 1603 recurse_lookups (c, 1604 lookupCount, lookupRecord); 1605 } 1606 1607 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, 1608 unsigned int backtrackCount, 1609 const USHORT backtrack[] HB_UNUSED, 1610 unsigned int inputCount, /* Including the first glyph (not matched) */ 1611 const USHORT input[], /* Array of input values--start with second glyph */ 1612 unsigned int lookaheadCount, 1613 const USHORT lookahead[] HB_UNUSED, 1614 unsigned int lookupCount HB_UNUSED, 1615 const LookupRecord lookupRecord[] HB_UNUSED, 1616 ChainContextApplyLookupContext &lookup_context) 1617 { 1618 return (c->zero_context ? !backtrackCount && !lookaheadCount : true) 1619 && would_match_input (c, 1620 inputCount, input, 1621 lookup_context.funcs.match, lookup_context.match_data[1]); 1622 } 1623 1624 static inline bool chain_context_apply_lookup (hb_apply_context_t *c, 1625 unsigned int backtrackCount, 1626 const USHORT backtrack[], 1627 unsigned int inputCount, /* Including the first glyph (not matched) */ 1628 const USHORT input[], /* Array of input values--start with second glyph */ 1629 unsigned int lookaheadCount, 1630 const USHORT lookahead[], 1631 unsigned int lookupCount, 1632 const LookupRecord lookupRecord[], 1633 ChainContextApplyLookupContext &lookup_context) 1634 { 1635 unsigned int match_length = 0; 1636 unsigned int match_positions[MAX_CONTEXT_LENGTH]; 1637 return match_input (c, 1638 inputCount, input, 1639 lookup_context.funcs.match, lookup_context.match_data[1], 1640 &match_length, match_positions) 1641 && match_backtrack (c, 1642 backtrackCount, backtrack, 1643 lookup_context.funcs.match, lookup_context.match_data[0]) 1644 && match_lookahead (c, 1645 lookaheadCount, lookahead, 1646 lookup_context.funcs.match, lookup_context.match_data[2], 1647 match_length) 1648 && apply_lookup (c, 1649 inputCount, match_positions, 1650 lookupCount, lookupRecord, 1651 match_length); 1652 } 1653 1654 struct ChainRule 1655 { 1656 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1657 { 1658 TRACE_CLOSURE (this); 1659 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1660 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1661 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1662 chain_context_closure_lookup (c, 1663 backtrack.len, backtrack.array, 1664 input.len, input.array, 1665 lookahead.len, lookahead.array, 1666 lookup.len, lookup.array, 1667 lookup_context); 1668 } 1669 1670 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const 1671 { 1672 TRACE_COLLECT_GLYPHS (this); 1673 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1674 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1675 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1676 chain_context_collect_glyphs_lookup (c, 1677 backtrack.len, backtrack.array, 1678 input.len, input.array, 1679 lookahead.len, lookahead.array, 1680 lookup.len, lookup.array, 1681 lookup_context); 1682 } 1683 1684 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1685 { 1686 TRACE_WOULD_APPLY (this); 1687 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1688 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1689 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1690 return TRACE_RETURN (chain_context_would_apply_lookup (c, 1691 backtrack.len, backtrack.array, 1692 input.len, input.array, 1693 lookahead.len, lookahead.array, lookup.len, 1694 lookup.array, lookup_context)); 1695 } 1696 1697 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1698 { 1699 TRACE_APPLY (this); 1700 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1701 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1702 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1703 return TRACE_RETURN (chain_context_apply_lookup (c, 1704 backtrack.len, backtrack.array, 1705 input.len, input.array, 1706 lookahead.len, lookahead.array, lookup.len, 1707 lookup.array, lookup_context)); 1708 } 1709 1710 inline bool sanitize (hb_sanitize_context_t *c) { 1711 TRACE_SANITIZE (this); 1712 if (!backtrack.sanitize (c)) return TRACE_RETURN (false); 1713 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1714 if (!input.sanitize (c)) return TRACE_RETURN (false); 1715 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1716 if (!lookahead.sanitize (c)) return TRACE_RETURN (false); 1717 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1718 return TRACE_RETURN (lookup.sanitize (c)); 1719 } 1720 1721 protected: 1722 ArrayOf<USHORT> 1723 backtrack; /* Array of backtracking values 1724 * (to be matched before the input 1725 * sequence) */ 1726 HeadlessArrayOf<USHORT> 1727 inputX; /* Array of input values (start with 1728 * second glyph) */ 1729 ArrayOf<USHORT> 1730 lookaheadX; /* Array of lookahead values's (to be 1731 * matched after the input sequence) */ 1732 ArrayOf<LookupRecord> 1733 lookupX; /* Array of LookupRecords--in 1734 * design order) */ 1735 public: 1736 DEFINE_SIZE_MIN (8); 1737 }; 1738 1739 struct ChainRuleSet 1740 { 1741 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1742 { 1743 TRACE_CLOSURE (this); 1744 unsigned int num_rules = rule.len; 1745 for (unsigned int i = 0; i < num_rules; i++) 1746 (this+rule[i]).closure (c, lookup_context); 1747 } 1748 1749 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const 1750 { 1751 TRACE_COLLECT_GLYPHS (this); 1752 unsigned int num_rules = rule.len; 1753 for (unsigned int i = 0; i < num_rules; i++) 1754 (this+rule[i]).collect_glyphs (c, lookup_context); 1755 } 1756 1757 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1758 { 1759 TRACE_WOULD_APPLY (this); 1760 unsigned int num_rules = rule.len; 1761 for (unsigned int i = 0; i < num_rules; i++) 1762 if ((this+rule[i]).would_apply (c, lookup_context)) 1763 return TRACE_RETURN (true); 1764 1765 return TRACE_RETURN (false); 1766 } 1767 1768 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1769 { 1770 TRACE_APPLY (this); 1771 unsigned int num_rules = rule.len; 1772 for (unsigned int i = 0; i < num_rules; i++) 1773 if ((this+rule[i]).apply (c, lookup_context)) 1774 return TRACE_RETURN (true); 1775 1776 return TRACE_RETURN (false); 1777 } 1778 1779 inline bool sanitize (hb_sanitize_context_t *c) { 1780 TRACE_SANITIZE (this); 1781 return TRACE_RETURN (rule.sanitize (c, this)); 1782 } 1783 1784 protected: 1785 OffsetArrayOf<ChainRule> 1786 rule; /* Array of ChainRule tables 1787 * ordered by preference */ 1788 public: 1789 DEFINE_SIZE_ARRAY (2, rule); 1790 }; 1791 1792 struct ChainContextFormat1 1793 { 1794 inline void closure (hb_closure_context_t *c) const 1795 { 1796 TRACE_CLOSURE (this); 1797 const Coverage &cov = (this+coverage); 1798 1799 struct ChainContextClosureLookupContext lookup_context = { 1800 {intersects_glyph}, 1801 {NULL, NULL, NULL} 1802 }; 1803 1804 unsigned int count = ruleSet.len; 1805 for (unsigned int i = 0; i < count; i++) 1806 if (cov.intersects_coverage (c->glyphs, i)) { 1807 const ChainRuleSet &rule_set = this+ruleSet[i]; 1808 rule_set.closure (c, lookup_context); 1809 } 1810 } 1811 1812 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1813 { 1814 TRACE_COLLECT_GLYPHS (this); 1815 (this+coverage).add_coverage (c->input); 1816 1817 struct ChainContextCollectGlyphsLookupContext lookup_context = { 1818 {collect_glyph}, 1819 {NULL, NULL, NULL} 1820 }; 1821 1822 unsigned int count = ruleSet.len; 1823 for (unsigned int i = 0; i < count; i++) 1824 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1825 } 1826 1827 inline bool would_apply (hb_would_apply_context_t *c) const 1828 { 1829 TRACE_WOULD_APPLY (this); 1830 1831 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 1832 struct ChainContextApplyLookupContext lookup_context = { 1833 {match_glyph}, 1834 {NULL, NULL, NULL} 1835 }; 1836 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1837 } 1838 1839 inline const Coverage &get_coverage (void) const 1840 { 1841 return this+coverage; 1842 } 1843 1844 inline bool apply (hb_apply_context_t *c) const 1845 { 1846 TRACE_APPLY (this); 1847 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1848 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1849 1850 const ChainRuleSet &rule_set = this+ruleSet[index]; 1851 struct ChainContextApplyLookupContext lookup_context = { 1852 {match_glyph}, 1853 {NULL, NULL, NULL} 1854 }; 1855 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1856 } 1857 1858 inline bool sanitize (hb_sanitize_context_t *c) { 1859 TRACE_SANITIZE (this); 1860 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1861 } 1862 1863 protected: 1864 USHORT format; /* Format identifier--format = 1 */ 1865 OffsetTo<Coverage> 1866 coverage; /* Offset to Coverage table--from 1867 * beginning of table */ 1868 OffsetArrayOf<ChainRuleSet> 1869 ruleSet; /* Array of ChainRuleSet tables 1870 * ordered by Coverage Index */ 1871 public: 1872 DEFINE_SIZE_ARRAY (6, ruleSet); 1873 }; 1874 1875 struct ChainContextFormat2 1876 { 1877 inline void closure (hb_closure_context_t *c) const 1878 { 1879 TRACE_CLOSURE (this); 1880 if (!(this+coverage).intersects (c->glyphs)) 1881 return; 1882 1883 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1884 const ClassDef &input_class_def = this+inputClassDef; 1885 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1886 1887 struct ChainContextClosureLookupContext lookup_context = { 1888 {intersects_class}, 1889 {&backtrack_class_def, 1890 &input_class_def, 1891 &lookahead_class_def} 1892 }; 1893 1894 unsigned int count = ruleSet.len; 1895 for (unsigned int i = 0; i < count; i++) 1896 if (input_class_def.intersects_class (c->glyphs, i)) { 1897 const ChainRuleSet &rule_set = this+ruleSet[i]; 1898 rule_set.closure (c, lookup_context); 1899 } 1900 } 1901 1902 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1903 { 1904 TRACE_COLLECT_GLYPHS (this); 1905 (this+coverage).add_coverage (c->input); 1906 1907 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1908 const ClassDef &input_class_def = this+inputClassDef; 1909 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1910 1911 struct ChainContextCollectGlyphsLookupContext lookup_context = { 1912 {collect_class}, 1913 {&backtrack_class_def, 1914 &input_class_def, 1915 &lookahead_class_def} 1916 }; 1917 1918 unsigned int count = ruleSet.len; 1919 for (unsigned int i = 0; i < count; i++) 1920 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1921 } 1922 1923 inline bool would_apply (hb_would_apply_context_t *c) const 1924 { 1925 TRACE_WOULD_APPLY (this); 1926 1927 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1928 const ClassDef &input_class_def = this+inputClassDef; 1929 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1930 1931 unsigned int index = input_class_def.get_class (c->glyphs[0]); 1932 const ChainRuleSet &rule_set = this+ruleSet[index]; 1933 struct ChainContextApplyLookupContext lookup_context = { 1934 {match_class}, 1935 {&backtrack_class_def, 1936 &input_class_def, 1937 &lookahead_class_def} 1938 }; 1939 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1940 } 1941 1942 inline const Coverage &get_coverage (void) const 1943 { 1944 return this+coverage; 1945 } 1946 1947 inline bool apply (hb_apply_context_t *c) const 1948 { 1949 TRACE_APPLY (this); 1950 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1951 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1952 1953 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1954 const ClassDef &input_class_def = this+inputClassDef; 1955 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1956 1957 index = input_class_def.get_class (c->buffer->cur().codepoint); 1958 const ChainRuleSet &rule_set = this+ruleSet[index]; 1959 struct ChainContextApplyLookupContext lookup_context = { 1960 {match_class}, 1961 {&backtrack_class_def, 1962 &input_class_def, 1963 &lookahead_class_def} 1964 }; 1965 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1966 } 1967 1968 inline bool sanitize (hb_sanitize_context_t *c) { 1969 TRACE_SANITIZE (this); 1970 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && 1971 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && 1972 ruleSet.sanitize (c, this)); 1973 } 1974 1975 protected: 1976 USHORT format; /* Format identifier--format = 2 */ 1977 OffsetTo<Coverage> 1978 coverage; /* Offset to Coverage table--from 1979 * beginning of table */ 1980 OffsetTo<ClassDef> 1981 backtrackClassDef; /* Offset to glyph ClassDef table 1982 * containing backtrack sequence 1983 * data--from beginning of table */ 1984 OffsetTo<ClassDef> 1985 inputClassDef; /* Offset to glyph ClassDef 1986 * table containing input sequence 1987 * data--from beginning of table */ 1988 OffsetTo<ClassDef> 1989 lookaheadClassDef; /* Offset to glyph ClassDef table 1990 * containing lookahead sequence 1991 * data--from beginning of table */ 1992 OffsetArrayOf<ChainRuleSet> 1993 ruleSet; /* Array of ChainRuleSet tables 1994 * ordered by class */ 1995 public: 1996 DEFINE_SIZE_ARRAY (12, ruleSet); 1997 }; 1998 1999 struct ChainContextFormat3 2000 { 2001 inline void closure (hb_closure_context_t *c) const 2002 { 2003 TRACE_CLOSURE (this); 2004 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2005 2006 if (!(this+input[0]).intersects (c->glyphs)) 2007 return; 2008 2009 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2010 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2011 struct ChainContextClosureLookupContext lookup_context = { 2012 {intersects_coverage}, 2013 {this, this, this} 2014 }; 2015 chain_context_closure_lookup (c, 2016 backtrack.len, (const USHORT *) backtrack.array, 2017 input.len, (const USHORT *) input.array + 1, 2018 lookahead.len, (const USHORT *) lookahead.array, 2019 lookup.len, lookup.array, 2020 lookup_context); 2021 } 2022 2023 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 2024 { 2025 TRACE_COLLECT_GLYPHS (this); 2026 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2027 2028 (this+input[0]).add_coverage (c->input); 2029 2030 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2031 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2032 struct ChainContextCollectGlyphsLookupContext lookup_context = { 2033 {collect_coverage}, 2034 {this, this, this} 2035 }; 2036 chain_context_collect_glyphs_lookup (c, 2037 backtrack.len, (const USHORT *) backtrack.array, 2038 input.len, (const USHORT *) input.array + 1, 2039 lookahead.len, (const USHORT *) lookahead.array, 2040 lookup.len, lookup.array, 2041 lookup_context); 2042 } 2043 2044 inline bool would_apply (hb_would_apply_context_t *c) const 2045 { 2046 TRACE_WOULD_APPLY (this); 2047 2048 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2049 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2050 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2051 struct ChainContextApplyLookupContext lookup_context = { 2052 {match_coverage}, 2053 {this, this, this} 2054 }; 2055 return TRACE_RETURN (chain_context_would_apply_lookup (c, 2056 backtrack.len, (const USHORT *) backtrack.array, 2057 input.len, (const USHORT *) input.array + 1, 2058 lookahead.len, (const USHORT *) lookahead.array, 2059 lookup.len, lookup.array, lookup_context)); 2060 } 2061 2062 inline const Coverage &get_coverage (void) const 2063 { 2064 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2065 return this+input[0]; 2066 } 2067 2068 inline bool apply (hb_apply_context_t *c) const 2069 { 2070 TRACE_APPLY (this); 2071 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2072 2073 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint); 2074 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 2075 2076 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2077 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2078 struct ChainContextApplyLookupContext lookup_context = { 2079 {match_coverage}, 2080 {this, this, this} 2081 }; 2082 return TRACE_RETURN (chain_context_apply_lookup (c, 2083 backtrack.len, (const USHORT *) backtrack.array, 2084 input.len, (const USHORT *) input.array + 1, 2085 lookahead.len, (const USHORT *) lookahead.array, 2086 lookup.len, lookup.array, lookup_context)); 2087 } 2088 2089 inline bool sanitize (hb_sanitize_context_t *c) { 2090 TRACE_SANITIZE (this); 2091 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); 2092 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2093 if (!input.sanitize (c, this)) return TRACE_RETURN (false); 2094 if (!input.len) return TRACE_RETURN (false); /* To be consistent with Context. */ 2095 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2096 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false); 2097 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2098 return TRACE_RETURN (lookup.sanitize (c)); 2099 } 2100 2101 protected: 2102 USHORT format; /* Format identifier--format = 3 */ 2103 OffsetArrayOf<Coverage> 2104 backtrack; /* Array of coverage tables 2105 * in backtracking sequence, in glyph 2106 * sequence order */ 2107 OffsetArrayOf<Coverage> 2108 inputX ; /* Array of coverage 2109 * tables in input sequence, in glyph 2110 * sequence order */ 2111 OffsetArrayOf<Coverage> 2112 lookaheadX; /* Array of coverage tables 2113 * in lookahead sequence, in glyph 2114 * sequence order */ 2115 ArrayOf<LookupRecord> 2116 lookupX; /* Array of LookupRecords--in 2117 * design order) */ 2118 public: 2119 DEFINE_SIZE_MIN (10); 2120 }; 2121 2122 struct ChainContext 2123 { 2124 template <typename context_t> 2125 inline typename context_t::return_t dispatch (context_t *c) const 2126 { 2127 TRACE_DISPATCH (this); 2128 switch (u.format) { 2129 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 2130 case 2: return TRACE_RETURN (c->dispatch (u.format2)); 2131 case 3: return TRACE_RETURN (c->dispatch (u.format3)); 2132 default:return TRACE_RETURN (c->default_return_value ()); 2133 } 2134 } 2135 2136 inline bool sanitize (hb_sanitize_context_t *c) { 2137 TRACE_SANITIZE (this); 2138 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 2139 switch (u.format) { 2140 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 2141 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 2142 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 2143 default:return TRACE_RETURN (true); 2144 } 2145 } 2146 2147 protected: 2148 union { 2149 USHORT format; /* Format identifier */ 2150 ChainContextFormat1 format1; 2151 ChainContextFormat2 format2; 2152 ChainContextFormat3 format3; 2153 } u; 2154 }; 2155 2156 2157 struct ExtensionFormat1 2158 { 2159 inline unsigned int get_type (void) const { return extensionLookupType; } 2160 inline unsigned int get_offset (void) const { return extensionOffset; } 2161 2162 inline bool sanitize (hb_sanitize_context_t *c) { 2163 TRACE_SANITIZE (this); 2164 return TRACE_RETURN (c->check_struct (this)); 2165 } 2166 2167 protected: 2168 USHORT format; /* Format identifier. Set to 1. */ 2169 USHORT extensionLookupType; /* Lookup type of subtable referenced 2170 * by ExtensionOffset (i.e. the 2171 * extension subtable). */ 2172 ULONG extensionOffset; /* Offset to the extension subtable, 2173 * of lookup type subtable. */ 2174 public: 2175 DEFINE_SIZE_STATIC (8); 2176 }; 2177 2178 template <typename T> 2179 struct Extension 2180 { 2181 inline unsigned int get_type (void) const 2182 { 2183 switch (u.format) { 2184 case 1: return u.format1.get_type (); 2185 default:return 0; 2186 } 2187 } 2188 inline unsigned int get_offset (void) const 2189 { 2190 switch (u.format) { 2191 case 1: return u.format1.get_offset (); 2192 default:return 0; 2193 } 2194 } 2195 2196 template <typename X> 2197 inline const X& get_subtable (void) const 2198 { 2199 unsigned int offset = get_offset (); 2200 if (unlikely (!offset)) return Null(typename T::LookupSubTable); 2201 return StructAtOffset<typename T::LookupSubTable> (this, offset); 2202 } 2203 2204 template <typename context_t> 2205 inline typename context_t::return_t dispatch (context_t *c) const 2206 { 2207 return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()); 2208 } 2209 2210 inline bool sanitize_self (hb_sanitize_context_t *c) { 2211 TRACE_SANITIZE (this); 2212 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 2213 switch (u.format) { 2214 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 2215 default:return TRACE_RETURN (true); 2216 } 2217 } 2218 2219 inline bool sanitize (hb_sanitize_context_t *c) { 2220 TRACE_SANITIZE (this); 2221 if (!sanitize_self (c)) return TRACE_RETURN (false); 2222 unsigned int offset = get_offset (); 2223 if (unlikely (!offset)) return TRACE_RETURN (true); 2224 return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ())); 2225 } 2226 2227 protected: 2228 union { 2229 USHORT format; /* Format identifier */ 2230 ExtensionFormat1 format1; 2231 } u; 2232 }; 2233 2234 2235 /* 2236 * GSUB/GPOS Common 2237 */ 2238 2239 struct GSUBGPOS 2240 { 2241 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; 2242 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; 2243 2244 inline unsigned int get_script_count (void) const 2245 { return (this+scriptList).len; } 2246 inline const Tag& get_script_tag (unsigned int i) const 2247 { return (this+scriptList).get_tag (i); } 2248 inline unsigned int get_script_tags (unsigned int start_offset, 2249 unsigned int *script_count /* IN/OUT */, 2250 hb_tag_t *script_tags /* OUT */) const 2251 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } 2252 inline const Script& get_script (unsigned int i) const 2253 { return (this+scriptList)[i]; } 2254 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const 2255 { return (this+scriptList).find_index (tag, index); } 2256 2257 inline unsigned int get_feature_count (void) const 2258 { return (this+featureList).len; } 2259 inline hb_tag_t get_feature_tag (unsigned int i) const 2260 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); } 2261 inline unsigned int get_feature_tags (unsigned int start_offset, 2262 unsigned int *feature_count /* IN/OUT */, 2263 hb_tag_t *feature_tags /* OUT */) const 2264 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } 2265 inline const Feature& get_feature (unsigned int i) const 2266 { return (this+featureList)[i]; } 2267 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const 2268 { return (this+featureList).find_index (tag, index); } 2269 2270 inline unsigned int get_lookup_count (void) const 2271 { return (this+lookupList).len; } 2272 inline const Lookup& get_lookup (unsigned int i) const 2273 { return (this+lookupList)[i]; } 2274 2275 inline bool sanitize (hb_sanitize_context_t *c) { 2276 TRACE_SANITIZE (this); 2277 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && 2278 scriptList.sanitize (c, this) && 2279 featureList.sanitize (c, this) && 2280 lookupList.sanitize (c, this)); 2281 } 2282 2283 protected: 2284 FixedVersion version; /* Version of the GSUB/GPOS table--initially set 2285 * to 0x00010000u */ 2286 OffsetTo<ScriptList> 2287 scriptList; /* ScriptList table */ 2288 OffsetTo<FeatureList> 2289 featureList; /* FeatureList table */ 2290 OffsetTo<LookupList> 2291 lookupList; /* LookupList table */ 2292 public: 2293 DEFINE_SIZE_STATIC (10); 2294 }; 2295 2296 2297 } /* namespace OT */ 2298 2299 2300 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ 2301