2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OT_LAYOUT_GSUBGPOS_HH
30 #define HB_OT_LAYOUT_GSUBGPOS_HH
33 #include "hb-buffer.hh"
36 #include "hb-ot-map.hh"
37 #include "hb-ot-layout-common.hh"
38 #include "hb-ot-layout-gdef-table.hh"
44 struct hb_intersects_context_t :
45 hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
47 const char *get_name () { return "INTERSECTS"; }
49 return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
50 static return_t default_return_value () { return false; }
51 bool stop_sublookup_iteration (return_t r) const { return r; }
53 const hb_set_t *glyphs;
54 unsigned int debug_depth;
56 hb_intersects_context_t (const hb_set_t *glyphs_) :
61 struct hb_closure_context_t :
62 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, 0>
64 const char *get_name () { return "CLOSURE"; }
65 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
67 return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
68 static return_t default_return_value () { return HB_VOID; }
69 void recurse (unsigned int lookup_index)
71 if (unlikely (nesting_level_left == 0 || !recurse_func))
75 recurse_func (this, lookup_index);
79 bool should_visit_lookup (unsigned int lookup_index)
81 if (is_lookup_done (lookup_index))
83 done_lookups->set (lookup_index, glyphs->get_population ());
87 bool is_lookup_done (unsigned int lookup_index)
89 /* Have we visited this lookup with the current set of glyphs? */
90 return done_lookups->get (lookup_index) == glyphs->get_population ();
96 recurse_func_t recurse_func;
97 unsigned int nesting_level_left;
98 unsigned int debug_depth;
100 hb_closure_context_t (hb_face_t *face_,
102 hb_map_t *done_lookups_,
103 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
106 recurse_func (nullptr),
107 nesting_level_left (nesting_level_left_),
109 done_lookups (done_lookups_) {}
111 ~hb_closure_context_t () { flush (); }
113 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
117 hb_set_union (glyphs, out);
122 hb_map_t *done_lookups;
126 struct hb_would_apply_context_t :
127 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
129 const char *get_name () { return "WOULD_APPLY"; }
130 template <typename T>
131 return_t dispatch (const T &obj) { return obj.would_apply (this); }
132 static return_t default_return_value () { return false; }
133 bool stop_sublookup_iteration (return_t r) const { return r; }
136 const hb_codepoint_t *glyphs;
139 unsigned int debug_depth;
141 hb_would_apply_context_t (hb_face_t *face_,
142 const hb_codepoint_t *glyphs_,
144 bool zero_context_) :
148 zero_context (zero_context_),
153 struct hb_collect_glyphs_context_t :
154 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, 0>
156 const char *get_name () { return "COLLECT_GLYPHS"; }
157 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
158 template <typename T>
159 return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
160 static return_t default_return_value () { return HB_VOID; }
161 void recurse (unsigned int lookup_index)
163 if (unlikely (nesting_level_left == 0 || !recurse_func))
166 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
167 * past the previous check. For GSUB, we only want to collect the output
168 * glyphs in the recursion. If output is not requested, we can go home now.
170 * Note further, that the above is not exactly correct. A recursed lookup
171 * is allowed to match input that is not matched in the context, but that's
172 * not how most fonts are built. It's possible to relax that and recurse
173 * with all sets here if it proves to be an issue.
176 if (output == hb_set_get_empty ())
179 /* Return if new lookup was recursed to before. */
180 if (recursed_lookups->has (lookup_index))
183 hb_set_t *old_before = before;
184 hb_set_t *old_input = input;
185 hb_set_t *old_after = after;
186 before = input = after = hb_set_get_empty ();
188 nesting_level_left--;
189 recurse_func (this, lookup_index);
190 nesting_level_left++;
196 recursed_lookups->add (lookup_index);
204 recurse_func_t recurse_func;
205 hb_set_t *recursed_lookups;
206 unsigned int nesting_level_left;
207 unsigned int debug_depth;
209 hb_collect_glyphs_context_t (hb_face_t *face_,
210 hb_set_t *glyphs_before, /* OUT. May be NULL */
211 hb_set_t *glyphs_input, /* OUT. May be NULL */
212 hb_set_t *glyphs_after, /* OUT. May be NULL */
213 hb_set_t *glyphs_output, /* OUT. May be NULL */
214 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
216 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
217 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
218 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
219 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
220 recurse_func (nullptr),
221 recursed_lookups (hb_set_create ()),
222 nesting_level_left (nesting_level_left_),
224 ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
226 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
231 template <typename set_t>
232 struct hb_add_coverage_context_t :
233 hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
235 const char *get_name () { return "GET_COVERAGE"; }
236 typedef const Coverage &return_t;
237 template <typename T>
238 return_t dispatch (const T &obj) { return obj.get_coverage (); }
239 static return_t default_return_value () { return Null(Coverage); }
240 bool stop_sublookup_iteration (return_t r) const
242 r.add_coverage (set);
246 hb_add_coverage_context_t (set_t *set_) :
251 unsigned int debug_depth;
255 struct hb_ot_apply_context_t :
256 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
265 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
268 match_func (nullptr),
269 match_data (nullptr) {}
271 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
273 void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
274 void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
275 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
276 void set_mask (hb_mask_t mask_) { mask = mask_; }
277 void set_syllable (uint8_t syllable_) { syllable = syllable_; }
278 void set_match_func (match_func_t match_func_,
279 const void *match_data_)
280 { match_func = match_func_; match_data = match_data_; }
288 may_match_t may_match (const hb_glyph_info_t &info,
289 const HBUINT16 *glyph_data) const
291 if (!(info.mask & mask) ||
292 (syllable && syllable != info.syllable ()))
296 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
307 may_skip_t may_skip (const hb_ot_apply_context_t *c,
308 const hb_glyph_info_t &info) const
310 if (!c->check_glyph_property (&info, lookup_props))
313 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
314 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
315 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
322 unsigned int lookup_props;
327 match_func_t match_func;
328 const void *match_data;
331 struct skipping_iterator_t
333 void init (hb_ot_apply_context_t *c_, bool context_match = false)
336 match_glyph_data = nullptr;
337 matcher.set_match_func (nullptr, nullptr);
338 matcher.set_lookup_props (c->lookup_props);
339 /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
340 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
341 /* Ignore ZWJ if we are matching context, or asked to. */
342 matcher.set_ignore_zwj (context_match || c->auto_zwj);
343 matcher.set_mask (context_match ? -1 : c->lookup_mask);
345 void set_lookup_props (unsigned int lookup_props)
347 matcher.set_lookup_props (lookup_props);
349 void set_match_func (matcher_t::match_func_t match_func_,
350 const void *match_data_,
351 const HBUINT16 glyph_data[])
353 matcher.set_match_func (match_func_, match_data_);
354 match_glyph_data = glyph_data;
357 void reset (unsigned int start_index_,
358 unsigned int num_items_)
361 num_items = num_items_;
362 end = c->buffer->len;
363 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
366 void reject () { num_items++; match_glyph_data--; }
368 matcher_t::may_skip_t
369 may_skip (const hb_glyph_info_t &info) const
370 { return matcher.may_skip (c, info); }
374 assert (num_items > 0);
375 while (idx + num_items < end)
378 const hb_glyph_info_t &info = c->buffer->info[idx];
380 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
381 if (unlikely (skip == matcher_t::SKIP_YES))
384 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
385 if (match == matcher_t::MATCH_YES ||
386 (match == matcher_t::MATCH_MAYBE &&
387 skip == matcher_t::SKIP_NO))
394 if (skip == matcher_t::SKIP_NO)
401 assert (num_items > 0);
402 while (idx > num_items - 1)
405 const hb_glyph_info_t &info = c->buffer->out_info[idx];
407 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
408 if (unlikely (skip == matcher_t::SKIP_YES))
411 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
412 if (match == matcher_t::MATCH_YES ||
413 (match == matcher_t::MATCH_MAYBE &&
414 skip == matcher_t::SKIP_NO))
421 if (skip == matcher_t::SKIP_NO)
429 hb_ot_apply_context_t *c;
431 const HBUINT16 *match_glyph_data;
433 unsigned int num_items;
438 const char *get_name () { return "APPLY"; }
439 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
440 template <typename T>
441 return_t dispatch (const T &obj) { return obj.apply (this); }
442 static return_t default_return_value () { return false; }
443 bool stop_sublookup_iteration (return_t r) const { return r; }
444 return_t recurse (unsigned int sub_lookup_index)
446 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
447 return default_return_value ();
449 nesting_level_left--;
450 bool ret = recurse_func (this, sub_lookup_index);
451 nesting_level_left++;
455 skipping_iterator_t iter_input, iter_context;
460 recurse_func_t recurse_func;
462 const VariationStore &var_store;
464 hb_direction_t direction;
465 hb_mask_t lookup_mask;
466 unsigned int table_index; /* GSUB/GPOS */
467 unsigned int lookup_index;
468 unsigned int lookup_props;
469 unsigned int nesting_level_left;
470 unsigned int debug_depth;
472 bool has_glyph_classes;
477 uint32_t random_state;
480 hb_ot_apply_context_t (unsigned int table_index_,
482 hb_buffer_t *buffer_) :
483 iter_input (), iter_context (),
484 font (font_), face (font->face), buffer (buffer_),
485 recurse_func (nullptr),
486 gdef (*face->table.GDEF->table),
487 var_store (gdef.get_var_store ()),
488 direction (buffer_->props.direction),
490 table_index (table_index_),
491 lookup_index ((unsigned int) -1),
493 nesting_level_left (HB_MAX_NESTING_LEVEL),
495 has_glyph_classes (gdef.has_glyph_classes ()),
499 random_state (1) { init_iters (); }
503 iter_input.init (this, false);
504 iter_context.init (this, true);
507 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
508 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
509 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
510 void set_random (bool random_) { random = random_; }
511 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
512 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
513 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
515 uint32_t random_number ()
517 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
518 random_state = random_state * 48271 % 2147483647;
522 bool match_properties_mark (hb_codepoint_t glyph,
523 unsigned int glyph_props,
524 unsigned int match_props) const
526 /* If using mark filtering sets, the high short of
527 * match_props has the set index.
529 if (match_props & LookupFlag::UseMarkFilteringSet)
530 return gdef.mark_set_covers (match_props >> 16, glyph);
532 /* The second byte of match_props has the meaning
533 * "ignore marks of attachment type different than
534 * the attachment type specified."
536 if (match_props & LookupFlag::MarkAttachmentType)
537 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
542 bool check_glyph_property (const hb_glyph_info_t *info,
543 unsigned int match_props) const
545 hb_codepoint_t glyph = info->codepoint;
546 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
548 /* Not covered, if, for example, glyph class is ligature and
549 * match_props includes LookupFlags::IgnoreLigatures
551 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
554 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
555 return match_properties_mark (glyph, glyph_props, match_props);
560 void _set_glyph_props (hb_codepoint_t glyph_index,
561 unsigned int class_guess = 0,
562 bool ligature = false,
563 bool component = false) const
565 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
566 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
567 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
570 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
571 /* In the only place that the MULTIPLIED bit is used, Uniscribe
572 * seems to only care about the "last" transformation between
573 * Ligature and Multiple substitutions. Ie. if you ligate, expand,
574 * and ligate again, it forgives the multiplication and acts as
575 * if only ligation happened. As such, clear MULTIPLIED bit.
577 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
580 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
581 if (likely (has_glyph_classes))
582 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
583 else if (class_guess)
584 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
587 void replace_glyph (hb_codepoint_t glyph_index) const
589 _set_glyph_props (glyph_index);
590 buffer->replace_glyph (glyph_index);
592 void replace_glyph_inplace (hb_codepoint_t glyph_index) const
594 _set_glyph_props (glyph_index);
595 buffer->cur().codepoint = glyph_index;
597 void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
598 unsigned int class_guess) const
600 _set_glyph_props (glyph_index, class_guess, true);
601 buffer->replace_glyph (glyph_index);
603 void output_glyph_for_component (hb_codepoint_t glyph_index,
604 unsigned int class_guess) const
606 _set_glyph_props (glyph_index, class_guess, false, true);
607 buffer->output_glyph (glyph_index);
612 struct hb_get_subtables_context_t :
613 hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
615 template <typename Type>
616 static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
618 const Type *typed_obj = (const Type *) obj;
619 return typed_obj->apply (c);
622 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
624 struct hb_applicable_t
626 template <typename T>
627 void init (const T &obj_, hb_apply_func_t apply_func_)
630 apply_func = apply_func_;
632 obj_.get_coverage ().add_coverage (&digest);
635 bool apply (OT::hb_ot_apply_context_t *c) const
637 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
642 hb_apply_func_t apply_func;
643 hb_set_digest_t digest;
646 typedef hb_vector_t<hb_applicable_t> array_t;
648 /* Dispatch interface. */
649 const char *get_name () { return "GET_SUBTABLES"; }
650 template <typename T>
651 return_t dispatch (const T &obj)
653 hb_applicable_t *entry = array.push();
654 entry->init (obj, apply_to<T>);
657 static return_t default_return_value () { return HB_VOID; }
659 hb_get_subtables_context_t (array_t &array_) :
664 unsigned int debug_depth;
670 typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
671 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
672 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
674 struct ContextClosureFuncs
676 intersects_func_t intersects;
678 struct ContextCollectGlyphsFuncs
680 collect_glyphs_func_t collect;
682 struct ContextApplyFuncs
688 static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
690 return glyphs->has (value);
692 static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
694 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
695 return class_def.intersects_class (glyphs, value);
697 static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
699 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
700 return (data+coverage).intersects (glyphs);
703 static inline bool intersects_array (const hb_set_t *glyphs,
705 const HBUINT16 values[],
706 intersects_func_t intersects_func,
707 const void *intersects_data)
709 for (unsigned int i = 0; i < count; i++)
710 if (likely (!intersects_func (glyphs, values[i], intersects_data)))
716 static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
720 static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
722 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
723 class_def.add_class (glyphs, value);
725 static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
727 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
728 (data+coverage).add_coverage (glyphs);
730 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
733 const HBUINT16 values[],
734 collect_glyphs_func_t collect_func,
735 const void *collect_data)
737 for (unsigned int i = 0; i < count; i++)
738 collect_func (glyphs, values[i], collect_data);
742 static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
744 return glyph_id == value;
746 static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
748 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
749 return class_def.get_class (glyph_id) == value;
751 static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
753 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
754 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
757 static inline bool would_match_input (hb_would_apply_context_t *c,
758 unsigned int count, /* Including the first glyph (not matched) */
759 const HBUINT16 input[], /* Array of input values--start with second glyph */
760 match_func_t match_func,
761 const void *match_data)
766 for (unsigned int i = 1; i < count; i++)
767 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
772 static inline bool match_input (hb_ot_apply_context_t *c,
773 unsigned int count, /* Including the first glyph (not matched) */
774 const HBUINT16 input[], /* Array of input values--start with second glyph */
775 match_func_t match_func,
776 const void *match_data,
777 unsigned int *end_offset,
778 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
779 unsigned int *p_total_component_count = nullptr)
781 TRACE_APPLY (nullptr);
783 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
785 hb_buffer_t *buffer = c->buffer;
787 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
788 skippy_iter.reset (buffer->idx, count - 1);
789 skippy_iter.set_match_func (match_func, match_data, input);
792 * This is perhaps the trickiest part of OpenType... Remarks:
794 * - If all components of the ligature were marks, we call this a mark ligature.
796 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
797 * it as a ligature glyph.
799 * - Ligatures cannot be formed across glyphs attached to different components
800 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
801 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
802 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
803 * There are a couple of exceptions to this:
805 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
806 * assuming that the font designer knows what they are doing (otherwise it can
807 * break Indic stuff when a matra wants to ligate with a conjunct,
809 * o If two marks want to ligate and they belong to different components of the
810 * same ligature glyph, and said ligature glyph is to be ignored according to
811 * mark-filtering rules, then allow.
812 * https://github.com/harfbuzz/harfbuzz/issues/545
815 unsigned int total_component_count = 0;
816 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
818 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
819 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
823 LIGBASE_MAY_NOT_SKIP,
825 } ligbase = LIGBASE_NOT_CHECKED;
827 match_positions[0] = buffer->idx;
828 for (unsigned int i = 1; i < count; i++)
830 if (!skippy_iter.next ()) return_trace (false);
832 match_positions[i] = skippy_iter.idx;
834 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
835 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
837 if (first_lig_id && first_lig_comp)
839 /* If first component was attached to a previous ligature component,
840 * all subsequent components should be attached to the same ligature
841 * component, otherwise we shouldn't ligate them... */
842 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
844 /* ...unless, we are attached to a base ligature and that base
845 * ligature is ignorable. */
846 if (ligbase == LIGBASE_NOT_CHECKED)
849 const hb_glyph_info_t *out = buffer->out_info;
850 unsigned int j = buffer->out_len;
851 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
853 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
862 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
863 ligbase = LIGBASE_MAY_SKIP;
865 ligbase = LIGBASE_MAY_NOT_SKIP;
868 if (ligbase == LIGBASE_MAY_NOT_SKIP)
869 return_trace (false);
874 /* If first component was NOT attached to a previous ligature component,
875 * all subsequent components should also NOT be attached to any ligature
876 * component, unless they are attached to the first component itself! */
877 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
878 return_trace (false);
881 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
884 *end_offset = skippy_iter.idx - buffer->idx + 1;
886 if (p_total_component_count)
887 *p_total_component_count = total_component_count;
891 static inline bool ligate_input (hb_ot_apply_context_t *c,
892 unsigned int count, /* Including the first glyph */
893 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
894 unsigned int match_length,
895 hb_codepoint_t lig_glyph,
896 unsigned int total_component_count)
898 TRACE_APPLY (nullptr);
900 hb_buffer_t *buffer = c->buffer;
902 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
904 /* - If a base and one or more marks ligate, consider that as a base, NOT
905 * ligature, such that all following marks can still attach to it.
906 * https://github.com/harfbuzz/harfbuzz/issues/1109
908 * - If all components of the ligature were marks, we call this a mark ligature.
909 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave
910 * the ligature to keep its old ligature id. This will allow it to attach to
911 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
912 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
913 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
914 * later, we don't want them to lose their ligature id/component, otherwise
915 * GPOS will fail to correctly position the mark ligature on top of the
916 * LAM,LAM,HEH ligature. See:
917 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
919 * - If a ligature is formed of components that some of which are also ligatures
920 * themselves, and those ligature components had marks attached to *their*
921 * components, we have to attach the marks to the new ligature component
922 * positions! Now *that*'s tricky! And these marks may be following the
923 * last component of the whole sequence, so we should loop forward looking
924 * for them and update them.
926 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
927 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
928 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
929 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
930 * the new ligature with a component value of 2.
932 * This in fact happened to a font... See:
933 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
936 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
937 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
938 for (unsigned int i = 1; i < count; i++)
939 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
941 is_base_ligature = false;
942 is_mark_ligature = false;
945 bool is_ligature = !is_base_ligature && !is_mark_ligature;
947 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
948 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
949 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
950 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
951 unsigned int components_so_far = last_num_components;
955 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
956 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
958 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
961 c->replace_glyph_with_ligature (lig_glyph, klass);
963 for (unsigned int i = 1; i < count; i++)
965 while (buffer->idx < match_positions[i] && buffer->successful)
969 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
971 this_comp = last_num_components;
972 unsigned int new_lig_comp = components_so_far - last_num_components +
973 MIN (this_comp, last_num_components);
974 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
976 buffer->next_glyph ();
979 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
980 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
981 components_so_far += last_num_components;
983 /* Skip the base glyph */
987 if (!is_mark_ligature && last_lig_id) {
988 /* Re-adjust components for any marks following. */
989 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
990 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
991 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
994 unsigned int new_lig_comp = components_so_far - last_num_components +
995 MIN (this_comp, last_num_components);
996 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
1001 return_trace (true);
1004 static inline bool match_backtrack (hb_ot_apply_context_t *c,
1006 const HBUINT16 backtrack[],
1007 match_func_t match_func,
1008 const void *match_data,
1009 unsigned int *match_start)
1011 TRACE_APPLY (nullptr);
1013 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1014 skippy_iter.reset (c->buffer->backtrack_len (), count);
1015 skippy_iter.set_match_func (match_func, match_data, backtrack);
1017 for (unsigned int i = 0; i < count; i++)
1018 if (!skippy_iter.prev ())
1019 return_trace (false);
1021 *match_start = skippy_iter.idx;
1023 return_trace (true);
1026 static inline bool match_lookahead (hb_ot_apply_context_t *c,
1028 const HBUINT16 lookahead[],
1029 match_func_t match_func,
1030 const void *match_data,
1031 unsigned int offset,
1032 unsigned int *end_index)
1034 TRACE_APPLY (nullptr);
1036 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1037 skippy_iter.reset (c->buffer->idx + offset - 1, count);
1038 skippy_iter.set_match_func (match_func, match_data, lookahead);
1040 for (unsigned int i = 0; i < count; i++)
1041 if (!skippy_iter.next ())
1042 return_trace (false);
1044 *end_index = skippy_iter.idx + 1;
1046 return_trace (true);
1053 bool sanitize (hb_sanitize_context_t *c) const
1055 TRACE_SANITIZE (this);
1056 return_trace (c->check_struct (this));
1059 HBUINT16 sequenceIndex; /* Index into current glyph
1060 * sequence--first glyph = 0 */
1061 HBUINT16 lookupListIndex; /* Lookup to apply to that
1062 * position--zero--based */
1064 DEFINE_SIZE_STATIC (4);
1067 template <typename context_t>
1068 static inline void recurse_lookups (context_t *c,
1069 unsigned int lookupCount,
1070 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1072 for (unsigned int i = 0; i < lookupCount; i++)
1073 c->recurse (lookupRecord[i].lookupListIndex);
1076 static inline bool apply_lookup (hb_ot_apply_context_t *c,
1077 unsigned int count, /* Including the first glyph */
1078 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
1079 unsigned int lookupCount,
1080 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1081 unsigned int match_length)
1083 TRACE_APPLY (nullptr);
1085 hb_buffer_t *buffer = c->buffer;
1088 /* All positions are distance from beginning of *output* buffer.
1091 unsigned int bl = buffer->backtrack_len ();
1092 end = bl + match_length;
1094 int delta = bl - buffer->idx;
1095 /* Convert positions to new indexing. */
1096 for (unsigned int j = 0; j < count; j++)
1097 match_positions[j] += delta;
1100 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
1102 unsigned int idx = lookupRecord[i].sequenceIndex;
1106 /* Don't recurse to ourself at same position.
1107 * Note that this test is too naive, it doesn't catch longer loops. */
1108 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1111 if (unlikely (!buffer->move_to (match_positions[idx])))
1114 if (unlikely (buffer->max_ops <= 0))
1117 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1118 if (!c->recurse (lookupRecord[i].lookupListIndex))
1121 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1122 int delta = new_len - orig_len;
1127 /* Recursed lookup changed buffer len. Adjust.
1131 * Right now, if buffer length increased by n, we assume n new glyphs
1132 * were added right after the current position, and if buffer length
1133 * was decreased by n, we assume n match positions after the current
1134 * one where removed. The former (buffer length increased) case is
1135 * fine, but the decrease case can be improved in at least two ways,
1136 * both of which are significant:
1138 * - If recursed-to lookup is MultipleSubst and buffer length
1139 * decreased, then it's current match position that was deleted,
1140 * NOT the one after it.
1142 * - If buffer length was decreased by n, it does not necessarily
1143 * mean that n match positions where removed, as there might
1144 * have been marks and default-ignorables in the sequence. We
1145 * should instead drop match positions between current-position
1146 * and current-position + n instead.
1148 * It should be possible to construct tests for both of these cases.
1152 if (end <= int (match_positions[idx]))
1154 /* End might end up being smaller than match_positions[idx] if the recursed
1155 * lookup ended up removing many items, more than we have had matched.
1156 * Just never rewind end back and get out of here.
1157 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1158 end = match_positions[idx];
1159 /* There can't be any further changes. */
1163 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1167 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1172 /* NOTE: delta is negative. */
1173 delta = MAX (delta, (int) next - (int) count);
1178 memmove (match_positions + next + delta, match_positions + next,
1179 (count - next) * sizeof (match_positions[0]));
1183 /* Fill in new entries. */
1184 for (unsigned int j = idx + 1; j < next; j++)
1185 match_positions[j] = match_positions[j - 1] + 1;
1187 /* And fixup the rest. */
1188 for (; next < count; next++)
1189 match_positions[next] += delta;
1192 buffer->move_to (end);
1194 return_trace (true);
1199 /* Contextual lookups */
1201 struct ContextClosureLookupContext
1203 ContextClosureFuncs funcs;
1204 const void *intersects_data;
1207 struct ContextCollectGlyphsLookupContext
1209 ContextCollectGlyphsFuncs funcs;
1210 const void *collect_data;
1213 struct ContextApplyLookupContext
1215 ContextApplyFuncs funcs;
1216 const void *match_data;
1219 static inline bool context_intersects (const hb_set_t *glyphs,
1220 unsigned int inputCount, /* Including the first glyph (not matched) */
1221 const HBUINT16 input[], /* Array of input values--start with second glyph */
1222 ContextClosureLookupContext &lookup_context)
1224 return intersects_array (glyphs,
1225 inputCount ? inputCount - 1 : 0, input,
1226 lookup_context.funcs.intersects, lookup_context.intersects_data);
1229 static inline void context_closure_lookup (hb_closure_context_t *c,
1230 unsigned int inputCount, /* Including the first glyph (not matched) */
1231 const HBUINT16 input[], /* Array of input values--start with second glyph */
1232 unsigned int lookupCount,
1233 const LookupRecord lookupRecord[],
1234 ContextClosureLookupContext &lookup_context)
1236 if (context_intersects (c->glyphs,
1240 lookupCount, lookupRecord);
1243 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1244 unsigned int inputCount, /* Including the first glyph (not matched) */
1245 const HBUINT16 input[], /* Array of input values--start with second glyph */
1246 unsigned int lookupCount,
1247 const LookupRecord lookupRecord[],
1248 ContextCollectGlyphsLookupContext &lookup_context)
1250 collect_array (c, c->input,
1251 inputCount ? inputCount - 1 : 0, input,
1252 lookup_context.funcs.collect, lookup_context.collect_data);
1254 lookupCount, lookupRecord);
1257 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1258 unsigned int inputCount, /* Including the first glyph (not matched) */
1259 const HBUINT16 input[], /* Array of input values--start with second glyph */
1260 unsigned int lookupCount HB_UNUSED,
1261 const LookupRecord lookupRecord[] HB_UNUSED,
1262 ContextApplyLookupContext &lookup_context)
1264 return would_match_input (c,
1266 lookup_context.funcs.match, lookup_context.match_data);
1268 static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
1269 unsigned int inputCount, /* Including the first glyph (not matched) */
1270 const HBUINT16 input[], /* Array of input values--start with second glyph */
1271 unsigned int lookupCount,
1272 const LookupRecord lookupRecord[],
1273 ContextApplyLookupContext &lookup_context)
1275 unsigned int match_length = 0;
1276 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1277 return match_input (c,
1279 lookup_context.funcs.match, lookup_context.match_data,
1280 &match_length, match_positions)
1281 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1283 inputCount, match_positions,
1284 lookupCount, lookupRecord,
1290 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
1292 return context_intersects (glyphs,
1293 inputCount, inputZ.arrayZ,
1297 void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1299 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1300 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
1301 context_closure_lookup (c,
1302 inputCount, inputZ.arrayZ,
1303 lookupCount, lookupRecord.arrayZ,
1307 void collect_glyphs (hb_collect_glyphs_context_t *c,
1308 ContextCollectGlyphsLookupContext &lookup_context) const
1310 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1311 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1312 context_collect_glyphs_lookup (c,
1313 inputCount, inputZ.arrayZ,
1314 lookupCount, lookupRecord.arrayZ,
1318 bool would_apply (hb_would_apply_context_t *c,
1319 ContextApplyLookupContext &lookup_context) const
1321 TRACE_WOULD_APPLY (this);
1322 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1323 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1324 return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1327 bool apply (hb_ot_apply_context_t *c,
1328 ContextApplyLookupContext &lookup_context) const
1331 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1332 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1333 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1337 bool sanitize (hb_sanitize_context_t *c) const
1339 TRACE_SANITIZE (this);
1340 return_trace (inputCount.sanitize (c) &&
1341 lookupCount.sanitize (c) &&
1342 c->check_range (inputZ.arrayZ,
1343 inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
1344 LookupRecord::static_size * lookupCount));
1348 HBUINT16 inputCount; /* Total number of glyphs in input
1349 * glyph sequence--includes the first
1351 HBUINT16 lookupCount; /* Number of LookupRecords */
1352 UnsizedArrayOf<HBUINT16>
1353 inputZ; /* Array of match inputs--start with
1355 /*UnsizedArrayOf<LookupRecord>
1356 lookupRecordX;*/ /* Array of LookupRecords--in
1359 DEFINE_SIZE_ARRAY (4, inputZ);
1364 bool intersects (const hb_set_t *glyphs,
1365 ContextClosureLookupContext &lookup_context) const
1367 unsigned int num_rules = rule.len;
1368 for (unsigned int i = 0; i < num_rules; i++)
1369 if ((this+rule[i]).intersects (glyphs, lookup_context))
1374 void closure (hb_closure_context_t *c,
1375 ContextClosureLookupContext &lookup_context) const
1377 unsigned int num_rules = rule.len;
1378 for (unsigned int i = 0; i < num_rules; i++)
1379 (this+rule[i]).closure (c, lookup_context);
1382 void collect_glyphs (hb_collect_glyphs_context_t *c,
1383 ContextCollectGlyphsLookupContext &lookup_context) const
1385 unsigned int num_rules = rule.len;
1386 for (unsigned int i = 0; i < num_rules; i++)
1387 (this+rule[i]).collect_glyphs (c, lookup_context);
1390 bool would_apply (hb_would_apply_context_t *c,
1391 ContextApplyLookupContext &lookup_context) const
1393 TRACE_WOULD_APPLY (this);
1394 unsigned int num_rules = rule.len;
1395 for (unsigned int i = 0; i < num_rules; i++)
1397 if ((this+rule[i]).would_apply (c, lookup_context))
1398 return_trace (true);
1400 return_trace (false);
1403 bool apply (hb_ot_apply_context_t *c,
1404 ContextApplyLookupContext &lookup_context) const
1407 unsigned int num_rules = rule.len;
1408 for (unsigned int i = 0; i < num_rules; i++)
1410 if ((this+rule[i]).apply (c, lookup_context))
1411 return_trace (true);
1413 return_trace (false);
1416 bool sanitize (hb_sanitize_context_t *c) const
1418 TRACE_SANITIZE (this);
1419 return_trace (rule.sanitize (c, this));
1424 rule; /* Array of Rule tables
1425 * ordered by preference */
1427 DEFINE_SIZE_ARRAY (2, rule);
1431 struct ContextFormat1
1433 bool intersects (const hb_set_t *glyphs) const
1435 struct ContextClosureLookupContext lookup_context = {
1440 unsigned int count = ruleSet.len;
1441 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1443 if (unlikely (iter.get_coverage () >= count))
1444 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1445 if (glyphs->has (iter.get_glyph ()) &&
1446 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
1452 void closure (hb_closure_context_t *c) const
1454 struct ContextClosureLookupContext lookup_context = {
1459 unsigned int count = ruleSet.len;
1460 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1462 if (unlikely (iter.get_coverage () >= count))
1463 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1464 if (c->glyphs->has (iter.get_glyph ()))
1465 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
1469 void collect_glyphs (hb_collect_glyphs_context_t *c) const
1471 (this+coverage).add_coverage (c->input);
1473 struct ContextCollectGlyphsLookupContext lookup_context = {
1478 unsigned int count = ruleSet.len;
1479 for (unsigned int i = 0; i < count; i++)
1480 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1483 bool would_apply (hb_would_apply_context_t *c) const
1485 TRACE_WOULD_APPLY (this);
1487 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1488 struct ContextApplyLookupContext lookup_context = {
1492 return_trace (rule_set.would_apply (c, lookup_context));
1495 const Coverage &get_coverage () const { return this+coverage; }
1497 bool apply (hb_ot_apply_context_t *c) const
1500 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1501 if (likely (index == NOT_COVERED))
1502 return_trace (false);
1504 const RuleSet &rule_set = this+ruleSet[index];
1505 struct ContextApplyLookupContext lookup_context = {
1509 return_trace (rule_set.apply (c, lookup_context));
1512 bool subset (hb_subset_context_t *c) const
1514 TRACE_SUBSET (this);
1516 return_trace (false);
1519 bool sanitize (hb_sanitize_context_t *c) const
1521 TRACE_SANITIZE (this);
1522 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1526 HBUINT16 format; /* Format identifier--format = 1 */
1528 coverage; /* Offset to Coverage table--from
1529 * beginning of table */
1530 OffsetArrayOf<RuleSet>
1531 ruleSet; /* Array of RuleSet tables
1532 * ordered by Coverage Index */
1534 DEFINE_SIZE_ARRAY (6, ruleSet);
1538 struct ContextFormat2
1540 bool intersects (const hb_set_t *glyphs) const
1542 if (!(this+coverage).intersects (glyphs))
1545 const ClassDef &class_def = this+classDef;
1547 struct ContextClosureLookupContext lookup_context = {
1552 unsigned int count = ruleSet.len;
1553 for (unsigned int i = 0; i < count; i++)
1554 if (class_def.intersects_class (glyphs, i) &&
1555 (this+ruleSet[i]).intersects (glyphs, lookup_context))
1561 void closure (hb_closure_context_t *c) const
1563 if (!(this+coverage).intersects (c->glyphs))
1566 const ClassDef &class_def = this+classDef;
1568 struct ContextClosureLookupContext lookup_context = {
1573 unsigned int count = ruleSet.len;
1574 for (unsigned int i = 0; i < count; i++)
1575 if (class_def.intersects_class (c->glyphs, i)) {
1576 const RuleSet &rule_set = this+ruleSet[i];
1577 rule_set.closure (c, lookup_context);
1581 void collect_glyphs (hb_collect_glyphs_context_t *c) const
1583 (this+coverage).add_coverage (c->input);
1585 const ClassDef &class_def = this+classDef;
1586 struct ContextCollectGlyphsLookupContext lookup_context = {
1591 unsigned int count = ruleSet.len;
1592 for (unsigned int i = 0; i < count; i++)
1593 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1596 bool would_apply (hb_would_apply_context_t *c) const
1598 TRACE_WOULD_APPLY (this);
1600 const ClassDef &class_def = this+classDef;
1601 unsigned int index = class_def.get_class (c->glyphs[0]);
1602 const RuleSet &rule_set = this+ruleSet[index];
1603 struct ContextApplyLookupContext lookup_context = {
1607 return_trace (rule_set.would_apply (c, lookup_context));
1610 const Coverage &get_coverage () const { return this+coverage; }
1612 bool apply (hb_ot_apply_context_t *c) const
1615 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1616 if (likely (index == NOT_COVERED)) return_trace (false);
1618 const ClassDef &class_def = this+classDef;
1619 index = class_def.get_class (c->buffer->cur().codepoint);
1620 const RuleSet &rule_set = this+ruleSet[index];
1621 struct ContextApplyLookupContext lookup_context = {
1625 return_trace (rule_set.apply (c, lookup_context));
1628 bool subset (hb_subset_context_t *c) const
1630 TRACE_SUBSET (this);
1632 return_trace (false);
1635 bool sanitize (hb_sanitize_context_t *c) const
1637 TRACE_SANITIZE (this);
1638 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
1642 HBUINT16 format; /* Format identifier--format = 2 */
1644 coverage; /* Offset to Coverage table--from
1645 * beginning of table */
1647 classDef; /* Offset to glyph ClassDef table--from
1648 * beginning of table */
1649 OffsetArrayOf<RuleSet>
1650 ruleSet; /* Array of RuleSet tables
1651 * ordered by class */
1653 DEFINE_SIZE_ARRAY (8, ruleSet);
1657 struct ContextFormat3
1659 bool intersects (const hb_set_t *glyphs) const
1661 if (!(this+coverageZ[0]).intersects (glyphs))
1664 struct ContextClosureLookupContext lookup_context = {
1665 {intersects_coverage},
1668 return context_intersects (glyphs,
1669 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1673 void closure (hb_closure_context_t *c) const
1675 if (!(this+coverageZ[0]).intersects (c->glyphs))
1678 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1679 struct ContextClosureLookupContext lookup_context = {
1680 {intersects_coverage},
1683 context_closure_lookup (c,
1684 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1685 lookupCount, lookupRecord,
1689 void collect_glyphs (hb_collect_glyphs_context_t *c) const
1691 (this+coverageZ[0]).add_coverage (c->input);
1693 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1694 struct ContextCollectGlyphsLookupContext lookup_context = {
1699 context_collect_glyphs_lookup (c,
1700 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1701 lookupCount, lookupRecord,
1705 bool would_apply (hb_would_apply_context_t *c) const
1707 TRACE_WOULD_APPLY (this);
1709 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1710 struct ContextApplyLookupContext lookup_context = {
1714 return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1717 const Coverage &get_coverage () const { return this+coverageZ[0]; }
1719 bool apply (hb_ot_apply_context_t *c) const
1722 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
1723 if (likely (index == NOT_COVERED)) return_trace (false);
1725 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1726 struct ContextApplyLookupContext lookup_context = {
1730 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1733 bool subset (hb_subset_context_t *c) const
1735 TRACE_SUBSET (this);
1737 return_trace (false);
1740 bool sanitize (hb_sanitize_context_t *c) const
1742 TRACE_SANITIZE (this);
1743 if (!c->check_struct (this)) return_trace (false);
1744 unsigned int count = glyphCount;
1745 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1746 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
1747 for (unsigned int i = 0; i < count; i++)
1748 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
1749 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1750 return_trace (c->check_array (lookupRecord, lookupCount));
1754 HBUINT16 format; /* Format identifier--format = 3 */
1755 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
1757 HBUINT16 lookupCount; /* Number of LookupRecords */
1758 UnsizedArrayOf<OffsetTo<Coverage> >
1759 coverageZ; /* Array of offsets to Coverage
1760 * table in glyph sequence order */
1761 /*UnsizedArrayOf<LookupRecord>
1762 lookupRecordX;*/ /* Array of LookupRecords--in
1765 DEFINE_SIZE_ARRAY (6, coverageZ);
1770 template <typename context_t>
1771 typename context_t::return_t dispatch (context_t *c) const
1773 TRACE_DISPATCH (this, u.format);
1774 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1776 case 1: return_trace (c->dispatch (u.format1));
1777 case 2: return_trace (c->dispatch (u.format2));
1778 case 3: return_trace (c->dispatch (u.format3));
1779 default:return_trace (c->default_return_value ());
1785 HBUINT16 format; /* Format identifier */
1786 ContextFormat1 format1;
1787 ContextFormat2 format2;
1788 ContextFormat3 format3;
1793 /* Chaining Contextual lookups */
1795 struct ChainContextClosureLookupContext
1797 ContextClosureFuncs funcs;
1798 const void *intersects_data[3];
1801 struct ChainContextCollectGlyphsLookupContext
1803 ContextCollectGlyphsFuncs funcs;
1804 const void *collect_data[3];
1807 struct ChainContextApplyLookupContext
1809 ContextApplyFuncs funcs;
1810 const void *match_data[3];
1813 static inline bool chain_context_intersects (const hb_set_t *glyphs,
1814 unsigned int backtrackCount,
1815 const HBUINT16 backtrack[],
1816 unsigned int inputCount, /* Including the first glyph (not matched) */
1817 const HBUINT16 input[], /* Array of input values--start with second glyph */
1818 unsigned int lookaheadCount,
1819 const HBUINT16 lookahead[],
1820 ChainContextClosureLookupContext &lookup_context)
1822 return intersects_array (glyphs,
1823 backtrackCount, backtrack,
1824 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1825 && intersects_array (glyphs,
1826 inputCount ? inputCount - 1 : 0, input,
1827 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1828 && intersects_array (glyphs,
1829 lookaheadCount, lookahead,
1830 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
1833 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1834 unsigned int backtrackCount,
1835 const HBUINT16 backtrack[],
1836 unsigned int inputCount, /* Including the first glyph (not matched) */
1837 const HBUINT16 input[], /* Array of input values--start with second glyph */
1838 unsigned int lookaheadCount,
1839 const HBUINT16 lookahead[],
1840 unsigned int lookupCount,
1841 const LookupRecord lookupRecord[],
1842 ChainContextClosureLookupContext &lookup_context)
1844 if (chain_context_intersects (c->glyphs,
1845 backtrackCount, backtrack,
1847 lookaheadCount, lookahead,
1850 lookupCount, lookupRecord);
1853 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1854 unsigned int backtrackCount,
1855 const HBUINT16 backtrack[],
1856 unsigned int inputCount, /* Including the first glyph (not matched) */
1857 const HBUINT16 input[], /* Array of input values--start with second glyph */
1858 unsigned int lookaheadCount,
1859 const HBUINT16 lookahead[],
1860 unsigned int lookupCount,
1861 const LookupRecord lookupRecord[],
1862 ChainContextCollectGlyphsLookupContext &lookup_context)
1864 collect_array (c, c->before,
1865 backtrackCount, backtrack,
1866 lookup_context.funcs.collect, lookup_context.collect_data[0]);
1867 collect_array (c, c->input,
1868 inputCount ? inputCount - 1 : 0, input,
1869 lookup_context.funcs.collect, lookup_context.collect_data[1]);
1870 collect_array (c, c->after,
1871 lookaheadCount, lookahead,
1872 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1874 lookupCount, lookupRecord);
1877 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1878 unsigned int backtrackCount,
1879 const HBUINT16 backtrack[] HB_UNUSED,
1880 unsigned int inputCount, /* Including the first glyph (not matched) */
1881 const HBUINT16 input[], /* Array of input values--start with second glyph */
1882 unsigned int lookaheadCount,
1883 const HBUINT16 lookahead[] HB_UNUSED,
1884 unsigned int lookupCount HB_UNUSED,
1885 const LookupRecord lookupRecord[] HB_UNUSED,
1886 ChainContextApplyLookupContext &lookup_context)
1888 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1889 && would_match_input (c,
1891 lookup_context.funcs.match, lookup_context.match_data[1]);
1894 static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
1895 unsigned int backtrackCount,
1896 const HBUINT16 backtrack[],
1897 unsigned int inputCount, /* Including the first glyph (not matched) */
1898 const HBUINT16 input[], /* Array of input values--start with second glyph */
1899 unsigned int lookaheadCount,
1900 const HBUINT16 lookahead[],
1901 unsigned int lookupCount,
1902 const LookupRecord lookupRecord[],
1903 ChainContextApplyLookupContext &lookup_context)
1905 unsigned int start_index = 0, match_length = 0, end_index = 0;
1906 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1907 return match_input (c,
1909 lookup_context.funcs.match, lookup_context.match_data[1],
1910 &match_length, match_positions)
1911 && match_backtrack (c,
1912 backtrackCount, backtrack,
1913 lookup_context.funcs.match, lookup_context.match_data[0],
1915 && match_lookahead (c,
1916 lookaheadCount, lookahead,
1917 lookup_context.funcs.match, lookup_context.match_data[2],
1918 match_length, &end_index)
1919 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1921 inputCount, match_positions,
1922 lookupCount, lookupRecord,
1928 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
1930 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1931 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1932 return chain_context_intersects (glyphs,
1933 backtrack.len, backtrack.arrayZ,
1934 input.lenP1, input.arrayZ,
1935 lookahead.len, lookahead.arrayZ,
1939 void closure (hb_closure_context_t *c,
1940 ChainContextClosureLookupContext &lookup_context) const
1942 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1943 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1944 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1945 chain_context_closure_lookup (c,
1946 backtrack.len, backtrack.arrayZ,
1947 input.lenP1, input.arrayZ,
1948 lookahead.len, lookahead.arrayZ,
1949 lookup.len, lookup.arrayZ,
1953 void collect_glyphs (hb_collect_glyphs_context_t *c,
1954 ChainContextCollectGlyphsLookupContext &lookup_context) const
1956 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1957 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1958 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1959 chain_context_collect_glyphs_lookup (c,
1960 backtrack.len, backtrack.arrayZ,
1961 input.lenP1, input.arrayZ,
1962 lookahead.len, lookahead.arrayZ,
1963 lookup.len, lookup.arrayZ,
1967 bool would_apply (hb_would_apply_context_t *c,
1968 ChainContextApplyLookupContext &lookup_context) const
1970 TRACE_WOULD_APPLY (this);
1971 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1972 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1973 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1974 return_trace (chain_context_would_apply_lookup (c,
1975 backtrack.len, backtrack.arrayZ,
1976 input.lenP1, input.arrayZ,
1977 lookahead.len, lookahead.arrayZ, lookup.len,
1978 lookup.arrayZ, lookup_context));
1981 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1984 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1985 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1986 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1987 return_trace (chain_context_apply_lookup (c,
1988 backtrack.len, backtrack.arrayZ,
1989 input.lenP1, input.arrayZ,
1990 lookahead.len, lookahead.arrayZ, lookup.len,
1991 lookup.arrayZ, lookup_context));
1994 bool sanitize (hb_sanitize_context_t *c) const
1996 TRACE_SANITIZE (this);
1997 if (!backtrack.sanitize (c)) return_trace (false);
1998 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1999 if (!input.sanitize (c)) return_trace (false);
2000 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
2001 if (!lookahead.sanitize (c)) return_trace (false);
2002 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2003 return_trace (lookup.sanitize (c));
2008 backtrack; /* Array of backtracking values
2009 * (to be matched before the input
2011 HeadlessArrayOf<HBUINT16>
2012 inputX; /* Array of input values (start with
2015 lookaheadX; /* Array of lookahead values's (to be
2016 * matched after the input sequence) */
2017 ArrayOf<LookupRecord>
2018 lookupX; /* Array of LookupRecords--in
2021 DEFINE_SIZE_MIN (8);
2026 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
2028 unsigned int num_rules = rule.len;
2029 for (unsigned int i = 0; i < num_rules; i++)
2030 if ((this+rule[i]).intersects (glyphs, lookup_context))
2034 void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
2036 unsigned int num_rules = rule.len;
2037 for (unsigned int i = 0; i < num_rules; i++)
2038 (this+rule[i]).closure (c, lookup_context);
2041 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
2043 unsigned int num_rules = rule.len;
2044 for (unsigned int i = 0; i < num_rules; i++)
2045 (this+rule[i]).collect_glyphs (c, lookup_context);
2048 bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2050 TRACE_WOULD_APPLY (this);
2051 unsigned int num_rules = rule.len;
2052 for (unsigned int i = 0; i < num_rules; i++)
2053 if ((this+rule[i]).would_apply (c, lookup_context))
2054 return_trace (true);
2056 return_trace (false);
2059 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2062 unsigned int num_rules = rule.len;
2063 for (unsigned int i = 0; i < num_rules; i++)
2064 if ((this+rule[i]).apply (c, lookup_context))
2065 return_trace (true);
2067 return_trace (false);
2070 bool sanitize (hb_sanitize_context_t *c) const
2072 TRACE_SANITIZE (this);
2073 return_trace (rule.sanitize (c, this));
2077 OffsetArrayOf<ChainRule>
2078 rule; /* Array of ChainRule tables
2079 * ordered by preference */
2081 DEFINE_SIZE_ARRAY (2, rule);
2084 struct ChainContextFormat1
2086 bool intersects (const hb_set_t *glyphs) const
2088 struct ChainContextClosureLookupContext lookup_context = {
2090 {nullptr, nullptr, nullptr}
2093 unsigned int count = ruleSet.len;
2094 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
2096 if (unlikely (iter.get_coverage () >= count))
2097 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2098 if (glyphs->has (iter.get_glyph ()) &&
2099 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
2105 void closure (hb_closure_context_t *c) const
2107 struct ChainContextClosureLookupContext lookup_context = {
2109 {nullptr, nullptr, nullptr}
2112 unsigned int count = ruleSet.len;
2113 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
2115 if (unlikely (iter.get_coverage () >= count))
2116 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2117 if (c->glyphs->has (iter.get_glyph ()))
2118 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
2122 void collect_glyphs (hb_collect_glyphs_context_t *c) const
2124 (this+coverage).add_coverage (c->input);
2126 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2128 {nullptr, nullptr, nullptr}
2131 unsigned int count = ruleSet.len;
2132 for (unsigned int i = 0; i < count; i++)
2133 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
2136 bool would_apply (hb_would_apply_context_t *c) const
2138 TRACE_WOULD_APPLY (this);
2140 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
2141 struct ChainContextApplyLookupContext lookup_context = {
2143 {nullptr, nullptr, nullptr}
2145 return_trace (rule_set.would_apply (c, lookup_context));
2148 const Coverage &get_coverage () const { return this+coverage; }
2150 bool apply (hb_ot_apply_context_t *c) const
2153 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2154 if (likely (index == NOT_COVERED)) return_trace (false);
2156 const ChainRuleSet &rule_set = this+ruleSet[index];
2157 struct ChainContextApplyLookupContext lookup_context = {
2159 {nullptr, nullptr, nullptr}
2161 return_trace (rule_set.apply (c, lookup_context));
2164 bool subset (hb_subset_context_t *c) const
2166 TRACE_SUBSET (this);
2168 return_trace (false);
2171 bool sanitize (hb_sanitize_context_t *c) const
2173 TRACE_SANITIZE (this);
2174 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
2178 HBUINT16 format; /* Format identifier--format = 1 */
2180 coverage; /* Offset to Coverage table--from
2181 * beginning of table */
2182 OffsetArrayOf<ChainRuleSet>
2183 ruleSet; /* Array of ChainRuleSet tables
2184 * ordered by Coverage Index */
2186 DEFINE_SIZE_ARRAY (6, ruleSet);
2189 struct ChainContextFormat2
2191 bool intersects (const hb_set_t *glyphs) const
2193 if (!(this+coverage).intersects (glyphs))
2196 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2197 const ClassDef &input_class_def = this+inputClassDef;
2198 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2200 struct ChainContextClosureLookupContext lookup_context = {
2202 {&backtrack_class_def,
2204 &lookahead_class_def}
2207 unsigned int count = ruleSet.len;
2208 for (unsigned int i = 0; i < count; i++)
2209 if (input_class_def.intersects_class (glyphs, i) &&
2210 (this+ruleSet[i]).intersects (glyphs, lookup_context))
2215 void closure (hb_closure_context_t *c) const
2217 if (!(this+coverage).intersects (c->glyphs))
2220 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2221 const ClassDef &input_class_def = this+inputClassDef;
2222 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2224 struct ChainContextClosureLookupContext lookup_context = {
2226 {&backtrack_class_def,
2228 &lookahead_class_def}
2231 unsigned int count = ruleSet.len;
2232 for (unsigned int i = 0; i < count; i++)
2233 if (input_class_def.intersects_class (c->glyphs, i)) {
2234 const ChainRuleSet &rule_set = this+ruleSet[i];
2235 rule_set.closure (c, lookup_context);
2239 void collect_glyphs (hb_collect_glyphs_context_t *c) const
2241 (this+coverage).add_coverage (c->input);
2243 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2244 const ClassDef &input_class_def = this+inputClassDef;
2245 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2247 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2249 {&backtrack_class_def,
2251 &lookahead_class_def}
2254 unsigned int count = ruleSet.len;
2255 for (unsigned int i = 0; i < count; i++)
2256 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
2259 bool would_apply (hb_would_apply_context_t *c) const
2261 TRACE_WOULD_APPLY (this);
2263 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2264 const ClassDef &input_class_def = this+inputClassDef;
2265 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2267 unsigned int index = input_class_def.get_class (c->glyphs[0]);
2268 const ChainRuleSet &rule_set = this+ruleSet[index];
2269 struct ChainContextApplyLookupContext lookup_context = {
2271 {&backtrack_class_def,
2273 &lookahead_class_def}
2275 return_trace (rule_set.would_apply (c, lookup_context));
2278 const Coverage &get_coverage () const { return this+coverage; }
2280 bool apply (hb_ot_apply_context_t *c) const
2283 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2284 if (likely (index == NOT_COVERED)) return_trace (false);
2286 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2287 const ClassDef &input_class_def = this+inputClassDef;
2288 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2290 index = input_class_def.get_class (c->buffer->cur().codepoint);
2291 const ChainRuleSet &rule_set = this+ruleSet[index];
2292 struct ChainContextApplyLookupContext lookup_context = {
2294 {&backtrack_class_def,
2296 &lookahead_class_def}
2298 return_trace (rule_set.apply (c, lookup_context));
2301 bool subset (hb_subset_context_t *c) const
2303 TRACE_SUBSET (this);
2305 return_trace (false);
2308 bool sanitize (hb_sanitize_context_t *c) const
2310 TRACE_SANITIZE (this);
2311 return_trace (coverage.sanitize (c, this) &&
2312 backtrackClassDef.sanitize (c, this) &&
2313 inputClassDef.sanitize (c, this) &&
2314 lookaheadClassDef.sanitize (c, this) &&
2315 ruleSet.sanitize (c, this));
2319 HBUINT16 format; /* Format identifier--format = 2 */
2321 coverage; /* Offset to Coverage table--from
2322 * beginning of table */
2324 backtrackClassDef; /* Offset to glyph ClassDef table
2325 * containing backtrack sequence
2326 * data--from beginning of table */
2328 inputClassDef; /* Offset to glyph ClassDef
2329 * table containing input sequence
2330 * data--from beginning of table */
2332 lookaheadClassDef; /* Offset to glyph ClassDef table
2333 * containing lookahead sequence
2334 * data--from beginning of table */
2335 OffsetArrayOf<ChainRuleSet>
2336 ruleSet; /* Array of ChainRuleSet tables
2337 * ordered by class */
2339 DEFINE_SIZE_ARRAY (12, ruleSet);
2342 struct ChainContextFormat3
2344 bool intersects (const hb_set_t *glyphs) const
2346 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2348 if (!(this+input[0]).intersects (glyphs))
2351 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2352 struct ChainContextClosureLookupContext lookup_context = {
2353 {intersects_coverage},
2356 return chain_context_intersects (glyphs,
2357 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2358 input.len, (const HBUINT16 *) input.arrayZ + 1,
2359 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2363 void closure (hb_closure_context_t *c) const
2365 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2367 if (!(this+input[0]).intersects (c->glyphs))
2370 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2371 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2372 struct ChainContextClosureLookupContext lookup_context = {
2373 {intersects_coverage},
2376 chain_context_closure_lookup (c,
2377 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2378 input.len, (const HBUINT16 *) input.arrayZ + 1,
2379 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2380 lookup.len, lookup.arrayZ,
2384 void collect_glyphs (hb_collect_glyphs_context_t *c) const
2386 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2388 (this+input[0]).add_coverage (c->input);
2390 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2391 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2392 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2396 chain_context_collect_glyphs_lookup (c,
2397 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2398 input.len, (const HBUINT16 *) input.arrayZ + 1,
2399 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2400 lookup.len, lookup.arrayZ,
2404 bool would_apply (hb_would_apply_context_t *c) const
2406 TRACE_WOULD_APPLY (this);
2408 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2409 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2410 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2411 struct ChainContextApplyLookupContext lookup_context = {
2415 return_trace (chain_context_would_apply_lookup (c,
2416 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2417 input.len, (const HBUINT16 *) input.arrayZ + 1,
2418 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2419 lookup.len, lookup.arrayZ, lookup_context));
2422 const Coverage &get_coverage () const
2424 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2425 return this+input[0];
2428 bool apply (hb_ot_apply_context_t *c) const
2431 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2433 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2434 if (likely (index == NOT_COVERED)) return_trace (false);
2436 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2437 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2438 struct ChainContextApplyLookupContext lookup_context = {
2442 return_trace (chain_context_apply_lookup (c,
2443 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2444 input.len, (const HBUINT16 *) input.arrayZ + 1,
2445 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2446 lookup.len, lookup.arrayZ, lookup_context));
2449 bool subset (hb_subset_context_t *c) const
2451 TRACE_SUBSET (this);
2453 return_trace (false);
2456 bool sanitize (hb_sanitize_context_t *c) const
2458 TRACE_SANITIZE (this);
2459 if (!backtrack.sanitize (c, this)) return_trace (false);
2460 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2461 if (!input.sanitize (c, this)) return_trace (false);
2462 if (!input.len) return_trace (false); /* To be consistent with Context. */
2463 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2464 if (!lookahead.sanitize (c, this)) return_trace (false);
2465 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2466 return_trace (lookup.sanitize (c));
2470 HBUINT16 format; /* Format identifier--format = 3 */
2471 OffsetArrayOf<Coverage>
2472 backtrack; /* Array of coverage tables
2473 * in backtracking sequence, in glyph
2475 OffsetArrayOf<Coverage>
2476 inputX ; /* Array of coverage
2477 * tables in input sequence, in glyph
2479 OffsetArrayOf<Coverage>
2480 lookaheadX; /* Array of coverage tables
2481 * in lookahead sequence, in glyph
2483 ArrayOf<LookupRecord>
2484 lookupX; /* Array of LookupRecords--in
2487 DEFINE_SIZE_MIN (10);
2492 template <typename context_t>
2493 typename context_t::return_t dispatch (context_t *c) const
2495 TRACE_DISPATCH (this, u.format);
2496 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2498 case 1: return_trace (c->dispatch (u.format1));
2499 case 2: return_trace (c->dispatch (u.format2));
2500 case 3: return_trace (c->dispatch (u.format3));
2501 default:return_trace (c->default_return_value ());
2507 HBUINT16 format; /* Format identifier */
2508 ChainContextFormat1 format1;
2509 ChainContextFormat2 format2;
2510 ChainContextFormat3 format3;
2515 template <typename T>
2516 struct ExtensionFormat1
2518 unsigned int get_type () const { return extensionLookupType; }
2520 template <typename X>
2521 const X& get_subtable () const
2523 unsigned int offset = extensionOffset;
2524 if (unlikely (!offset)) return Null(typename T::SubTable);
2525 return StructAtOffset<typename T::SubTable> (this, offset);
2528 template <typename context_t>
2529 typename context_t::return_t dispatch (context_t *c) const
2531 TRACE_DISPATCH (this, format);
2532 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
2533 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
2536 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
2537 bool sanitize (hb_sanitize_context_t *c) const
2539 TRACE_SANITIZE (this);
2540 return_trace (c->check_struct (this) &&
2541 extensionOffset != 0 &&
2542 extensionLookupType != T::SubTable::Extension);
2546 HBUINT16 format; /* Format identifier. Set to 1. */
2547 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
2548 * by ExtensionOffset (i.e. the
2549 * extension subtable). */
2550 HBUINT32 extensionOffset; /* Offset to the extension subtable,
2551 * of lookup type subtable. */
2553 DEFINE_SIZE_STATIC (8);
2556 template <typename T>
2559 unsigned int get_type () const
2562 case 1: return u.format1.get_type ();
2566 template <typename X>
2567 const X& get_subtable () const
2570 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
2571 default:return Null(typename T::SubTable);
2575 template <typename context_t>
2576 typename context_t::return_t dispatch (context_t *c) const
2578 TRACE_DISPATCH (this, u.format);
2579 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2581 case 1: return_trace (u.format1.dispatch (c));
2582 default:return_trace (c->default_return_value ());
2588 HBUINT16 format; /* Format identifier */
2589 ExtensionFormat1<T> format1;
2598 struct hb_ot_layout_lookup_accelerator_t
2600 template <typename TLookup>
2601 void init (const TLookup &lookup)
2604 lookup.add_coverage (&digest);
2607 OT::hb_get_subtables_context_t c_get_subtables (subtables);
2608 lookup.dispatch (&c_get_subtables);
2610 void fini () { subtables.fini (); }
2612 bool may_have (hb_codepoint_t g) const
2613 { return digest.may_have (g); }
2615 bool apply (hb_ot_apply_context_t *c) const
2617 for (unsigned int i = 0; i < subtables.length; i++)
2618 if (subtables[i].apply (c))
2624 hb_set_digest_t digest;
2625 hb_get_subtables_context_t::array_t subtables;
2630 bool has_data () const { return version.to_int (); }
2631 unsigned int get_script_count () const
2632 { return (this+scriptList).len; }
2633 const Tag& get_script_tag (unsigned int i) const
2634 { return (this+scriptList).get_tag (i); }
2635 unsigned int get_script_tags (unsigned int start_offset,
2636 unsigned int *script_count /* IN/OUT */,
2637 hb_tag_t *script_tags /* OUT */) const
2638 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
2639 const Script& get_script (unsigned int i) const
2640 { return (this+scriptList)[i]; }
2641 bool find_script_index (hb_tag_t tag, unsigned int *index) const
2642 { return (this+scriptList).find_index (tag, index); }
2644 unsigned int get_feature_count () const
2645 { return (this+featureList).len; }
2646 hb_tag_t get_feature_tag (unsigned int i) const
2647 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
2648 unsigned int get_feature_tags (unsigned int start_offset,
2649 unsigned int *feature_count /* IN/OUT */,
2650 hb_tag_t *feature_tags /* OUT */) const
2651 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
2652 const Feature& get_feature (unsigned int i) const
2653 { return (this+featureList)[i]; }
2654 bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2655 { return (this+featureList).find_index (tag, index); }
2657 unsigned int get_lookup_count () const
2658 { return (this+lookupList).len; }
2659 const Lookup& get_lookup (unsigned int i) const
2660 { return (this+lookupList)[i]; }
2662 bool find_variations_index (const int *coords, unsigned int num_coords,
2663 unsigned int *index) const
2664 { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2665 .find_index (coords, num_coords, index); }
2666 const Feature& get_feature_variation (unsigned int feature_index,
2667 unsigned int variations_index) const
2669 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2670 version.to_int () >= 0x00010001u)
2672 const Feature *feature = (this+featureVars).find_substitute (variations_index,
2677 return get_feature (feature_index);
2680 template <typename TLookup>
2681 bool subset (hb_subset_context_t *c) const
2683 TRACE_SUBSET (this);
2684 struct GSUBGPOS *out = c->serializer->embed (*this);
2685 if (unlikely (!out)) return_trace (false);
2687 out->scriptList.serialize_subset (c, this+scriptList, out);
2688 out->featureList.serialize_subset (c, this+featureList, out);
2690 typedef OffsetListOf<TLookup> TLookupList;
2691 /* TODO Use intersects() to count how many subtables survive? */
2692 CastR<OffsetTo<TLookupList> > (out->lookupList)
2693 .serialize_subset (c,
2694 this+CastR<const OffsetTo<TLookupList> > (lookupList),
2697 if (version.to_int () >= 0x00010001u)
2698 out->featureVars.serialize_subset (c, this+featureVars, out);
2700 return_trace (true);
2703 unsigned int get_size () const
2706 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
2709 template <typename TLookup>
2710 bool sanitize (hb_sanitize_context_t *c) const
2712 TRACE_SANITIZE (this);
2713 typedef OffsetListOf<TLookup> TLookupList;
2714 return_trace (version.sanitize (c) &&
2715 likely (version.major == 1) &&
2716 scriptList.sanitize (c, this) &&
2717 featureList.sanitize (c, this) &&
2718 CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
2719 (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
2722 template <typename T>
2723 struct accelerator_t
2725 void init (hb_face_t *face)
2727 this->table = hb_sanitize_context_t().reference_table<T> (face);
2728 if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
2730 hb_blob_destroy (this->table.get_blob ());
2731 this->table = hb_blob_get_empty ();
2734 this->lookup_count = table->get_lookup_count ();
2736 this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
2737 if (unlikely (!this->accels))
2738 this->lookup_count = 0;
2740 for (unsigned int i = 0; i < this->lookup_count; i++)
2741 this->accels[i].init (table->get_lookup (i));
2746 for (unsigned int i = 0; i < this->lookup_count; i++)
2747 this->accels[i].fini ();
2748 free (this->accels);
2749 this->table.destroy ();
2752 hb_blob_ptr_t<T> table;
2753 unsigned int lookup_count;
2754 hb_ot_layout_lookup_accelerator_t *accels;
2758 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
2760 OffsetTo<ScriptList>
2761 scriptList; /* ScriptList table */
2762 OffsetTo<FeatureList>
2763 featureList; /* FeatureList table */
2764 OffsetTo<LookupList>
2765 lookupList; /* LookupList table */
2766 LOffsetTo<FeatureVariations>
2767 featureVars; /* Offset to Feature Variations
2768 table--from beginning of table
2769 * (may be NULL). Introduced
2770 * in version 0x00010001. */
2772 DEFINE_SIZE_MIN (10);
2776 } /* namespace OT */
2779 #endif /* HB_OT_LAYOUT_GSUBGPOS_HH */