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