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