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