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