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