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