hb-ot-layout-gsubgpos-private.hh revision 1bcfa06d1173f219809542a7380ce77f1c907bec
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, 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 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 VOID; } 64 static return_t default_return_value (void) { return VOID; } 65 bool stop_sublookup_iteration (const return_t r) 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 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 (const 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, 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 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 VOID; } 152 static return_t default_return_value (void) { return VOID; } 153 bool stop_sublookup_iteration (const return_t r) 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 those are not requested, we can go home now. */ 162 163 nesting_level_left--; 164 /* Only collect output glyphs in the recursion. */ 165 hb_collect_glyphs_context_t new_c (this->face, NULL, NULL, NULL, &output, nesting_level_left); 166 recurse_func (&new_c, lookup_index); 167 nesting_level_left++; 168 return VOID; 169 } 170 171 hb_face_t *face; 172 hb_set_t &before; 173 hb_set_t &input; 174 hb_set_t &after; 175 hb_set_t &output; 176 recurse_func_t recurse_func; 177 unsigned int nesting_level_left; 178 unsigned int debug_depth; 179 180 hb_collect_glyphs_context_t (hb_face_t *face_, 181 hb_set_t *glyphs_before, /* OUT. May be NULL */ 182 hb_set_t *glyphs_input, /* OUT. May be NULL */ 183 hb_set_t *glyphs_after, /* OUT. May be NULL */ 184 hb_set_t *glyphs_output, /* OUT. May be NULL */ 185 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : 186 face (face_), 187 before (glyphs_before ? *glyphs_before : *hb_set_get_empty ()), 188 input (glyphs_input ? *glyphs_input : *hb_set_get_empty ()), 189 after (glyphs_after ? *glyphs_after : *hb_set_get_empty ()), 190 output (glyphs_output ? *glyphs_output : *hb_set_get_empty ()), 191 recurse_func (NULL), 192 nesting_level_left (nesting_level_left_), 193 debug_depth (0) {} 194 195 void set_recurse_func (recurse_func_t func) { recurse_func = func; } 196}; 197 198 199 200struct hb_get_coverage_context_t 201{ 202 inline const char *get_name (void) { return "GET_COVERAGE"; } 203 static const unsigned int max_debug_depth = 0; 204 typedef const Coverage &return_t; 205 template <typename T> 206 inline return_t process (const T &obj) { return obj.get_coverage (); } 207 static return_t default_return_value (void) { return Null(Coverage); } 208 209 hb_get_coverage_context_t (void) : 210 debug_depth (0) {} 211 212 unsigned int debug_depth; 213}; 214 215 216 217#ifndef HB_DEBUG_APPLY 218#define HB_DEBUG_APPLY (HB_DEBUG+0) 219#endif 220 221#define TRACE_APPLY(this) \ 222 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ 223 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 224 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); 225 226struct hb_apply_context_t 227{ 228 inline const char *get_name (void) { return "APPLY"; } 229 static const unsigned int max_debug_depth = HB_DEBUG_APPLY; 230 typedef bool return_t; 231 typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index); 232 template <typename T> 233 inline return_t process (const T &obj) { return obj.apply (this); } 234 static return_t default_return_value (void) { return false; } 235 bool stop_sublookup_iteration (const return_t r) const { return r; } 236 return_t recurse (unsigned int lookup_index) 237 { 238 if (unlikely (nesting_level_left == 0 || !recurse_func)) 239 return default_return_value (); 240 241 nesting_level_left--; 242 bool ret = recurse_func (this, lookup_index); 243 nesting_level_left++; 244 return ret; 245 } 246 247 hb_font_t *font; 248 hb_face_t *face; 249 hb_buffer_t *buffer; 250 hb_direction_t direction; 251 hb_mask_t lookup_mask; 252 recurse_func_t recurse_func; 253 unsigned int nesting_level_left; 254 unsigned int lookup_props; 255 unsigned int property; /* propety of first glyph */ 256 const GDEF &gdef; 257 bool has_glyph_classes; 258 unsigned int debug_depth; 259 260 261 hb_apply_context_t (hb_font_t *font_, 262 hb_buffer_t *buffer_, 263 hb_mask_t lookup_mask_) : 264 font (font_), face (font->face), buffer (buffer_), 265 direction (buffer_->props.direction), 266 lookup_mask (lookup_mask_), 267 recurse_func (NULL), 268 nesting_level_left (MAX_NESTING_LEVEL), 269 lookup_props (0), property (0), 270 gdef (*hb_ot_layout_from_face (face)->gdef), 271 has_glyph_classes (gdef.has_glyph_classes ()), 272 debug_depth (0) {} 273 274 void set_recurse_func (recurse_func_t func) { recurse_func = func; } 275 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } 276 void set_lookup (const Lookup &l) { lookup_props = l.get_props (); } 277 278 struct mark_skipping_forward_iterator_t 279 { 280 inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_, 281 unsigned int start_index_, 282 unsigned int num_items_, 283 bool context_match = false) 284 { 285 c = c_; 286 idx = start_index_; 287 num_items = num_items_; 288 mask = context_match ? -1 : c->lookup_mask; 289 syllable = context_match ? 0 : c->buffer->cur().syllable (); 290 end = c->buffer->len; 291 } 292 inline bool has_no_chance (void) const 293 { 294 return unlikely (num_items && idx + num_items >= end); 295 } 296 inline void reject (void) 297 { 298 num_items++; 299 } 300 inline bool next (unsigned int *property_out, 301 unsigned int lookup_props) 302 { 303 assert (num_items > 0); 304 do 305 { 306 if (has_no_chance ()) 307 return false; 308 idx++; 309 } while (c->should_skip_mark (&c->buffer->info[idx], lookup_props, property_out)); 310 num_items--; 311 return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ()); 312 } 313 inline bool next (unsigned int *property_out = NULL) 314 { 315 return next (property_out, c->lookup_props); 316 } 317 318 unsigned int idx; 319 protected: 320 hb_apply_context_t *c; 321 unsigned int num_items; 322 hb_mask_t mask; 323 uint8_t syllable; 324 unsigned int end; 325 }; 326 327 struct mark_skipping_backward_iterator_t 328 { 329 inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_, 330 unsigned int start_index_, 331 unsigned int num_items_, 332 hb_mask_t mask_ = 0, 333 bool match_syllable_ = true) 334 { 335 c = c_; 336 idx = start_index_; 337 num_items = num_items_; 338 mask = mask_ ? mask_ : c->lookup_mask; 339 syllable = match_syllable_ ? c->buffer->cur().syllable () : 0; 340 } 341 inline bool has_no_chance (void) const 342 { 343 return unlikely (idx < num_items); 344 } 345 inline void reject (void) 346 { 347 num_items++; 348 } 349 inline bool prev (unsigned int *property_out, 350 unsigned int lookup_props) 351 { 352 assert (num_items > 0); 353 do 354 { 355 if (has_no_chance ()) 356 return false; 357 idx--; 358 } while (c->should_skip_mark (&c->buffer->out_info[idx], lookup_props, property_out)); 359 num_items--; 360 return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ()); 361 } 362 inline bool prev (unsigned int *property_out = NULL) 363 { 364 return prev (property_out, c->lookup_props); 365 } 366 367 unsigned int idx; 368 protected: 369 hb_apply_context_t *c; 370 unsigned int num_items; 371 hb_mask_t mask; 372 uint8_t syllable; 373 }; 374 375 inline bool 376 match_properties_mark (hb_codepoint_t glyph, 377 unsigned int glyph_props, 378 unsigned int lookup_props) const 379 { 380 /* If using mark filtering sets, the high short of 381 * lookup_props has the set index. 382 */ 383 if (lookup_props & LookupFlag::UseMarkFilteringSet) 384 return gdef.mark_set_covers (lookup_props >> 16, glyph); 385 386 /* The second byte of lookup_props has the meaning 387 * "ignore marks of attachment type different than 388 * the attachment type specified." 389 */ 390 if (lookup_props & LookupFlag::MarkAttachmentType) 391 return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType); 392 393 return true; 394 } 395 396 inline bool 397 match_properties (hb_codepoint_t glyph, 398 unsigned int glyph_props, 399 unsigned int lookup_props) const 400 { 401 /* Not covered, if, for example, glyph class is ligature and 402 * lookup_props includes LookupFlags::IgnoreLigatures 403 */ 404 if (glyph_props & lookup_props & LookupFlag::IgnoreFlags) 405 return false; 406 407 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) 408 return match_properties_mark (glyph, glyph_props, lookup_props); 409 410 return true; 411 } 412 413 inline bool 414 check_glyph_property (hb_glyph_info_t *info, 415 unsigned int lookup_props, 416 unsigned int *property_out) const 417 { 418 unsigned int property; 419 420 property = info->glyph_props(); 421 *property_out = property; 422 423 return match_properties (info->codepoint, property, lookup_props); 424 } 425 426 inline bool 427 should_skip_mark (hb_glyph_info_t *info, 428 unsigned int lookup_props, 429 unsigned int *property_out) const 430 { 431 unsigned int property; 432 433 property = info->glyph_props(); 434 if (property_out) 435 *property_out = property; 436 437 /* If it's a mark, skip it if we don't accept it. */ 438 if (unlikely (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) 439 return !match_properties (info->codepoint, property, lookup_props); 440 441 /* If not a mark, don't skip. */ 442 return false; 443 } 444 445 446 inline bool should_mark_skip_current_glyph (void) const 447 { 448 return should_skip_mark (&buffer->cur(), lookup_props, NULL); 449 } 450 451 inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const 452 { 453 if (likely (has_glyph_classes)) 454 buffer->cur().glyph_props() = gdef.get_glyph_props (glyph_index); 455 else if (class_guess) 456 buffer->cur().glyph_props() = class_guess; 457 } 458 459 inline void output_glyph (hb_codepoint_t glyph_index, 460 unsigned int class_guess = 0) const 461 { 462 set_class (glyph_index, class_guess); 463 buffer->output_glyph (glyph_index); 464 } 465 inline void replace_glyph (hb_codepoint_t glyph_index, 466 unsigned int class_guess = 0) const 467 { 468 set_class (glyph_index, class_guess); 469 buffer->replace_glyph (glyph_index); 470 } 471 inline void replace_glyph_inplace (hb_codepoint_t glyph_index, 472 unsigned int class_guess = 0) const 473 { 474 set_class (glyph_index, class_guess); 475 buffer->cur().codepoint = glyph_index; 476 } 477}; 478 479 480 481typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); 482typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); 483typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); 484 485struct ContextClosureFuncs 486{ 487 intersects_func_t intersects; 488}; 489struct ContextCollectGlyphsFuncs 490{ 491 collect_glyphs_func_t collect; 492}; 493struct ContextApplyFuncs 494{ 495 match_func_t match; 496}; 497 498 499static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) 500{ 501 return glyphs->has (value); 502} 503static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data) 504{ 505 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 506 return class_def.intersects_class (glyphs, value); 507} 508static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) 509{ 510 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 511 return (data+coverage).intersects (glyphs); 512} 513 514static inline bool intersects_array (hb_closure_context_t *c, 515 unsigned int count, 516 const USHORT values[], 517 intersects_func_t intersects_func, 518 const void *intersects_data) 519{ 520 for (unsigned int i = 0; i < count; i++) 521 if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) 522 return false; 523 return true; 524} 525 526 527static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) 528{ 529 glyphs->add (value); 530} 531static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data) 532{ 533 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 534 class_def.add_class (glyphs, value); 535} 536static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) 537{ 538 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 539 (data+coverage).add_coverage (glyphs); 540} 541static inline void collect_array (hb_collect_glyphs_context_t *c, 542 hb_set_t *glyphs, 543 unsigned int count, 544 const USHORT values[], 545 collect_glyphs_func_t collect_func, 546 const void *collect_data) 547{ 548 for (unsigned int i = 0; i < count; i++) 549 collect_func (glyphs, values[i], collect_data); 550} 551 552 553static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED) 554{ 555 return glyph_id == value; 556} 557static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 558{ 559 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 560 return class_def.get_class (glyph_id) == value; 561} 562static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 563{ 564 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 565 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; 566} 567 568static inline bool would_match_input (hb_would_apply_context_t *c, 569 unsigned int count, /* Including the first glyph (not matched) */ 570 const USHORT input[], /* Array of input values--start with second glyph */ 571 match_func_t match_func, 572 const void *match_data) 573{ 574 if (count != c->len) 575 return false; 576 577 for (unsigned int i = 1; i < count; i++) 578 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data))) 579 return false; 580 581 return true; 582} 583static inline bool match_input (hb_apply_context_t *c, 584 unsigned int count, /* Including the first glyph (not matched) */ 585 const USHORT input[], /* Array of input values--start with second glyph */ 586 match_func_t match_func, 587 const void *match_data, 588 unsigned int *end_offset = NULL, 589 bool *p_is_mark_ligature = NULL, 590 unsigned int *p_total_component_count = NULL) 591{ 592 TRACE_APPLY (NULL); 593 594 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); 595 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 596 597 /* 598 * This is perhaps the trickiest part of OpenType... Remarks: 599 * 600 * - If all components of the ligature were marks, we call this a mark ligature. 601 * 602 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize 603 * it as a ligature glyph. 604 * 605 * - Ligatures cannot be formed across glyphs attached to different components 606 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and 607 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother. 608 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o 609 * There is an exception to this: If a ligature tries ligating with marks that 610 * belong to it itself, go ahead, assuming that the font designer knows what 611 * they are doing (otherwise it can break Indic stuff when a matra wants to 612 * ligate with a conjunct...) 613 */ 614 615 bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK); 616 617 unsigned int total_component_count = 0; 618 total_component_count += get_lig_num_comps (c->buffer->cur()); 619 620 unsigned int first_lig_id = get_lig_id (c->buffer->cur()); 621 unsigned int first_lig_comp = get_lig_comp (c->buffer->cur()); 622 623 for (unsigned int i = 1; i < count; i++) 624 { 625 unsigned int property; 626 627 if (!skippy_iter.next (&property)) return TRACE_RETURN (false); 628 629 if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return TRACE_RETURN (false); 630 631 unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]); 632 unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]); 633 634 if (first_lig_id && first_lig_comp) { 635 /* If first component was attached to a previous ligature component, 636 * all subsequent components should be attached to the same ligature 637 * component, otherwise we shouldn't ligate them. */ 638 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) 639 return TRACE_RETURN (false); 640 } else { 641 /* If first component was NOT attached to a previous ligature component, 642 * all subsequent components should also NOT be attached to any ligature 643 * component, unless they are attached to the first component itself! */ 644 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id)) 645 return TRACE_RETURN (false); 646 } 647 648 is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK); 649 total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]); 650 } 651 652 if (end_offset) 653 *end_offset = skippy_iter.idx - c->buffer->idx + 1; 654 655 if (p_is_mark_ligature) 656 *p_is_mark_ligature = is_mark_ligature; 657 658 if (p_total_component_count) 659 *p_total_component_count = total_component_count; 660 661 return TRACE_RETURN (true); 662} 663static inline void ligate_input (hb_apply_context_t *c, 664 unsigned int count, /* Including the first glyph (not matched) */ 665 const USHORT input[], /* Array of input values--start with second glyph */ 666 hb_codepoint_t lig_glyph, 667 match_func_t match_func, 668 const void *match_data, 669 bool is_mark_ligature, 670 unsigned int total_component_count) 671{ 672 /* 673 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave 674 * the ligature to keep its old ligature id. This will allow it to attach to 675 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH, 676 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a 677 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature 678 * later, we don't want them to lose their ligature id/component, otherwise 679 * GPOS will fail to correctly position the mark ligature on top of the 680 * LAM,LAM,HEH ligature. See: 681 * https://bugzilla.gnome.org/show_bug.cgi?id=676343 682 * 683 * - If a ligature is formed of components that some of which are also ligatures 684 * themselves, and those ligature components had marks attached to *their* 685 * components, we have to attach the marks to the new ligature component 686 * positions! Now *that*'s tricky! And these marks may be following the 687 * last component of the whole sequence, so we should loop forward looking 688 * for them and update them. 689 * 690 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a 691 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature 692 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature 693 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to 694 * the new ligature with a component value of 2. 695 * 696 * This in fact happened to a font... See: 697 * https://bugzilla.gnome.org/show_bug.cgi?id=437633 698 */ 699 700 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; 701 unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer); 702 unsigned int last_lig_id = get_lig_id (c->buffer->cur()); 703 unsigned int last_num_components = get_lig_num_comps (c->buffer->cur()); 704 unsigned int components_so_far = last_num_components; 705 706 if (!is_mark_ligature) 707 set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count); 708 c->replace_glyph (lig_glyph, klass); 709 710 for (unsigned int i = 1; i < count; i++) 711 { 712 while (c->should_mark_skip_current_glyph ()) 713 { 714 if (!is_mark_ligature) { 715 unsigned int new_lig_comp = components_so_far - last_num_components + 716 MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components); 717 set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp); 718 } 719 c->buffer->next_glyph (); 720 } 721 722 last_lig_id = get_lig_id (c->buffer->cur()); 723 last_num_components = get_lig_num_comps (c->buffer->cur()); 724 components_so_far += last_num_components; 725 726 /* Skip the base glyph */ 727 c->buffer->idx++; 728 } 729 730 if (!is_mark_ligature && last_lig_id) { 731 /* Re-adjust components for any marks following. */ 732 for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) { 733 if (last_lig_id == get_lig_id (c->buffer->info[i])) { 734 unsigned int new_lig_comp = components_so_far - last_num_components + 735 MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components); 736 set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp); 737 } else 738 break; 739 } 740 } 741} 742 743static inline bool match_backtrack (hb_apply_context_t *c, 744 unsigned int count, 745 const USHORT backtrack[], 746 match_func_t match_func, 747 const void *match_data) 748{ 749 TRACE_APPLY (NULL); 750 751 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true); 752 if (skippy_iter.has_no_chance ()) 753 return TRACE_RETURN (false); 754 755 for (unsigned int i = 0; i < count; i++) 756 { 757 if (!skippy_iter.prev ()) 758 return TRACE_RETURN (false); 759 760 if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data))) 761 return TRACE_RETURN (false); 762 } 763 764 return TRACE_RETURN (true); 765} 766 767static inline bool match_lookahead (hb_apply_context_t *c, 768 unsigned int count, 769 const USHORT lookahead[], 770 match_func_t match_func, 771 const void *match_data, 772 unsigned int offset) 773{ 774 TRACE_APPLY (NULL); 775 776 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true); 777 if (skippy_iter.has_no_chance ()) 778 return TRACE_RETURN (false); 779 780 for (unsigned int i = 0; i < count; i++) 781 { 782 if (!skippy_iter.next ()) 783 return TRACE_RETURN (false); 784 785 if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data))) 786 return TRACE_RETURN (false); 787 } 788 789 return TRACE_RETURN (true); 790} 791 792 793 794struct LookupRecord 795{ 796 inline bool sanitize (hb_sanitize_context_t *c) { 797 TRACE_SANITIZE (this); 798 return TRACE_RETURN (c->check_struct (this)); 799 } 800 801 USHORT sequenceIndex; /* Index into current glyph 802 * sequence--first glyph = 0 */ 803 USHORT lookupListIndex; /* Lookup to apply to that 804 * position--zero--based */ 805 public: 806 DEFINE_SIZE_STATIC (4); 807}; 808 809 810template <typename context_t> 811static inline void recurse_lookups (context_t *c, 812 unsigned int lookupCount, 813 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) 814{ 815 for (unsigned int i = 0; i < lookupCount; i++) 816 c->recurse (lookupRecord->lookupListIndex); 817} 818 819static inline bool apply_lookup (hb_apply_context_t *c, 820 unsigned int count, /* Including the first glyph */ 821 unsigned int lookupCount, 822 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) 823{ 824 TRACE_APPLY (NULL); 825 826 unsigned int end = c->buffer->len; 827 if (unlikely (count == 0 || c->buffer->idx + count > end)) 828 return TRACE_RETURN (false); 829 830 /* TODO We don't support lookupRecord arrays that are not increasing: 831 * Should be easy for in_place ones at least. */ 832 833 /* Note: If sublookup is reverse, it will underflow after the first loop 834 * and we jump out of it. Not entirely disastrous. So we don't check 835 * for reverse lookup here. 836 */ 837 for (unsigned int i = 0; i < count; /* NOP */) 838 { 839 if (unlikely (c->buffer->idx == end)) 840 return TRACE_RETURN (true); 841 while (c->should_mark_skip_current_glyph ()) 842 { 843 /* No lookup applied for this index */ 844 c->buffer->next_glyph (); 845 if (unlikely (c->buffer->idx == end)) 846 return TRACE_RETURN (true); 847 } 848 849 if (lookupCount && i == lookupRecord->sequenceIndex) 850 { 851 unsigned int old_pos = c->buffer->idx; 852 853 /* Apply a lookup */ 854 bool done = c->recurse (lookupRecord->lookupListIndex); 855 856 lookupRecord++; 857 lookupCount--; 858 /* Err, this is wrong if the lookup jumped over some glyphs */ 859 i += c->buffer->idx - old_pos; 860 if (unlikely (c->buffer->idx == end)) 861 return TRACE_RETURN (true); 862 863 if (!done) 864 goto not_applied; 865 } 866 else 867 { 868 not_applied: 869 /* No lookup applied for this index */ 870 c->buffer->next_glyph (); 871 i++; 872 } 873 } 874 875 return TRACE_RETURN (true); 876} 877 878 879 880/* Contextual lookups */ 881 882struct ContextClosureLookupContext 883{ 884 ContextClosureFuncs funcs; 885 const void *intersects_data; 886}; 887 888struct ContextCollectGlyphsLookupContext 889{ 890 ContextCollectGlyphsFuncs funcs; 891 const void *collect_data; 892}; 893 894struct ContextApplyLookupContext 895{ 896 ContextApplyFuncs funcs; 897 const void *match_data; 898}; 899 900static inline void context_closure_lookup (hb_closure_context_t *c, 901 unsigned int inputCount, /* Including the first glyph (not matched) */ 902 const USHORT input[], /* Array of input values--start with second glyph */ 903 unsigned int lookupCount, 904 const LookupRecord lookupRecord[], 905 ContextClosureLookupContext &lookup_context) 906{ 907 if (intersects_array (c, 908 inputCount ? inputCount - 1 : 0, input, 909 lookup_context.funcs.intersects, lookup_context.intersects_data)) 910 recurse_lookups (c, 911 lookupCount, lookupRecord); 912} 913 914static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 915 unsigned int inputCount, /* Including the first glyph (not matched) */ 916 const USHORT input[], /* Array of input values--start with second glyph */ 917 unsigned int lookupCount, 918 const LookupRecord lookupRecord[], 919 ContextCollectGlyphsLookupContext &lookup_context) 920{ 921 collect_array (c, &c->input, 922 inputCount ? inputCount - 1 : 0, input, 923 lookup_context.funcs.collect, lookup_context.collect_data); 924 recurse_lookups (c, 925 lookupCount, lookupRecord); 926} 927 928static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, 929 unsigned int inputCount, /* Including the first glyph (not matched) */ 930 const USHORT input[], /* Array of input values--start with second glyph */ 931 unsigned int lookupCount, 932 const LookupRecord lookupRecord[], 933 ContextApplyLookupContext &lookup_context) 934{ 935 return would_match_input (c, 936 inputCount, input, 937 lookup_context.funcs.match, lookup_context.match_data); 938} 939static inline bool context_apply_lookup (hb_apply_context_t *c, 940 unsigned int inputCount, /* Including the first glyph (not matched) */ 941 const USHORT input[], /* Array of input values--start with second glyph */ 942 unsigned int lookupCount, 943 const LookupRecord lookupRecord[], 944 ContextApplyLookupContext &lookup_context) 945{ 946 return match_input (c, 947 inputCount, input, 948 lookup_context.funcs.match, lookup_context.match_data) 949 && apply_lookup (c, 950 inputCount, 951 lookupCount, lookupRecord); 952} 953 954struct Rule 955{ 956 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 957 { 958 TRACE_CLOSURE (this); 959 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 960 context_closure_lookup (c, 961 inputCount, input, 962 lookupCount, lookupRecord, 963 lookup_context); 964 } 965 966 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const 967 { 968 TRACE_COLLECT_GLYPHS (this); 969 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 970 context_collect_glyphs_lookup (c, 971 inputCount, input, 972 lookupCount, lookupRecord, 973 lookup_context); 974 } 975 976 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 977 { 978 TRACE_WOULD_APPLY (this); 979 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 980 return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); 981 } 982 983 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 984 { 985 TRACE_APPLY (this); 986 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 987 return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); 988 } 989 990 public: 991 inline bool sanitize (hb_sanitize_context_t *c) { 992 TRACE_SANITIZE (this); 993 return inputCount.sanitize (c) 994 && lookupCount.sanitize (c) 995 && c->check_range (input, 996 input[0].static_size * inputCount 997 + lookupRecordX[0].static_size * lookupCount); 998 } 999 1000 protected: 1001 USHORT inputCount; /* Total number of glyphs in input 1002 * glyph sequence--includes the first 1003 * glyph */ 1004 USHORT lookupCount; /* Number of LookupRecords */ 1005 USHORT input[VAR]; /* Array of match inputs--start with 1006 * second glyph */ 1007 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 1008 * design order */ 1009 public: 1010 DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX); 1011}; 1012 1013struct RuleSet 1014{ 1015 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 1016 { 1017 TRACE_CLOSURE (this); 1018 unsigned int num_rules = rule.len; 1019 for (unsigned int i = 0; i < num_rules; i++) 1020 (this+rule[i]).closure (c, lookup_context); 1021 } 1022 1023 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const 1024 { 1025 TRACE_COLLECT_GLYPHS (this); 1026 unsigned int num_rules = rule.len; 1027 for (unsigned int i = 0; i < num_rules; i++) 1028 (this+rule[i]).collect_glyphs (c, lookup_context); 1029 } 1030 1031 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1032 { 1033 TRACE_WOULD_APPLY (this); 1034 unsigned int num_rules = rule.len; 1035 for (unsigned int i = 0; i < num_rules; i++) 1036 { 1037 if ((this+rule[i]).would_apply (c, lookup_context)) 1038 return TRACE_RETURN (true); 1039 } 1040 return TRACE_RETURN (false); 1041 } 1042 1043 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1044 { 1045 TRACE_APPLY (this); 1046 unsigned int num_rules = rule.len; 1047 for (unsigned int i = 0; i < num_rules; i++) 1048 { 1049 if ((this+rule[i]).apply (c, lookup_context)) 1050 return TRACE_RETURN (true); 1051 } 1052 return TRACE_RETURN (false); 1053 } 1054 1055 inline bool sanitize (hb_sanitize_context_t *c) { 1056 TRACE_SANITIZE (this); 1057 return TRACE_RETURN (rule.sanitize (c, this)); 1058 } 1059 1060 protected: 1061 OffsetArrayOf<Rule> 1062 rule; /* Array of Rule tables 1063 * ordered by preference */ 1064 public: 1065 DEFINE_SIZE_ARRAY (2, rule); 1066}; 1067 1068 1069struct ContextFormat1 1070{ 1071 inline void closure (hb_closure_context_t *c) const 1072 { 1073 TRACE_CLOSURE (this); 1074 1075 const Coverage &cov = (this+coverage); 1076 1077 struct ContextClosureLookupContext lookup_context = { 1078 {intersects_glyph}, 1079 NULL 1080 }; 1081 1082 unsigned int count = ruleSet.len; 1083 for (unsigned int i = 0; i < count; i++) 1084 if (cov.intersects_coverage (c->glyphs, i)) { 1085 const RuleSet &rule_set = this+ruleSet[i]; 1086 rule_set.closure (c, lookup_context); 1087 } 1088 } 1089 1090 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1091 { 1092 TRACE_COLLECT_GLYPHS (this); 1093 (this+coverage).add_coverage (&c->input); 1094 1095 struct ContextCollectGlyphsLookupContext lookup_context = { 1096 {collect_glyph}, 1097 NULL 1098 }; 1099 1100 unsigned int count = ruleSet.len; 1101 for (unsigned int i = 0; i < count; i++) 1102 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1103 } 1104 1105 inline bool would_apply (hb_would_apply_context_t *c) const 1106 { 1107 TRACE_WOULD_APPLY (this); 1108 1109 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 1110 struct ContextApplyLookupContext lookup_context = { 1111 {match_glyph}, 1112 NULL 1113 }; 1114 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1115 } 1116 1117 inline const Coverage &get_coverage (void) const 1118 { 1119 return this+coverage; 1120 } 1121 1122 inline bool apply (hb_apply_context_t *c) const 1123 { 1124 TRACE_APPLY (this); 1125 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1126 if (likely (index == NOT_COVERED)) 1127 return TRACE_RETURN (false); 1128 1129 const RuleSet &rule_set = this+ruleSet[index]; 1130 struct ContextApplyLookupContext lookup_context = { 1131 {match_glyph}, 1132 NULL 1133 }; 1134 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1135 } 1136 1137 inline bool sanitize (hb_sanitize_context_t *c) { 1138 TRACE_SANITIZE (this); 1139 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1140 } 1141 1142 protected: 1143 USHORT format; /* Format identifier--format = 1 */ 1144 OffsetTo<Coverage> 1145 coverage; /* Offset to Coverage table--from 1146 * beginning of table */ 1147 OffsetArrayOf<RuleSet> 1148 ruleSet; /* Array of RuleSet tables 1149 * ordered by Coverage Index */ 1150 public: 1151 DEFINE_SIZE_ARRAY (6, ruleSet); 1152}; 1153 1154 1155struct ContextFormat2 1156{ 1157 inline void closure (hb_closure_context_t *c) const 1158 { 1159 TRACE_CLOSURE (this); 1160 if (!(this+coverage).intersects (c->glyphs)) 1161 return; 1162 1163 const ClassDef &class_def = this+classDef; 1164 1165 struct ContextClosureLookupContext lookup_context = { 1166 {intersects_class}, 1167 NULL 1168 }; 1169 1170 unsigned int count = ruleSet.len; 1171 for (unsigned int i = 0; i < count; i++) 1172 if (class_def.intersects_class (c->glyphs, i)) { 1173 const RuleSet &rule_set = this+ruleSet[i]; 1174 rule_set.closure (c, lookup_context); 1175 } 1176 } 1177 1178 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1179 { 1180 TRACE_COLLECT_GLYPHS (this); 1181 (this+coverage).add_coverage (&c->input); 1182 1183 struct ContextCollectGlyphsLookupContext lookup_context = { 1184 {collect_class}, 1185 NULL 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[], 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[], 1451 unsigned int lookupCount, 1452 const LookupRecord lookupRecord[], 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 struct ChainContextCollectGlyphsLookupContext lookup_context = { 1743 {collect_class}, 1744 {NULL, NULL, NULL} 1745 }; 1746 1747 unsigned int count = ruleSet.len; 1748 for (unsigned int i = 0; i < count; i++) 1749 (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1750 } 1751 1752 inline bool would_apply (hb_would_apply_context_t *c) const 1753 { 1754 TRACE_WOULD_APPLY (this); 1755 1756 const ClassDef &input_class_def = this+inputClassDef; 1757 1758 unsigned int index = input_class_def.get_class (c->glyphs[0]); 1759 const ChainRuleSet &rule_set = this+ruleSet[index]; 1760 struct ChainContextApplyLookupContext lookup_context = { 1761 {match_class}, 1762 {NULL, &input_class_def, NULL} 1763 }; 1764 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1765 } 1766 1767 inline const Coverage &get_coverage (void) const 1768 { 1769 return this+coverage; 1770 } 1771 1772 inline bool apply (hb_apply_context_t *c) const 1773 { 1774 TRACE_APPLY (this); 1775 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1776 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1777 1778 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1779 const ClassDef &input_class_def = this+inputClassDef; 1780 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1781 1782 index = input_class_def.get_class (c->buffer->cur().codepoint); 1783 const ChainRuleSet &rule_set = this+ruleSet[index]; 1784 struct ChainContextApplyLookupContext lookup_context = { 1785 {match_class}, 1786 {&backtrack_class_def, 1787 &input_class_def, 1788 &lookahead_class_def} 1789 }; 1790 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1791 } 1792 1793 inline bool sanitize (hb_sanitize_context_t *c) { 1794 TRACE_SANITIZE (this); 1795 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && 1796 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && 1797 ruleSet.sanitize (c, this)); 1798 } 1799 1800 protected: 1801 USHORT format; /* Format identifier--format = 2 */ 1802 OffsetTo<Coverage> 1803 coverage; /* Offset to Coverage table--from 1804 * beginning of table */ 1805 OffsetTo<ClassDef> 1806 backtrackClassDef; /* Offset to glyph ClassDef table 1807 * containing backtrack sequence 1808 * data--from beginning of table */ 1809 OffsetTo<ClassDef> 1810 inputClassDef; /* Offset to glyph ClassDef 1811 * table containing input sequence 1812 * data--from beginning of table */ 1813 OffsetTo<ClassDef> 1814 lookaheadClassDef; /* Offset to glyph ClassDef table 1815 * containing lookahead sequence 1816 * data--from beginning of table */ 1817 OffsetArrayOf<ChainRuleSet> 1818 ruleSet; /* Array of ChainRuleSet tables 1819 * ordered by class */ 1820 public: 1821 DEFINE_SIZE_ARRAY (12, ruleSet); 1822}; 1823 1824struct ChainContextFormat3 1825{ 1826 inline void closure (hb_closure_context_t *c) const 1827 { 1828 TRACE_CLOSURE (this); 1829 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1830 1831 if (!(this+input[0]).intersects (c->glyphs)) 1832 return; 1833 1834 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1835 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1836 struct ChainContextClosureLookupContext lookup_context = { 1837 {intersects_coverage}, 1838 {this, this, this} 1839 }; 1840 chain_context_closure_lookup (c, 1841 backtrack.len, (const USHORT *) backtrack.array, 1842 input.len, (const USHORT *) input.array + 1, 1843 lookahead.len, (const USHORT *) lookahead.array, 1844 lookup.len, lookup.array, 1845 lookup_context); 1846 } 1847 1848 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1849 { 1850 TRACE_COLLECT_GLYPHS (this); 1851 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1852 1853 (this+input[0]).add_coverage (&c->input); 1854 1855 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1856 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1857 struct ChainContextCollectGlyphsLookupContext lookup_context = { 1858 {collect_coverage}, 1859 {this, this, this} 1860 }; 1861 chain_context_collect_glyphs_lookup (c, 1862 backtrack.len, (const USHORT *) backtrack.array, 1863 input.len, (const USHORT *) input.array + 1, 1864 lookahead.len, (const USHORT *) lookahead.array, 1865 lookup.len, lookup.array, 1866 lookup_context); 1867 } 1868 1869 inline bool would_apply (hb_would_apply_context_t *c) const 1870 { 1871 TRACE_WOULD_APPLY (this); 1872 1873 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1874 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1875 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1876 struct ChainContextApplyLookupContext lookup_context = { 1877 {match_coverage}, 1878 {this, this, this} 1879 }; 1880 return TRACE_RETURN (chain_context_would_apply_lookup (c, 1881 backtrack.len, (const USHORT *) backtrack.array, 1882 input.len, (const USHORT *) input.array + 1, 1883 lookahead.len, (const USHORT *) lookahead.array, 1884 lookup.len, lookup.array, lookup_context)); 1885 } 1886 1887 inline const Coverage &get_coverage (void) const 1888 { 1889 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1890 return this+input[0]; 1891 } 1892 1893 inline bool apply (hb_apply_context_t *c) const 1894 { 1895 TRACE_APPLY (this); 1896 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1897 1898 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint); 1899 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1900 1901 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1902 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1903 struct ChainContextApplyLookupContext lookup_context = { 1904 {match_coverage}, 1905 {this, this, this} 1906 }; 1907 return TRACE_RETURN (chain_context_apply_lookup (c, 1908 backtrack.len, (const USHORT *) backtrack.array, 1909 input.len, (const USHORT *) input.array + 1, 1910 lookahead.len, (const USHORT *) lookahead.array, 1911 lookup.len, lookup.array, lookup_context)); 1912 } 1913 1914 inline bool sanitize (hb_sanitize_context_t *c) { 1915 TRACE_SANITIZE (this); 1916 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); 1917 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1918 if (!input.sanitize (c, this)) return TRACE_RETURN (false); 1919 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1920 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false); 1921 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1922 return TRACE_RETURN (lookup.sanitize (c)); 1923 } 1924 1925 protected: 1926 USHORT format; /* Format identifier--format = 3 */ 1927 OffsetArrayOf<Coverage> 1928 backtrack; /* Array of coverage tables 1929 * in backtracking sequence, in glyph 1930 * sequence order */ 1931 OffsetArrayOf<Coverage> 1932 inputX ; /* Array of coverage 1933 * tables in input sequence, in glyph 1934 * sequence order */ 1935 OffsetArrayOf<Coverage> 1936 lookaheadX; /* Array of coverage tables 1937 * in lookahead sequence, in glyph 1938 * sequence order */ 1939 ArrayOf<LookupRecord> 1940 lookupX; /* Array of LookupRecords--in 1941 * design order) */ 1942 public: 1943 DEFINE_SIZE_MIN (10); 1944}; 1945 1946struct ChainContext 1947{ 1948 template <typename context_t> 1949 inline typename context_t::return_t process (context_t *c) const 1950 { 1951 TRACE_PROCESS (this); 1952 switch (u.format) { 1953 case 1: return TRACE_RETURN (c->process (u.format1)); 1954 case 2: return TRACE_RETURN (c->process (u.format2)); 1955 case 3: return TRACE_RETURN (c->process (u.format3)); 1956 default:return TRACE_RETURN (c->default_return_value ()); 1957 } 1958 } 1959 1960 inline bool sanitize (hb_sanitize_context_t *c) { 1961 TRACE_SANITIZE (this); 1962 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1963 switch (u.format) { 1964 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1965 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1966 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1967 default:return TRACE_RETURN (true); 1968 } 1969 } 1970 1971 protected: 1972 union { 1973 USHORT format; /* Format identifier */ 1974 ChainContextFormat1 format1; 1975 ChainContextFormat2 format2; 1976 ChainContextFormat3 format3; 1977 } u; 1978}; 1979 1980 1981struct ExtensionFormat1 1982{ 1983 inline unsigned int get_type (void) const { return extensionLookupType; } 1984 inline unsigned int get_offset (void) const { return extensionOffset; } 1985 1986 inline bool sanitize (hb_sanitize_context_t *c) { 1987 TRACE_SANITIZE (this); 1988 return TRACE_RETURN (c->check_struct (this)); 1989 } 1990 1991 protected: 1992 USHORT format; /* Format identifier. Set to 1. */ 1993 USHORT extensionLookupType; /* Lookup type of subtable referenced 1994 * by ExtensionOffset (i.e. the 1995 * extension subtable). */ 1996 ULONG extensionOffset; /* Offset to the extension subtable, 1997 * of lookup type subtable. */ 1998 public: 1999 DEFINE_SIZE_STATIC (8); 2000}; 2001 2002template <typename T> 2003struct Extension 2004{ 2005 inline unsigned int get_type (void) const 2006 { 2007 switch (u.format) { 2008 case 1: return u.format1.get_type (); 2009 default:return 0; 2010 } 2011 } 2012 inline unsigned int get_offset (void) const 2013 { 2014 switch (u.format) { 2015 case 1: return u.format1.get_offset (); 2016 default:return 0; 2017 } 2018 } 2019 2020 template <typename X> 2021 inline const X& get_subtable (void) const 2022 { 2023 unsigned int offset = get_offset (); 2024 if (unlikely (!offset)) return Null(typename T::LookupSubTable); 2025 return StructAtOffset<typename T::LookupSubTable> (this, offset); 2026 } 2027 2028 template <typename context_t> 2029 inline typename context_t::return_t process (context_t *c) const 2030 { 2031 return get_subtable<typename T::LookupSubTable> ().process (c, get_type ()); 2032 } 2033 2034 inline bool sanitize_self (hb_sanitize_context_t *c) { 2035 TRACE_SANITIZE (this); 2036 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 2037 switch (u.format) { 2038 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 2039 default:return TRACE_RETURN (true); 2040 } 2041 } 2042 2043 inline bool sanitize (hb_sanitize_context_t *c) { 2044 TRACE_SANITIZE (this); 2045 if (!sanitize_self (c)) return TRACE_RETURN (false); 2046 unsigned int offset = get_offset (); 2047 if (unlikely (!offset)) return TRACE_RETURN (true); 2048 return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ())); 2049 } 2050 2051 protected: 2052 union { 2053 USHORT format; /* Format identifier */ 2054 ExtensionFormat1 format1; 2055 } u; 2056}; 2057 2058 2059/* 2060 * GSUB/GPOS Common 2061 */ 2062 2063struct GSUBGPOS 2064{ 2065 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; 2066 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; 2067 2068 inline unsigned int get_script_count (void) const 2069 { return (this+scriptList).len; } 2070 inline const Tag& get_script_tag (unsigned int i) const 2071 { return (this+scriptList).get_tag (i); } 2072 inline unsigned int get_script_tags (unsigned int start_offset, 2073 unsigned int *script_count /* IN/OUT */, 2074 hb_tag_t *script_tags /* OUT */) const 2075 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } 2076 inline const Script& get_script (unsigned int i) const 2077 { return (this+scriptList)[i]; } 2078 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const 2079 { return (this+scriptList).find_index (tag, index); } 2080 2081 inline unsigned int get_feature_count (void) const 2082 { return (this+featureList).len; } 2083 inline const Tag& get_feature_tag (unsigned int i) const 2084 { return (this+featureList).get_tag (i); } 2085 inline unsigned int get_feature_tags (unsigned int start_offset, 2086 unsigned int *feature_count /* IN/OUT */, 2087 hb_tag_t *feature_tags /* OUT */) const 2088 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } 2089 inline const Feature& get_feature (unsigned int i) const 2090 { return (this+featureList)[i]; } 2091 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const 2092 { return (this+featureList).find_index (tag, index); } 2093 2094 inline unsigned int get_lookup_count (void) const 2095 { return (this+lookupList).len; } 2096 inline const Lookup& get_lookup (unsigned int i) const 2097 { return (this+lookupList)[i]; } 2098 2099 inline bool sanitize (hb_sanitize_context_t *c) { 2100 TRACE_SANITIZE (this); 2101 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && 2102 scriptList.sanitize (c, this) && 2103 featureList.sanitize (c, this) && 2104 lookupList.sanitize (c, this)); 2105 } 2106 2107 protected: 2108 FixedVersion version; /* Version of the GSUB/GPOS table--initially set 2109 * to 0x00010000 */ 2110 OffsetTo<ScriptList> 2111 scriptList; /* ScriptList table */ 2112 OffsetTo<FeatureList> 2113 featureList; /* FeatureList table */ 2114 OffsetTo<LookupList> 2115 lookupList; /* LookupList table */ 2116 public: 2117 DEFINE_SIZE_STATIC (10); 2118}; 2119 2120 2121} /* namespace OT */ 2122 2123 2124#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ 2125