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