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