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