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