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