hb-ot-layout-gsubgpos-private.hh revision 05ad6b50ac0a1b9a8da10d2ee2238068b7811e7d
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 = _hb_glyph_info_get_glyph_props (&info); 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 = _hb_glyph_info_get_glyph_props (info); 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 unsigned int add_in = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; 622 if (likely (has_glyph_classes)) 623 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index)); 624 else if (class_guess) 625 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in| class_guess); 626 } 627 628 inline void replace_glyph (hb_codepoint_t glyph_index) const 629 { 630 _set_glyph_props (glyph_index); 631 buffer->replace_glyph (glyph_index); 632 } 633 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const 634 { 635 _set_glyph_props (glyph_index); 636 buffer->cur().codepoint = glyph_index; 637 } 638 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index, 639 unsigned int class_guess) const 640 { 641 _set_glyph_props (glyph_index, class_guess); 642 buffer->replace_glyph (glyph_index); 643 } 644 inline void output_glyph (hb_codepoint_t glyph_index, 645 unsigned int class_guess) const 646 { 647 _set_glyph_props (glyph_index, class_guess); 648 buffer->output_glyph (glyph_index); 649 } 650}; 651 652 653 654typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); 655typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); 656typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); 657 658struct ContextClosureFuncs 659{ 660 intersects_func_t intersects; 661}; 662struct ContextCollectGlyphsFuncs 663{ 664 collect_glyphs_func_t collect; 665}; 666struct ContextApplyFuncs 667{ 668 match_func_t match; 669}; 670 671 672static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) 673{ 674 return glyphs->has (value); 675} 676static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data) 677{ 678 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 679 return class_def.intersects_class (glyphs, value); 680} 681static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) 682{ 683 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 684 return (data+coverage).intersects (glyphs); 685} 686 687static inline bool intersects_array (hb_closure_context_t *c, 688 unsigned int count, 689 const USHORT values[], 690 intersects_func_t intersects_func, 691 const void *intersects_data) 692{ 693 for (unsigned int i = 0; i < count; i++) 694 if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) 695 return false; 696 return true; 697} 698 699 700static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) 701{ 702 glyphs->add (value); 703} 704static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data) 705{ 706 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 707 class_def.add_class (glyphs, value); 708} 709static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) 710{ 711 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 712 (data+coverage).add_coverage (glyphs); 713} 714static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, 715 hb_set_t *glyphs, 716 unsigned int count, 717 const USHORT values[], 718 collect_glyphs_func_t collect_func, 719 const void *collect_data) 720{ 721 for (unsigned int i = 0; i < count; i++) 722 collect_func (glyphs, values[i], collect_data); 723} 724 725 726static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED) 727{ 728 return glyph_id == value; 729} 730static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 731{ 732 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 733 return class_def.get_class (glyph_id) == value; 734} 735static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 736{ 737 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 738 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; 739} 740 741static inline bool would_match_input (hb_would_apply_context_t *c, 742 unsigned int count, /* Including the first glyph (not matched) */ 743 const USHORT input[], /* Array of input values--start with second glyph */ 744 match_func_t match_func, 745 const void *match_data) 746{ 747 if (count != c->len) 748 return false; 749 750 for (unsigned int i = 1; i < count; i++) 751 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data))) 752 return false; 753 754 return true; 755} 756static inline bool match_input (hb_apply_context_t *c, 757 unsigned int count, /* Including the first glyph (not matched) */ 758 const USHORT input[], /* Array of input values--start with second glyph */ 759 match_func_t match_func, 760 const void *match_data, 761 unsigned int *end_offset, 762 unsigned int match_positions[MAX_CONTEXT_LENGTH], 763 bool *p_is_mark_ligature = NULL, 764 unsigned int *p_total_component_count = NULL) 765{ 766 TRACE_APPLY (NULL); 767 768 if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false); 769 770 hb_buffer_t *buffer = c->buffer; 771 772 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1); 773 skippy_iter.set_match_func (match_func, match_data, input); 774 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 775 776 /* 777 * This is perhaps the trickiest part of OpenType... Remarks: 778 * 779 * - If all components of the ligature were marks, we call this a mark ligature. 780 * 781 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize 782 * it as a ligature glyph. 783 * 784 * - Ligatures cannot be formed across glyphs attached to different components 785 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and 786 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother. 787 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o 788 * There is an exception to this: If a ligature tries ligating with marks that 789 * belong to it itself, go ahead, assuming that the font designer knows what 790 * they are doing (otherwise it can break Indic stuff when a matra wants to 791 * ligate with a conjunct...) 792 */ 793 794 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur()); 795 796 unsigned int total_component_count = 0; 797 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 798 799 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 800 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); 801 802 match_positions[0] = buffer->idx; 803 for (unsigned int i = 1; i < count; i++) 804 { 805 if (!skippy_iter.next ()) return TRACE_RETURN (false); 806 807 match_positions[i] = skippy_iter.idx; 808 809 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); 810 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); 811 812 if (first_lig_id && first_lig_comp) { 813 /* If first component was attached to a previous ligature component, 814 * all subsequent components should be attached to the same ligature 815 * component, otherwise we shouldn't ligate them. */ 816 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) 817 return TRACE_RETURN (false); 818 } else { 819 /* If first component was NOT attached to a previous ligature component, 820 * all subsequent components should also NOT be attached to any ligature 821 * component, unless they are attached to the first component itself! */ 822 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id)) 823 return TRACE_RETURN (false); 824 } 825 826 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]); 827 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); 828 } 829 830 *end_offset = skippy_iter.idx - buffer->idx + 1; 831 832 if (p_is_mark_ligature) 833 *p_is_mark_ligature = is_mark_ligature; 834 835 if (p_total_component_count) 836 *p_total_component_count = total_component_count; 837 838 return TRACE_RETURN (true); 839} 840static inline void ligate_input (hb_apply_context_t *c, 841 unsigned int count, /* Including the first glyph */ 842 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ 843 unsigned int match_length, 844 hb_codepoint_t lig_glyph, 845 bool is_mark_ligature, 846 unsigned int total_component_count) 847{ 848 TRACE_APPLY (NULL); 849 850 hb_buffer_t *buffer = c->buffer; 851 852 buffer->merge_clusters (buffer->idx, buffer->idx + match_length); 853 854 /* 855 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave 856 * the ligature to keep its old ligature id. This will allow it to attach to 857 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH, 858 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a 859 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature 860 * later, we don't want them to lose their ligature id/component, otherwise 861 * GPOS will fail to correctly position the mark ligature on top of the 862 * LAM,LAM,HEH ligature. See: 863 * https://bugzilla.gnome.org/show_bug.cgi?id=676343 864 * 865 * - If a ligature is formed of components that some of which are also ligatures 866 * themselves, and those ligature components had marks attached to *their* 867 * components, we have to attach the marks to the new ligature component 868 * positions! Now *that*'s tricky! And these marks may be following the 869 * last component of the whole sequence, so we should loop forward looking 870 * for them and update them. 871 * 872 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a 873 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature 874 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature 875 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to 876 * the new ligature with a component value of 2. 877 * 878 * This in fact happened to a font... See: 879 * https://bugzilla.gnome.org/show_bug.cgi?id=437633 880 */ 881 882 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; 883 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer); 884 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 885 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 886 unsigned int components_so_far = last_num_components; 887 888 if (!is_mark_ligature) 889 { 890 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count); 891 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 892 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER); 893 } 894 c->replace_glyph_with_ligature (lig_glyph, klass); 895 896 for (unsigned int i = 1; i < count; i++) 897 { 898 while (buffer->idx < match_positions[i]) 899 { 900 if (!is_mark_ligature) { 901 unsigned int new_lig_comp = components_so_far - last_num_components + 902 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components); 903 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp); 904 } 905 buffer->next_glyph (); 906 } 907 908 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 909 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 910 components_so_far += last_num_components; 911 912 /* Skip the base glyph */ 913 buffer->idx++; 914 } 915 916 if (!is_mark_ligature && last_lig_id) { 917 /* Re-adjust components for any marks following. */ 918 for (unsigned int i = buffer->idx; i < buffer->len; i++) { 919 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) { 920 unsigned int new_lig_comp = components_so_far - last_num_components + 921 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components); 922 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp); 923 } else 924 break; 925 } 926 } 927} 928 929static inline bool match_backtrack (hb_apply_context_t *c, 930 unsigned int count, 931 const USHORT backtrack[], 932 match_func_t match_func, 933 const void *match_data) 934{ 935 TRACE_APPLY (NULL); 936 937 hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true); 938 skippy_iter.set_match_func (match_func, match_data, backtrack); 939 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 940 941 for (unsigned int i = 0; i < count; i++) 942 if (!skippy_iter.prev ()) 943 return TRACE_RETURN (false); 944 945 return TRACE_RETURN (true); 946} 947 948static inline bool match_lookahead (hb_apply_context_t *c, 949 unsigned int count, 950 const USHORT lookahead[], 951 match_func_t match_func, 952 const void *match_data, 953 unsigned int offset) 954{ 955 TRACE_APPLY (NULL); 956 957 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true); 958 skippy_iter.set_match_func (match_func, match_data, lookahead); 959 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 960 961 for (unsigned int i = 0; i < count; i++) 962 if (!skippy_iter.next ()) 963 return TRACE_RETURN (false); 964 965 return TRACE_RETURN (true); 966} 967 968 969 970struct LookupRecord 971{ 972 inline bool sanitize (hb_sanitize_context_t *c) { 973 TRACE_SANITIZE (this); 974 return TRACE_RETURN (c->check_struct (this)); 975 } 976 977 USHORT sequenceIndex; /* Index into current glyph 978 * sequence--first glyph = 0 */ 979 USHORT lookupListIndex; /* Lookup to apply to that 980 * position--zero--based */ 981 public: 982 DEFINE_SIZE_STATIC (4); 983}; 984 985 986template <typename context_t> 987static inline void recurse_lookups (context_t *c, 988 unsigned int lookupCount, 989 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) 990{ 991 for (unsigned int i = 0; i < lookupCount; i++) 992 c->recurse (lookupRecord[i].lookupListIndex); 993} 994 995static inline bool apply_lookup (hb_apply_context_t *c, 996 unsigned int count, /* Including the first glyph */ 997 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ 998 unsigned int lookupCount, 999 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ 1000 unsigned int match_length) 1001{ 1002 TRACE_APPLY (NULL); 1003 1004 hb_buffer_t *buffer = c->buffer; 1005 unsigned int end; 1006 1007 /* All positions are distance from beginning of *output* buffer. 1008 * Adjust. */ 1009 { 1010 unsigned int bl = buffer->backtrack_len (); 1011 end = bl + match_length; 1012 1013 int delta = bl - buffer->idx; 1014 /* Convert positions to new indexing. */ 1015 for (unsigned int j = 0; j < count; j++) 1016 match_positions[j] += delta; 1017 } 1018 1019 for (unsigned int i = 0; i < lookupCount; i++) 1020 { 1021 unsigned int idx = lookupRecord[i].sequenceIndex; 1022 if (idx >= count) 1023 continue; 1024 1025 buffer->move_to (match_positions[idx]); 1026 1027 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); 1028 if (!c->recurse (lookupRecord[i].lookupListIndex)) 1029 continue; 1030 1031 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len (); 1032 int delta = new_len - orig_len; 1033 1034 if (!delta) 1035 continue; 1036 1037 /* Recursed lookup changed buffer len. Adjust. */ 1038 1039 /* end can't go back past the current match position. */ 1040 end = MAX ((int) match_positions[idx] + 1, int (end) + delta); 1041 1042 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */ 1043 1044 if (delta > 0) 1045 { 1046 if (unlikely (delta + count > MAX_CONTEXT_LENGTH)) 1047 break; 1048 } 1049 else 1050 { 1051 /* NOTE: delta is negative. */ 1052 delta = MAX (delta, (int) next - (int) count); 1053 next -= delta; 1054 } 1055 1056 /* Shift! */ 1057 memmove (match_positions + next + delta, match_positions + next, 1058 (count - next) * sizeof (match_positions[0])); 1059 next += delta; 1060 count += delta; 1061 1062 /* Fill in new entries. */ 1063 for (unsigned int j = idx + 1; j < next; j++) 1064 match_positions[j] = match_positions[j - 1] + 1; 1065 1066 /* And fixup the rest. */ 1067 for (; next < count; next++) 1068 match_positions[next] += delta; 1069 } 1070 1071 buffer->move_to (end); 1072 1073 return TRACE_RETURN (true); 1074} 1075 1076 1077 1078/* Contextual lookups */ 1079 1080struct ContextClosureLookupContext 1081{ 1082 ContextClosureFuncs funcs; 1083 const void *intersects_data; 1084}; 1085 1086struct ContextCollectGlyphsLookupContext 1087{ 1088 ContextCollectGlyphsFuncs funcs; 1089 const void *collect_data; 1090}; 1091 1092struct ContextApplyLookupContext 1093{ 1094 ContextApplyFuncs funcs; 1095 const void *match_data; 1096}; 1097 1098static inline void context_closure_lookup (hb_closure_context_t *c, 1099 unsigned int inputCount, /* Including the first glyph (not matched) */ 1100 const USHORT input[], /* Array of input values--start with second glyph */ 1101 unsigned int lookupCount, 1102 const LookupRecord lookupRecord[], 1103 ContextClosureLookupContext &lookup_context) 1104{ 1105 if (intersects_array (c, 1106 inputCount ? inputCount - 1 : 0, input, 1107 lookup_context.funcs.intersects, lookup_context.intersects_data)) 1108 recurse_lookups (c, 1109 lookupCount, lookupRecord); 1110} 1111 1112static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 1113 unsigned int inputCount, /* Including the first glyph (not matched) */ 1114 const USHORT input[], /* Array of input values--start with second glyph */ 1115 unsigned int lookupCount, 1116 const LookupRecord lookupRecord[], 1117 ContextCollectGlyphsLookupContext &lookup_context) 1118{ 1119 collect_array (c, c->input, 1120 inputCount ? inputCount - 1 : 0, input, 1121 lookup_context.funcs.collect, lookup_context.collect_data); 1122 recurse_lookups (c, 1123 lookupCount, lookupRecord); 1124} 1125 1126static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, 1127 unsigned int inputCount, /* Including the first glyph (not matched) */ 1128 const USHORT input[], /* Array of input values--start with second glyph */ 1129 unsigned int lookupCount HB_UNUSED, 1130 const LookupRecord lookupRecord[] HB_UNUSED, 1131 ContextApplyLookupContext &lookup_context) 1132{ 1133 return would_match_input (c, 1134 inputCount, input, 1135 lookup_context.funcs.match, lookup_context.match_data); 1136} 1137static inline bool context_apply_lookup (hb_apply_context_t *c, 1138 unsigned int inputCount, /* Including the first glyph (not matched) */ 1139 const USHORT input[], /* Array of input values--start with second glyph */ 1140 unsigned int lookupCount, 1141 const LookupRecord lookupRecord[], 1142 ContextApplyLookupContext &lookup_context) 1143{ 1144 unsigned int match_length = 0; 1145 unsigned int match_positions[MAX_CONTEXT_LENGTH]; 1146 return match_input (c, 1147 inputCount, input, 1148 lookup_context.funcs.match, lookup_context.match_data, 1149 &match_length, match_positions) 1150 && apply_lookup (c, 1151 inputCount, match_positions, 1152 lookupCount, lookupRecord, 1153 match_length); 1154} 1155 1156struct Rule 1157{ 1158 inline bool is_inplace (hb_is_inplace_context_t *c) const 1159 { 1160 TRACE_IS_INPLACE (this); 1161 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1162 unsigned int count = lookupCount; 1163 for (unsigned int i = 0; i < count; i++) 1164 if (!c->recurse (lookupRecord[i].lookupListIndex)) 1165 return TRACE_RETURN (false); 1166 return TRACE_RETURN (true); 1167 } 1168 1169 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 1170 { 1171 TRACE_CLOSURE (this); 1172 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1173 context_closure_lookup (c, 1174 inputCount, input, 1175 lookupCount, lookupRecord, 1176 lookup_context); 1177 } 1178 1179 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const 1180 { 1181 TRACE_COLLECT_GLYPHS (this); 1182 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1183 context_collect_glyphs_lookup (c, 1184 inputCount, input, 1185 lookupCount, lookupRecord, 1186 lookup_context); 1187 } 1188 1189 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1190 { 1191 TRACE_WOULD_APPLY (this); 1192 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1193 return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); 1194 } 1195 1196 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1197 { 1198 TRACE_APPLY (this); 1199 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1200 return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); 1201 } 1202 1203 public: 1204 inline bool sanitize (hb_sanitize_context_t *c) { 1205 TRACE_SANITIZE (this); 1206 return inputCount.sanitize (c) 1207 && lookupCount.sanitize (c) 1208 && c->check_range (input, 1209 input[0].static_size * inputCount 1210 + lookupRecordX[0].static_size * lookupCount); 1211 } 1212 1213 protected: 1214 USHORT inputCount; /* Total number of glyphs in input 1215 * glyph sequence--includes the first 1216 * glyph */ 1217 USHORT lookupCount; /* Number of LookupRecords */ 1218 USHORT input[VAR]; /* Array of match inputs--start with 1219 * second glyph */ 1220 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 1221 * design order */ 1222 public: 1223 DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX); 1224}; 1225 1226struct RuleSet 1227{ 1228 inline bool is_inplace (hb_is_inplace_context_t *c) const 1229 { 1230 TRACE_IS_INPLACE (this); 1231 unsigned int num_rules = rule.len; 1232 for (unsigned int i = 0; i < num_rules; i++) 1233 if (!(this+rule[i]).is_inplace (c)) 1234 return TRACE_RETURN (false); 1235 return TRACE_RETURN (true); 1236 } 1237 1238 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 1239 { 1240 TRACE_CLOSURE (this); 1241 unsigned int num_rules = rule.len; 1242 for (unsigned int i = 0; i < num_rules; i++) 1243 (this+rule[i]).closure (c, lookup_context); 1244 } 1245 1246 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const 1247 { 1248 TRACE_COLLECT_GLYPHS (this); 1249 unsigned int num_rules = rule.len; 1250 for (unsigned int i = 0; i < num_rules; i++) 1251 (this+rule[i]).collect_glyphs (c, lookup_context); 1252 } 1253 1254 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1255 { 1256 TRACE_WOULD_APPLY (this); 1257 unsigned int num_rules = rule.len; 1258 for (unsigned int i = 0; i < num_rules; i++) 1259 { 1260 if ((this+rule[i]).would_apply (c, lookup_context)) 1261 return TRACE_RETURN (true); 1262 } 1263 return TRACE_RETURN (false); 1264 } 1265 1266 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1267 { 1268 TRACE_APPLY (this); 1269 unsigned int num_rules = rule.len; 1270 for (unsigned int i = 0; i < num_rules; i++) 1271 { 1272 if ((this+rule[i]).apply (c, lookup_context)) 1273 return TRACE_RETURN (true); 1274 } 1275 return TRACE_RETURN (false); 1276 } 1277 1278 inline bool sanitize (hb_sanitize_context_t *c) { 1279 TRACE_SANITIZE (this); 1280 return TRACE_RETURN (rule.sanitize (c, this)); 1281 } 1282 1283 protected: 1284 OffsetArrayOf<Rule> 1285 rule; /* Array of Rule tables 1286 * ordered by preference */ 1287 public: 1288 DEFINE_SIZE_ARRAY (2, rule); 1289}; 1290 1291 1292struct ContextFormat1 1293{ 1294 inline bool is_inplace (hb_is_inplace_context_t *c) const 1295 { 1296 TRACE_IS_INPLACE (this); 1297 unsigned int count = ruleSet.len; 1298 for (unsigned int i = 0; i < count; i++) 1299 if (!(this+ruleSet[i]).is_inplace (c)) 1300 return TRACE_RETURN (false); 1301 return TRACE_RETURN (true); 1302 } 1303 1304 inline void closure (hb_closure_context_t *c) const 1305 { 1306 TRACE_CLOSURE (this); 1307 1308 const Coverage &cov = (this+coverage); 1309 1310 struct ContextClosureLookupContext lookup_context = { 1311 {intersects_glyph}, 1312 NULL 1313 }; 1314 1315 unsigned int count = ruleSet.len; 1316 for (unsigned int i = 0; i < count; i++) 1317 if (cov.intersects_coverage (c->glyphs, i)) { 1318 const RuleSet &rule_set = this+ruleSet[i]; 1319 rule_set.closure (c, lookup_context); 1320 } 1321 } 1322 1323 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1324 { 1325 TRACE_COLLECT_GLYPHS (this); 1326 (this+coverage).add_coverage (c->input); 1327 1328 struct ContextCollectGlyphsLookupContext lookup_context = { 1329 {collect_glyph}, 1330 NULL 1331 }; 1332 1333 unsigned int count = ruleSet.len; 1334 for (unsigned int i = 0; i < count; i++) 1335 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1336 } 1337 1338 inline bool would_apply (hb_would_apply_context_t *c) const 1339 { 1340 TRACE_WOULD_APPLY (this); 1341 1342 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 1343 struct ContextApplyLookupContext lookup_context = { 1344 {match_glyph}, 1345 NULL 1346 }; 1347 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1348 } 1349 1350 inline const Coverage &get_coverage (void) const 1351 { 1352 return this+coverage; 1353 } 1354 1355 inline bool apply (hb_apply_context_t *c) const 1356 { 1357 TRACE_APPLY (this); 1358 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1359 if (likely (index == NOT_COVERED)) 1360 return TRACE_RETURN (false); 1361 1362 const RuleSet &rule_set = this+ruleSet[index]; 1363 struct ContextApplyLookupContext lookup_context = { 1364 {match_glyph}, 1365 NULL 1366 }; 1367 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1368 } 1369 1370 inline bool sanitize (hb_sanitize_context_t *c) { 1371 TRACE_SANITIZE (this); 1372 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1373 } 1374 1375 protected: 1376 USHORT format; /* Format identifier--format = 1 */ 1377 OffsetTo<Coverage> 1378 coverage; /* Offset to Coverage table--from 1379 * beginning of table */ 1380 OffsetArrayOf<RuleSet> 1381 ruleSet; /* Array of RuleSet tables 1382 * ordered by Coverage Index */ 1383 public: 1384 DEFINE_SIZE_ARRAY (6, ruleSet); 1385}; 1386 1387 1388struct ContextFormat2 1389{ 1390 inline bool is_inplace (hb_is_inplace_context_t *c) const 1391 { 1392 TRACE_IS_INPLACE (this); 1393 unsigned int count = ruleSet.len; 1394 for (unsigned int i = 0; i < count; i++) 1395 if (!(this+ruleSet[i]).is_inplace (c)) 1396 return TRACE_RETURN (false); 1397 return TRACE_RETURN (true); 1398 } 1399 1400 inline void closure (hb_closure_context_t *c) const 1401 { 1402 TRACE_CLOSURE (this); 1403 if (!(this+coverage).intersects (c->glyphs)) 1404 return; 1405 1406 const ClassDef &class_def = this+classDef; 1407 1408 struct ContextClosureLookupContext lookup_context = { 1409 {intersects_class}, 1410 &class_def 1411 }; 1412 1413 unsigned int count = ruleSet.len; 1414 for (unsigned int i = 0; i < count; i++) 1415 if (class_def.intersects_class (c->glyphs, i)) { 1416 const RuleSet &rule_set = this+ruleSet[i]; 1417 rule_set.closure (c, lookup_context); 1418 } 1419 } 1420 1421 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1422 { 1423 TRACE_COLLECT_GLYPHS (this); 1424 (this+coverage).add_coverage (c->input); 1425 1426 const ClassDef &class_def = this+classDef; 1427 struct ContextCollectGlyphsLookupContext lookup_context = { 1428 {collect_class}, 1429 &class_def 1430 }; 1431 1432 unsigned int count = ruleSet.len; 1433 for (unsigned int i = 0; i < count; i++) 1434 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1435 } 1436 1437 inline bool would_apply (hb_would_apply_context_t *c) const 1438 { 1439 TRACE_WOULD_APPLY (this); 1440 1441 const ClassDef &class_def = this+classDef; 1442 unsigned int index = class_def.get_class (c->glyphs[0]); 1443 const RuleSet &rule_set = this+ruleSet[index]; 1444 struct ContextApplyLookupContext lookup_context = { 1445 {match_class}, 1446 &class_def 1447 }; 1448 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1449 } 1450 1451 inline const Coverage &get_coverage (void) const 1452 { 1453 return this+coverage; 1454 } 1455 1456 inline bool apply (hb_apply_context_t *c) const 1457 { 1458 TRACE_APPLY (this); 1459 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1460 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1461 1462 const ClassDef &class_def = this+classDef; 1463 index = class_def.get_class (c->buffer->cur().codepoint); 1464 const RuleSet &rule_set = this+ruleSet[index]; 1465 struct ContextApplyLookupContext lookup_context = { 1466 {match_class}, 1467 &class_def 1468 }; 1469 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1470 } 1471 1472 inline bool sanitize (hb_sanitize_context_t *c) { 1473 TRACE_SANITIZE (this); 1474 return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); 1475 } 1476 1477 protected: 1478 USHORT format; /* Format identifier--format = 2 */ 1479 OffsetTo<Coverage> 1480 coverage; /* Offset to Coverage table--from 1481 * beginning of table */ 1482 OffsetTo<ClassDef> 1483 classDef; /* Offset to glyph ClassDef table--from 1484 * beginning of table */ 1485 OffsetArrayOf<RuleSet> 1486 ruleSet; /* Array of RuleSet tables 1487 * ordered by class */ 1488 public: 1489 DEFINE_SIZE_ARRAY (8, ruleSet); 1490}; 1491 1492 1493struct ContextFormat3 1494{ 1495 inline bool is_inplace (hb_is_inplace_context_t *c) const 1496 { 1497 TRACE_IS_INPLACE (this); 1498 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1499 unsigned int count = lookupCount; 1500 for (unsigned int i = 0; i < count; i++) 1501 if (!c->recurse (lookupRecord[i].lookupListIndex)) 1502 return TRACE_RETURN (false); 1503 return TRACE_RETURN (true); 1504 } 1505 1506 inline void closure (hb_closure_context_t *c) const 1507 { 1508 TRACE_CLOSURE (this); 1509 if (!(this+coverage[0]).intersects (c->glyphs)) 1510 return; 1511 1512 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1513 struct ContextClosureLookupContext lookup_context = { 1514 {intersects_coverage}, 1515 this 1516 }; 1517 context_closure_lookup (c, 1518 glyphCount, (const USHORT *) (coverage + 1), 1519 lookupCount, lookupRecord, 1520 lookup_context); 1521 } 1522 1523 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1524 { 1525 TRACE_COLLECT_GLYPHS (this); 1526 (this+coverage[0]).add_coverage (c->input); 1527 1528 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1529 struct ContextCollectGlyphsLookupContext lookup_context = { 1530 {collect_coverage}, 1531 this 1532 }; 1533 1534 context_collect_glyphs_lookup (c, 1535 glyphCount, (const USHORT *) (coverage + 1), 1536 lookupCount, lookupRecord, 1537 lookup_context); 1538 } 1539 1540 inline bool would_apply (hb_would_apply_context_t *c) const 1541 { 1542 TRACE_WOULD_APPLY (this); 1543 1544 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1545 struct ContextApplyLookupContext lookup_context = { 1546 {match_coverage}, 1547 this 1548 }; 1549 return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); 1550 } 1551 1552 inline const Coverage &get_coverage (void) const 1553 { 1554 return this+coverage[0]; 1555 } 1556 1557 inline bool apply (hb_apply_context_t *c) const 1558 { 1559 TRACE_APPLY (this); 1560 unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint); 1561 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1562 1563 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1564 struct ContextApplyLookupContext lookup_context = { 1565 {match_coverage}, 1566 this 1567 }; 1568 return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); 1569 } 1570 1571 inline bool sanitize (hb_sanitize_context_t *c) { 1572 TRACE_SANITIZE (this); 1573 if (!c->check_struct (this)) return TRACE_RETURN (false); 1574 unsigned int count = glyphCount; 1575 if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false); 1576 for (unsigned int i = 0; i < count; i++) 1577 if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false); 1578 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count); 1579 return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); 1580 } 1581 1582 protected: 1583 USHORT format; /* Format identifier--format = 3 */ 1584 USHORT glyphCount; /* Number of glyphs in the input glyph 1585 * sequence */ 1586 USHORT lookupCount; /* Number of LookupRecords */ 1587 OffsetTo<Coverage> 1588 coverage[VAR]; /* Array of offsets to Coverage 1589 * table in glyph sequence order */ 1590 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 1591 * design order */ 1592 public: 1593 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX); 1594}; 1595 1596struct Context 1597{ 1598 template <typename context_t> 1599 inline typename context_t::return_t dispatch (context_t *c) const 1600 { 1601 TRACE_DISPATCH (this); 1602 switch (u.format) { 1603 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1604 case 2: return TRACE_RETURN (c->dispatch (u.format2)); 1605 case 3: return TRACE_RETURN (c->dispatch (u.format3)); 1606 default:return TRACE_RETURN (c->default_return_value ()); 1607 } 1608 } 1609 1610 inline bool sanitize (hb_sanitize_context_t *c) { 1611 TRACE_SANITIZE (this); 1612 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1613 switch (u.format) { 1614 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1615 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1616 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1617 default:return TRACE_RETURN (true); 1618 } 1619 } 1620 1621 protected: 1622 union { 1623 USHORT format; /* Format identifier */ 1624 ContextFormat1 format1; 1625 ContextFormat2 format2; 1626 ContextFormat3 format3; 1627 } u; 1628}; 1629 1630 1631/* Chaining Contextual lookups */ 1632 1633struct ChainContextClosureLookupContext 1634{ 1635 ContextClosureFuncs funcs; 1636 const void *intersects_data[3]; 1637}; 1638 1639struct ChainContextCollectGlyphsLookupContext 1640{ 1641 ContextCollectGlyphsFuncs funcs; 1642 const void *collect_data[3]; 1643}; 1644 1645struct ChainContextApplyLookupContext 1646{ 1647 ContextApplyFuncs funcs; 1648 const void *match_data[3]; 1649}; 1650 1651static inline void chain_context_closure_lookup (hb_closure_context_t *c, 1652 unsigned int backtrackCount, 1653 const USHORT backtrack[], 1654 unsigned int inputCount, /* Including the first glyph (not matched) */ 1655 const USHORT input[], /* Array of input values--start with second glyph */ 1656 unsigned int lookaheadCount, 1657 const USHORT lookahead[], 1658 unsigned int lookupCount, 1659 const LookupRecord lookupRecord[], 1660 ChainContextClosureLookupContext &lookup_context) 1661{ 1662 if (intersects_array (c, 1663 backtrackCount, backtrack, 1664 lookup_context.funcs.intersects, lookup_context.intersects_data[0]) 1665 && intersects_array (c, 1666 inputCount ? inputCount - 1 : 0, input, 1667 lookup_context.funcs.intersects, lookup_context.intersects_data[1]) 1668 && intersects_array (c, 1669 lookaheadCount, lookahead, 1670 lookup_context.funcs.intersects, lookup_context.intersects_data[2])) 1671 recurse_lookups (c, 1672 lookupCount, lookupRecord); 1673} 1674 1675static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 1676 unsigned int backtrackCount, 1677 const USHORT backtrack[], 1678 unsigned int inputCount, /* Including the first glyph (not matched) */ 1679 const USHORT input[], /* Array of input values--start with second glyph */ 1680 unsigned int lookaheadCount, 1681 const USHORT lookahead[], 1682 unsigned int lookupCount, 1683 const LookupRecord lookupRecord[], 1684 ChainContextCollectGlyphsLookupContext &lookup_context) 1685{ 1686 collect_array (c, c->before, 1687 backtrackCount, backtrack, 1688 lookup_context.funcs.collect, lookup_context.collect_data[0]); 1689 collect_array (c, c->input, 1690 inputCount ? inputCount - 1 : 0, input, 1691 lookup_context.funcs.collect, lookup_context.collect_data[1]); 1692 collect_array (c, c->after, 1693 lookaheadCount, lookahead, 1694 lookup_context.funcs.collect, lookup_context.collect_data[2]); 1695 recurse_lookups (c, 1696 lookupCount, lookupRecord); 1697} 1698 1699static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, 1700 unsigned int backtrackCount, 1701 const USHORT backtrack[] HB_UNUSED, 1702 unsigned int inputCount, /* Including the first glyph (not matched) */ 1703 const USHORT input[], /* Array of input values--start with second glyph */ 1704 unsigned int lookaheadCount, 1705 const USHORT lookahead[] HB_UNUSED, 1706 unsigned int lookupCount HB_UNUSED, 1707 const LookupRecord lookupRecord[] HB_UNUSED, 1708 ChainContextApplyLookupContext &lookup_context) 1709{ 1710 return (c->zero_context ? !backtrackCount && !lookaheadCount : true) 1711 && would_match_input (c, 1712 inputCount, input, 1713 lookup_context.funcs.match, lookup_context.match_data[1]); 1714} 1715 1716static inline bool chain_context_apply_lookup (hb_apply_context_t *c, 1717 unsigned int backtrackCount, 1718 const USHORT backtrack[], 1719 unsigned int inputCount, /* Including the first glyph (not matched) */ 1720 const USHORT input[], /* Array of input values--start with second glyph */ 1721 unsigned int lookaheadCount, 1722 const USHORT lookahead[], 1723 unsigned int lookupCount, 1724 const LookupRecord lookupRecord[], 1725 ChainContextApplyLookupContext &lookup_context) 1726{ 1727 unsigned int match_length = 0; 1728 unsigned int match_positions[MAX_CONTEXT_LENGTH]; 1729 return match_input (c, 1730 inputCount, input, 1731 lookup_context.funcs.match, lookup_context.match_data[1], 1732 &match_length, match_positions) 1733 && match_backtrack (c, 1734 backtrackCount, backtrack, 1735 lookup_context.funcs.match, lookup_context.match_data[0]) 1736 && match_lookahead (c, 1737 lookaheadCount, lookahead, 1738 lookup_context.funcs.match, lookup_context.match_data[2], 1739 match_length) 1740 && apply_lookup (c, 1741 inputCount, match_positions, 1742 lookupCount, lookupRecord, 1743 match_length); 1744} 1745 1746struct ChainRule 1747{ 1748 inline bool is_inplace (hb_is_inplace_context_t *c) const 1749 { 1750 TRACE_IS_INPLACE (this); 1751 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1752 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1753 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1754 unsigned int count = lookup.len; 1755 for (unsigned int i = 0; i < count; i++) 1756 if (!c->recurse (lookup.array[i].lookupListIndex)) 1757 return TRACE_RETURN (false); 1758 return TRACE_RETURN (true); 1759 } 1760 1761 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1762 { 1763 TRACE_CLOSURE (this); 1764 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1765 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1766 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1767 chain_context_closure_lookup (c, 1768 backtrack.len, backtrack.array, 1769 input.len, input.array, 1770 lookahead.len, lookahead.array, 1771 lookup.len, lookup.array, 1772 lookup_context); 1773 } 1774 1775 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const 1776 { 1777 TRACE_COLLECT_GLYPHS (this); 1778 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1779 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1780 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1781 chain_context_collect_glyphs_lookup (c, 1782 backtrack.len, backtrack.array, 1783 input.len, input.array, 1784 lookahead.len, lookahead.array, 1785 lookup.len, lookup.array, 1786 lookup_context); 1787 } 1788 1789 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1790 { 1791 TRACE_WOULD_APPLY (this); 1792 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1793 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1794 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1795 return TRACE_RETURN (chain_context_would_apply_lookup (c, 1796 backtrack.len, backtrack.array, 1797 input.len, input.array, 1798 lookahead.len, lookahead.array, lookup.len, 1799 lookup.array, lookup_context)); 1800 } 1801 1802 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1803 { 1804 TRACE_APPLY (this); 1805 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1806 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1807 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1808 return TRACE_RETURN (chain_context_apply_lookup (c, 1809 backtrack.len, backtrack.array, 1810 input.len, input.array, 1811 lookahead.len, lookahead.array, lookup.len, 1812 lookup.array, lookup_context)); 1813 } 1814 1815 inline bool sanitize (hb_sanitize_context_t *c) { 1816 TRACE_SANITIZE (this); 1817 if (!backtrack.sanitize (c)) return TRACE_RETURN (false); 1818 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1819 if (!input.sanitize (c)) return TRACE_RETURN (false); 1820 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1821 if (!lookahead.sanitize (c)) return TRACE_RETURN (false); 1822 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1823 return TRACE_RETURN (lookup.sanitize (c)); 1824 } 1825 1826 protected: 1827 ArrayOf<USHORT> 1828 backtrack; /* Array of backtracking values 1829 * (to be matched before the input 1830 * sequence) */ 1831 HeadlessArrayOf<USHORT> 1832 inputX; /* Array of input values (start with 1833 * second glyph) */ 1834 ArrayOf<USHORT> 1835 lookaheadX; /* Array of lookahead values's (to be 1836 * matched after the input sequence) */ 1837 ArrayOf<LookupRecord> 1838 lookupX; /* Array of LookupRecords--in 1839 * design order) */ 1840 public: 1841 DEFINE_SIZE_MIN (8); 1842}; 1843 1844struct ChainRuleSet 1845{ 1846 inline bool is_inplace (hb_is_inplace_context_t *c) const 1847 { 1848 TRACE_IS_INPLACE (this); 1849 unsigned int num_rules = rule.len; 1850 for (unsigned int i = 0; i < num_rules; i++) 1851 if (!(this+rule[i]).is_inplace (c)) 1852 return TRACE_RETURN (false); 1853 return TRACE_RETURN (true); 1854 } 1855 1856 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1857 { 1858 TRACE_CLOSURE (this); 1859 unsigned int num_rules = rule.len; 1860 for (unsigned int i = 0; i < num_rules; i++) 1861 (this+rule[i]).closure (c, lookup_context); 1862 } 1863 1864 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const 1865 { 1866 TRACE_COLLECT_GLYPHS (this); 1867 unsigned int num_rules = rule.len; 1868 for (unsigned int i = 0; i < num_rules; i++) 1869 (this+rule[i]).collect_glyphs (c, lookup_context); 1870 } 1871 1872 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1873 { 1874 TRACE_WOULD_APPLY (this); 1875 unsigned int num_rules = rule.len; 1876 for (unsigned int i = 0; i < num_rules; i++) 1877 if ((this+rule[i]).would_apply (c, lookup_context)) 1878 return TRACE_RETURN (true); 1879 1880 return TRACE_RETURN (false); 1881 } 1882 1883 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1884 { 1885 TRACE_APPLY (this); 1886 unsigned int num_rules = rule.len; 1887 for (unsigned int i = 0; i < num_rules; i++) 1888 if ((this+rule[i]).apply (c, lookup_context)) 1889 return TRACE_RETURN (true); 1890 1891 return TRACE_RETURN (false); 1892 } 1893 1894 inline bool sanitize (hb_sanitize_context_t *c) { 1895 TRACE_SANITIZE (this); 1896 return TRACE_RETURN (rule.sanitize (c, this)); 1897 } 1898 1899 protected: 1900 OffsetArrayOf<ChainRule> 1901 rule; /* Array of ChainRule tables 1902 * ordered by preference */ 1903 public: 1904 DEFINE_SIZE_ARRAY (2, rule); 1905}; 1906 1907struct ChainContextFormat1 1908{ 1909 inline bool is_inplace (hb_is_inplace_context_t *c) const 1910 { 1911 TRACE_IS_INPLACE (this); 1912 unsigned int count = ruleSet.len; 1913 for (unsigned int i = 0; i < count; i++) 1914 if (!(this+ruleSet[i]).is_inplace (c)) 1915 return TRACE_RETURN (false); 1916 return TRACE_RETURN (true); 1917 } 1918 1919 inline void closure (hb_closure_context_t *c) const 1920 { 1921 TRACE_CLOSURE (this); 1922 const Coverage &cov = (this+coverage); 1923 1924 struct ChainContextClosureLookupContext lookup_context = { 1925 {intersects_glyph}, 1926 {NULL, NULL, NULL} 1927 }; 1928 1929 unsigned int count = ruleSet.len; 1930 for (unsigned int i = 0; i < count; i++) 1931 if (cov.intersects_coverage (c->glyphs, i)) { 1932 const ChainRuleSet &rule_set = this+ruleSet[i]; 1933 rule_set.closure (c, lookup_context); 1934 } 1935 } 1936 1937 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1938 { 1939 TRACE_COLLECT_GLYPHS (this); 1940 (this+coverage).add_coverage (c->input); 1941 1942 struct ChainContextCollectGlyphsLookupContext lookup_context = { 1943 {collect_glyph}, 1944 {NULL, NULL, NULL} 1945 }; 1946 1947 unsigned int count = ruleSet.len; 1948 for (unsigned int i = 0; i < count; i++) 1949 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1950 } 1951 1952 inline bool would_apply (hb_would_apply_context_t *c) const 1953 { 1954 TRACE_WOULD_APPLY (this); 1955 1956 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 1957 struct ChainContextApplyLookupContext lookup_context = { 1958 {match_glyph}, 1959 {NULL, NULL, NULL} 1960 }; 1961 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1962 } 1963 1964 inline const Coverage &get_coverage (void) const 1965 { 1966 return this+coverage; 1967 } 1968 1969 inline bool apply (hb_apply_context_t *c) const 1970 { 1971 TRACE_APPLY (this); 1972 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1973 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1974 1975 const ChainRuleSet &rule_set = this+ruleSet[index]; 1976 struct ChainContextApplyLookupContext lookup_context = { 1977 {match_glyph}, 1978 {NULL, NULL, NULL} 1979 }; 1980 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1981 } 1982 1983 inline bool sanitize (hb_sanitize_context_t *c) { 1984 TRACE_SANITIZE (this); 1985 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1986 } 1987 1988 protected: 1989 USHORT format; /* Format identifier--format = 1 */ 1990 OffsetTo<Coverage> 1991 coverage; /* Offset to Coverage table--from 1992 * beginning of table */ 1993 OffsetArrayOf<ChainRuleSet> 1994 ruleSet; /* Array of ChainRuleSet tables 1995 * ordered by Coverage Index */ 1996 public: 1997 DEFINE_SIZE_ARRAY (6, ruleSet); 1998}; 1999 2000struct ChainContextFormat2 2001{ 2002 inline bool is_inplace (hb_is_inplace_context_t *c) const 2003 { 2004 TRACE_IS_INPLACE (this); 2005 unsigned int count = ruleSet.len; 2006 for (unsigned int i = 0; i < count; i++) 2007 if (!(this+ruleSet[i]).is_inplace (c)) 2008 return TRACE_RETURN (false); 2009 return TRACE_RETURN (true); 2010 } 2011 2012 inline void closure (hb_closure_context_t *c) const 2013 { 2014 TRACE_CLOSURE (this); 2015 if (!(this+coverage).intersects (c->glyphs)) 2016 return; 2017 2018 const ClassDef &backtrack_class_def = this+backtrackClassDef; 2019 const ClassDef &input_class_def = this+inputClassDef; 2020 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 2021 2022 struct ChainContextClosureLookupContext lookup_context = { 2023 {intersects_class}, 2024 {&backtrack_class_def, 2025 &input_class_def, 2026 &lookahead_class_def} 2027 }; 2028 2029 unsigned int count = ruleSet.len; 2030 for (unsigned int i = 0; i < count; i++) 2031 if (input_class_def.intersects_class (c->glyphs, i)) { 2032 const ChainRuleSet &rule_set = this+ruleSet[i]; 2033 rule_set.closure (c, lookup_context); 2034 } 2035 } 2036 2037 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 2038 { 2039 TRACE_COLLECT_GLYPHS (this); 2040 (this+coverage).add_coverage (c->input); 2041 2042 const ClassDef &backtrack_class_def = this+backtrackClassDef; 2043 const ClassDef &input_class_def = this+inputClassDef; 2044 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 2045 2046 struct ChainContextCollectGlyphsLookupContext lookup_context = { 2047 {collect_class}, 2048 {&backtrack_class_def, 2049 &input_class_def, 2050 &lookahead_class_def} 2051 }; 2052 2053 unsigned int count = ruleSet.len; 2054 for (unsigned int i = 0; i < count; i++) 2055 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 2056 } 2057 2058 inline bool would_apply (hb_would_apply_context_t *c) const 2059 { 2060 TRACE_WOULD_APPLY (this); 2061 2062 const ClassDef &backtrack_class_def = this+backtrackClassDef; 2063 const ClassDef &input_class_def = this+inputClassDef; 2064 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 2065 2066 unsigned int index = input_class_def.get_class (c->glyphs[0]); 2067 const ChainRuleSet &rule_set = this+ruleSet[index]; 2068 struct ChainContextApplyLookupContext lookup_context = { 2069 {match_class}, 2070 {&backtrack_class_def, 2071 &input_class_def, 2072 &lookahead_class_def} 2073 }; 2074 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 2075 } 2076 2077 inline const Coverage &get_coverage (void) const 2078 { 2079 return this+coverage; 2080 } 2081 2082 inline bool apply (hb_apply_context_t *c) const 2083 { 2084 TRACE_APPLY (this); 2085 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 2086 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 2087 2088 const ClassDef &backtrack_class_def = this+backtrackClassDef; 2089 const ClassDef &input_class_def = this+inputClassDef; 2090 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 2091 2092 index = input_class_def.get_class (c->buffer->cur().codepoint); 2093 const ChainRuleSet &rule_set = this+ruleSet[index]; 2094 struct ChainContextApplyLookupContext lookup_context = { 2095 {match_class}, 2096 {&backtrack_class_def, 2097 &input_class_def, 2098 &lookahead_class_def} 2099 }; 2100 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 2101 } 2102 2103 inline bool sanitize (hb_sanitize_context_t *c) { 2104 TRACE_SANITIZE (this); 2105 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && 2106 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && 2107 ruleSet.sanitize (c, this)); 2108 } 2109 2110 protected: 2111 USHORT format; /* Format identifier--format = 2 */ 2112 OffsetTo<Coverage> 2113 coverage; /* Offset to Coverage table--from 2114 * beginning of table */ 2115 OffsetTo<ClassDef> 2116 backtrackClassDef; /* Offset to glyph ClassDef table 2117 * containing backtrack sequence 2118 * data--from beginning of table */ 2119 OffsetTo<ClassDef> 2120 inputClassDef; /* Offset to glyph ClassDef 2121 * table containing input sequence 2122 * data--from beginning of table */ 2123 OffsetTo<ClassDef> 2124 lookaheadClassDef; /* Offset to glyph ClassDef table 2125 * containing lookahead sequence 2126 * data--from beginning of table */ 2127 OffsetArrayOf<ChainRuleSet> 2128 ruleSet; /* Array of ChainRuleSet tables 2129 * ordered by class */ 2130 public: 2131 DEFINE_SIZE_ARRAY (12, ruleSet); 2132}; 2133 2134struct ChainContextFormat3 2135{ 2136 inline bool is_inplace (hb_is_inplace_context_t *c) const 2137 { 2138 TRACE_IS_INPLACE (this); 2139 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2140 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2141 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2142 2143 unsigned int count = lookup.len; 2144 for (unsigned int i = 0; i < count; i++) 2145 if (!c->recurse (lookup.array[i].lookupListIndex)) 2146 return TRACE_RETURN (false); 2147 return TRACE_RETURN (true); 2148 } 2149 2150 inline void closure (hb_closure_context_t *c) const 2151 { 2152 TRACE_CLOSURE (this); 2153 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2154 2155 if (!(this+input[0]).intersects (c->glyphs)) 2156 return; 2157 2158 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2159 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2160 struct ChainContextClosureLookupContext lookup_context = { 2161 {intersects_coverage}, 2162 {this, this, this} 2163 }; 2164 chain_context_closure_lookup (c, 2165 backtrack.len, (const USHORT *) backtrack.array, 2166 input.len, (const USHORT *) input.array + 1, 2167 lookahead.len, (const USHORT *) lookahead.array, 2168 lookup.len, lookup.array, 2169 lookup_context); 2170 } 2171 2172 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 2173 { 2174 TRACE_COLLECT_GLYPHS (this); 2175 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2176 2177 (this+input[0]).add_coverage (c->input); 2178 2179 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2180 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2181 struct ChainContextCollectGlyphsLookupContext lookup_context = { 2182 {collect_coverage}, 2183 {this, this, this} 2184 }; 2185 chain_context_collect_glyphs_lookup (c, 2186 backtrack.len, (const USHORT *) backtrack.array, 2187 input.len, (const USHORT *) input.array + 1, 2188 lookahead.len, (const USHORT *) lookahead.array, 2189 lookup.len, lookup.array, 2190 lookup_context); 2191 } 2192 2193 inline bool would_apply (hb_would_apply_context_t *c) const 2194 { 2195 TRACE_WOULD_APPLY (this); 2196 2197 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2198 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2199 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2200 struct ChainContextApplyLookupContext lookup_context = { 2201 {match_coverage}, 2202 {this, this, this} 2203 }; 2204 return TRACE_RETURN (chain_context_would_apply_lookup (c, 2205 backtrack.len, (const USHORT *) backtrack.array, 2206 input.len, (const USHORT *) input.array + 1, 2207 lookahead.len, (const USHORT *) lookahead.array, 2208 lookup.len, lookup.array, lookup_context)); 2209 } 2210 2211 inline const Coverage &get_coverage (void) const 2212 { 2213 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2214 return this+input[0]; 2215 } 2216 2217 inline bool apply (hb_apply_context_t *c) const 2218 { 2219 TRACE_APPLY (this); 2220 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2221 2222 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint); 2223 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 2224 2225 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2226 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2227 struct ChainContextApplyLookupContext lookup_context = { 2228 {match_coverage}, 2229 {this, this, this} 2230 }; 2231 return TRACE_RETURN (chain_context_apply_lookup (c, 2232 backtrack.len, (const USHORT *) backtrack.array, 2233 input.len, (const USHORT *) input.array + 1, 2234 lookahead.len, (const USHORT *) lookahead.array, 2235 lookup.len, lookup.array, lookup_context)); 2236 } 2237 2238 inline bool sanitize (hb_sanitize_context_t *c) { 2239 TRACE_SANITIZE (this); 2240 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); 2241 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 2242 if (!input.sanitize (c, this)) return TRACE_RETURN (false); 2243 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 2244 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false); 2245 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 2246 return TRACE_RETURN (lookup.sanitize (c)); 2247 } 2248 2249 protected: 2250 USHORT format; /* Format identifier--format = 3 */ 2251 OffsetArrayOf<Coverage> 2252 backtrack; /* Array of coverage tables 2253 * in backtracking sequence, in glyph 2254 * sequence order */ 2255 OffsetArrayOf<Coverage> 2256 inputX ; /* Array of coverage 2257 * tables in input sequence, in glyph 2258 * sequence order */ 2259 OffsetArrayOf<Coverage> 2260 lookaheadX; /* Array of coverage tables 2261 * in lookahead sequence, in glyph 2262 * sequence order */ 2263 ArrayOf<LookupRecord> 2264 lookupX; /* Array of LookupRecords--in 2265 * design order) */ 2266 public: 2267 DEFINE_SIZE_MIN (10); 2268}; 2269 2270struct ChainContext 2271{ 2272 template <typename context_t> 2273 inline typename context_t::return_t dispatch (context_t *c) const 2274 { 2275 TRACE_DISPATCH (this); 2276 switch (u.format) { 2277 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 2278 case 2: return TRACE_RETURN (c->dispatch (u.format2)); 2279 case 3: return TRACE_RETURN (c->dispatch (u.format3)); 2280 default:return TRACE_RETURN (c->default_return_value ()); 2281 } 2282 } 2283 2284 inline bool sanitize (hb_sanitize_context_t *c) { 2285 TRACE_SANITIZE (this); 2286 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 2287 switch (u.format) { 2288 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 2289 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 2290 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 2291 default:return TRACE_RETURN (true); 2292 } 2293 } 2294 2295 protected: 2296 union { 2297 USHORT format; /* Format identifier */ 2298 ChainContextFormat1 format1; 2299 ChainContextFormat2 format2; 2300 ChainContextFormat3 format3; 2301 } u; 2302}; 2303 2304 2305struct ExtensionFormat1 2306{ 2307 inline unsigned int get_type (void) const { return extensionLookupType; } 2308 inline unsigned int get_offset (void) const { return extensionOffset; } 2309 2310 inline bool sanitize (hb_sanitize_context_t *c) { 2311 TRACE_SANITIZE (this); 2312 return TRACE_RETURN (c->check_struct (this)); 2313 } 2314 2315 protected: 2316 USHORT format; /* Format identifier. Set to 1. */ 2317 USHORT extensionLookupType; /* Lookup type of subtable referenced 2318 * by ExtensionOffset (i.e. the 2319 * extension subtable). */ 2320 ULONG extensionOffset; /* Offset to the extension subtable, 2321 * of lookup type subtable. */ 2322 public: 2323 DEFINE_SIZE_STATIC (8); 2324}; 2325 2326template <typename T> 2327struct Extension 2328{ 2329 inline unsigned int get_type (void) const 2330 { 2331 switch (u.format) { 2332 case 1: return u.format1.get_type (); 2333 default:return 0; 2334 } 2335 } 2336 inline unsigned int get_offset (void) const 2337 { 2338 switch (u.format) { 2339 case 1: return u.format1.get_offset (); 2340 default:return 0; 2341 } 2342 } 2343 2344 template <typename X> 2345 inline const X& get_subtable (void) const 2346 { 2347 unsigned int offset = get_offset (); 2348 if (unlikely (!offset)) return Null(typename T::LookupSubTable); 2349 return StructAtOffset<typename T::LookupSubTable> (this, offset); 2350 } 2351 2352 template <typename context_t> 2353 inline typename context_t::return_t dispatch (context_t *c) const 2354 { 2355 return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()); 2356 } 2357 2358 inline bool sanitize_self (hb_sanitize_context_t *c) { 2359 TRACE_SANITIZE (this); 2360 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 2361 switch (u.format) { 2362 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 2363 default:return TRACE_RETURN (true); 2364 } 2365 } 2366 2367 inline bool sanitize (hb_sanitize_context_t *c) { 2368 TRACE_SANITIZE (this); 2369 if (!sanitize_self (c)) return TRACE_RETURN (false); 2370 unsigned int offset = get_offset (); 2371 if (unlikely (!offset)) return TRACE_RETURN (true); 2372 return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ())); 2373 } 2374 2375 protected: 2376 union { 2377 USHORT format; /* Format identifier */ 2378 ExtensionFormat1 format1; 2379 } u; 2380}; 2381 2382 2383/* 2384 * GSUB/GPOS Common 2385 */ 2386 2387struct GSUBGPOS 2388{ 2389 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; 2390 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; 2391 2392 inline unsigned int get_script_count (void) const 2393 { return (this+scriptList).len; } 2394 inline const Tag& get_script_tag (unsigned int i) const 2395 { return (this+scriptList).get_tag (i); } 2396 inline unsigned int get_script_tags (unsigned int start_offset, 2397 unsigned int *script_count /* IN/OUT */, 2398 hb_tag_t *script_tags /* OUT */) const 2399 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } 2400 inline const Script& get_script (unsigned int i) const 2401 { return (this+scriptList)[i]; } 2402 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const 2403 { return (this+scriptList).find_index (tag, index); } 2404 2405 inline unsigned int get_feature_count (void) const 2406 { return (this+featureList).len; } 2407 inline const Tag& get_feature_tag (unsigned int i) const 2408 { return (this+featureList).get_tag (i); } 2409 inline unsigned int get_feature_tags (unsigned int start_offset, 2410 unsigned int *feature_count /* IN/OUT */, 2411 hb_tag_t *feature_tags /* OUT */) const 2412 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } 2413 inline const Feature& get_feature (unsigned int i) const 2414 { return (this+featureList)[i]; } 2415 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const 2416 { return (this+featureList).find_index (tag, index); } 2417 2418 inline unsigned int get_lookup_count (void) const 2419 { return (this+lookupList).len; } 2420 inline const Lookup& get_lookup (unsigned int i) const 2421 { return (this+lookupList)[i]; } 2422 2423 inline bool sanitize (hb_sanitize_context_t *c) { 2424 TRACE_SANITIZE (this); 2425 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && 2426 scriptList.sanitize (c, this) && 2427 featureList.sanitize (c, this) && 2428 lookupList.sanitize (c, this)); 2429 } 2430 2431 protected: 2432 FixedVersion version; /* Version of the GSUB/GPOS table--initially set 2433 * to 0x00010000 */ 2434 OffsetTo<ScriptList> 2435 scriptList; /* ScriptList table */ 2436 OffsetTo<FeatureList> 2437 featureList; /* FeatureList table */ 2438 OffsetTo<LookupList> 2439 lookupList; /* LookupList table */ 2440 public: 2441 DEFINE_SIZE_STATIC (10); 2442}; 2443 2444 2445} /* namespace OT */ 2446 2447 2448#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ 2449