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_PRIVATE_HH
30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
32 #include "hb-private.hh"
33 #include "hb-debug.hh"
34 #include "hb-buffer-private.hh"
35 #include "hb-map-private.hh"
36 #include "hb-ot-layout-gdef-table.hh"
37 #include "hb-set-private.hh"
43 struct hb_closure_context_t :
44 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
46 inline const char *get_name (void) { return "CLOSURE"; }
47 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
49 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
50 static return_t default_return_value (void) { return HB_VOID; }
51 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
52 return_t recurse (unsigned int lookup_index)
54 if (unlikely (nesting_level_left == 0 || !recurse_func))
55 return default_return_value ();
58 recurse_func (this, lookup_index);
63 bool should_visit_lookup (unsigned int lookup_index)
65 if (is_lookup_done (lookup_index))
67 done_lookups->set (lookup_index, glyphs->get_population ());
71 bool is_lookup_done (unsigned int lookup_index)
73 // Have we visited this lookup with the current set of glyphs?
74 return done_lookups->get (lookup_index) == glyphs->get_population ();
79 recurse_func_t recurse_func;
80 unsigned int nesting_level_left;
81 unsigned int debug_depth;
83 hb_closure_context_t (hb_face_t *face_,
85 hb_map_t *done_lookups_,
86 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
89 recurse_func (nullptr),
90 nesting_level_left (nesting_level_left_),
92 done_lookups (done_lookups_) {}
94 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
97 hb_map_t *done_lookups;
101 struct hb_would_apply_context_t :
102 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
104 inline const char *get_name (void) { return "WOULD_APPLY"; }
105 template <typename T>
106 inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
107 static return_t default_return_value (void) { return false; }
108 bool stop_sublookup_iteration (return_t r) const { return r; }
111 const hb_codepoint_t *glyphs;
114 unsigned int debug_depth;
116 hb_would_apply_context_t (hb_face_t *face_,
117 const hb_codepoint_t *glyphs_,
119 bool zero_context_) :
123 zero_context (zero_context_),
128 struct hb_collect_glyphs_context_t :
129 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
131 inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
132 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
133 template <typename T>
134 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
135 static return_t default_return_value (void) { return HB_VOID; }
136 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
137 return_t recurse (unsigned int lookup_index)
139 if (unlikely (nesting_level_left == 0 || !recurse_func))
140 return default_return_value ();
142 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
143 * past the previous check. For GSUB, we only want to collect the output
144 * glyphs in the recursion. If output is not requested, we can go home now.
146 * Note further, that the above is not exactly correct. A recursed lookup
147 * is allowed to match input that is not matched in the context, but that's
148 * not how most fonts are built. It's possible to relax that and recurse
149 * with all sets here if it proves to be an issue.
152 if (output == hb_set_get_empty ())
155 /* Return if new lookup was recursed to before. */
156 if (recursed_lookups->has (lookup_index))
159 hb_set_t *old_before = before;
160 hb_set_t *old_input = input;
161 hb_set_t *old_after = after;
162 before = input = after = hb_set_get_empty ();
164 nesting_level_left--;
165 recurse_func (this, lookup_index);
166 nesting_level_left++;
172 recursed_lookups->add (lookup_index);
182 recurse_func_t recurse_func;
183 hb_set_t *recursed_lookups;
184 unsigned int nesting_level_left;
185 unsigned int debug_depth;
187 hb_collect_glyphs_context_t (hb_face_t *face_,
188 hb_set_t *glyphs_before, /* OUT. May be nullptr */
189 hb_set_t *glyphs_input, /* OUT. May be nullptr */
190 hb_set_t *glyphs_after, /* OUT. May be nullptr */
191 hb_set_t *glyphs_output, /* OUT. May be nullptr */
192 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
194 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
195 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
196 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
197 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
198 recurse_func (nullptr),
199 recursed_lookups (nullptr),
200 nesting_level_left (nesting_level_left_),
203 recursed_lookups = hb_set_create ();
205 ~hb_collect_glyphs_context_t (void)
207 hb_set_destroy (recursed_lookups);
210 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
215 /* XXX Can we remove this? */
217 template <typename set_t>
218 struct hb_add_coverage_context_t :
219 hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
221 inline const char *get_name (void) { return "GET_COVERAGE"; }
222 typedef const Coverage &return_t;
223 template <typename T>
224 inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
225 static return_t default_return_value (void) { return Null(Coverage); }
226 bool stop_sublookup_iteration (return_t r) const
228 r.add_coverage (set);
232 hb_add_coverage_context_t (set_t *set_) :
237 unsigned int debug_depth;
241 struct hb_ot_apply_context_t :
242 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
246 inline matcher_t (void) :
251 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
254 match_func (nullptr),
255 match_data (nullptr) {};
257 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
259 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
260 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
261 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
262 inline void set_mask (hb_mask_t mask_) { mask = mask_; }
263 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; }
264 inline void set_match_func (match_func_t match_func_,
265 const void *match_data_)
266 { match_func = match_func_; match_data = match_data_; }
274 inline may_match_t may_match (const hb_glyph_info_t &info,
275 const HBUINT16 *glyph_data) const
277 if (!(info.mask & mask) ||
278 (syllable && syllable != info.syllable ()))
282 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
294 may_skip (const hb_ot_apply_context_t *c,
295 const hb_glyph_info_t &info) const
297 if (!c->check_glyph_property (&info, lookup_props))
300 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
301 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
302 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
309 unsigned int lookup_props;
314 match_func_t match_func;
315 const void *match_data;
318 struct skipping_iterator_t
320 inline void init (hb_ot_apply_context_t *c_, bool context_match = false)
323 match_glyph_data = nullptr;
324 matcher.set_match_func (nullptr, nullptr);
325 matcher.set_lookup_props (c->lookup_props);
326 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
327 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
328 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
329 matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj));
330 matcher.set_mask (context_match ? -1 : c->lookup_mask);
332 inline void set_lookup_props (unsigned int lookup_props)
334 matcher.set_lookup_props (lookup_props);
336 inline void set_match_func (matcher_t::match_func_t match_func_,
337 const void *match_data_,
338 const HBUINT16 glyph_data[])
340 matcher.set_match_func (match_func_, match_data_);
341 match_glyph_data = glyph_data;
344 inline void reset (unsigned int start_index_,
345 unsigned int num_items_)
348 num_items = num_items_;
349 end = c->buffer->len;
350 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
353 inline void reject (void) { num_items++; match_glyph_data--; }
355 inline matcher_t::may_skip_t
356 may_skip (const hb_glyph_info_t &info) const
358 return matcher.may_skip (c, info);
361 inline bool next (void)
363 assert (num_items > 0);
364 while (idx + num_items < end)
367 const hb_glyph_info_t &info = c->buffer->info[idx];
369 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
370 if (unlikely (skip == matcher_t::SKIP_YES))
373 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
374 if (match == matcher_t::MATCH_YES ||
375 (match == matcher_t::MATCH_MAYBE &&
376 skip == matcher_t::SKIP_NO))
383 if (skip == matcher_t::SKIP_NO)
388 inline bool prev (void)
390 assert (num_items > 0);
391 while (idx >= num_items)
394 const hb_glyph_info_t &info = c->buffer->out_info[idx];
396 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
397 if (unlikely (skip == matcher_t::SKIP_YES))
400 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
401 if (match == matcher_t::MATCH_YES ||
402 (match == matcher_t::MATCH_MAYBE &&
403 skip == matcher_t::SKIP_NO))
410 if (skip == matcher_t::SKIP_NO)
418 hb_ot_apply_context_t *c;
420 const HBUINT16 *match_glyph_data;
422 unsigned int num_items;
427 inline const char *get_name (void) { return "APPLY"; }
428 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
429 template <typename T>
430 inline return_t dispatch (const T &obj) { return obj.apply (this); }
431 static return_t default_return_value (void) { return false; }
432 bool stop_sublookup_iteration (return_t r) const { return r; }
433 return_t recurse (unsigned int sub_lookup_index)
435 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
436 return default_return_value ();
438 nesting_level_left--;
439 bool ret = recurse_func (this, sub_lookup_index);
440 nesting_level_left++;
444 skipping_iterator_t iter_input, iter_context;
449 recurse_func_t recurse_func;
451 const VariationStore &var_store;
453 hb_direction_t direction;
454 hb_mask_t lookup_mask;
455 unsigned int table_index; /* GSUB/GPOS */
456 unsigned int lookup_index;
457 unsigned int lookup_props;
458 unsigned int nesting_level_left;
459 unsigned int debug_depth;
463 bool has_glyph_classes;
466 hb_ot_apply_context_t (unsigned int table_index_,
468 hb_buffer_t *buffer_) :
469 iter_input (), iter_context (),
470 font (font_), face (font->face), buffer (buffer_),
471 recurse_func (nullptr),
472 gdef (*hb_ot_layout_from_face (face)->gdef),
473 var_store (gdef.get_var_store ()),
474 direction (buffer_->props.direction),
476 table_index (table_index_),
477 lookup_index ((unsigned int) -1),
479 nesting_level_left (HB_MAX_NESTING_LEVEL),
483 has_glyph_classes (gdef.has_glyph_classes ()) {}
485 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
486 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
487 inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
488 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
489 inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
490 inline void set_lookup_props (unsigned int lookup_props_)
492 lookup_props = lookup_props_;
493 iter_input.init (this, false);
494 iter_context.init (this, true);
498 match_properties_mark (hb_codepoint_t glyph,
499 unsigned int glyph_props,
500 unsigned int match_props) const
502 /* If using mark filtering sets, the high short of
503 * match_props has the set index.
505 if (match_props & LookupFlag::UseMarkFilteringSet)
506 return gdef.mark_set_covers (match_props >> 16, glyph);
508 /* The second byte of match_props has the meaning
509 * "ignore marks of attachment type different than
510 * the attachment type specified."
512 if (match_props & LookupFlag::MarkAttachmentType)
513 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
519 check_glyph_property (const hb_glyph_info_t *info,
520 unsigned int match_props) const
522 hb_codepoint_t glyph = info->codepoint;
523 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
525 /* Not covered, if, for example, glyph class is ligature and
526 * match_props includes LookupFlags::IgnoreLigatures
528 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
531 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
532 return match_properties_mark (glyph, glyph_props, match_props);
537 inline void _set_glyph_props (hb_codepoint_t glyph_index,
538 unsigned int class_guess = 0,
539 bool ligature = false,
540 bool component = false) const
542 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
543 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
544 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
547 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
548 /* In the only place that the MULTIPLIED bit is used, Uniscribe
549 * seems to only care about the "last" transformation between
550 * Ligature and Multiple substitions. Ie. if you ligate, expand,
551 * and ligate again, it forgives the multiplication and acts as
552 * if only ligation happened. As such, clear MULTIPLIED bit.
554 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
557 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
558 if (likely (has_glyph_classes))
559 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
560 else if (class_guess)
561 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
564 inline void replace_glyph (hb_codepoint_t glyph_index) const
566 _set_glyph_props (glyph_index);
567 buffer->replace_glyph (glyph_index);
569 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
571 _set_glyph_props (glyph_index);
572 buffer->cur().codepoint = glyph_index;
574 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
575 unsigned int class_guess) const
577 _set_glyph_props (glyph_index, class_guess, true);
578 buffer->replace_glyph (glyph_index);
580 inline void output_glyph_for_component (hb_codepoint_t glyph_index,
581 unsigned int class_guess) const
583 _set_glyph_props (glyph_index, class_guess, false, true);
584 buffer->output_glyph (glyph_index);
590 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
591 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
592 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
594 struct ContextClosureFuncs
596 intersects_func_t intersects;
598 struct ContextCollectGlyphsFuncs
600 collect_glyphs_func_t collect;
602 struct ContextApplyFuncs
608 static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
610 return glyphs->has (value);
612 static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
614 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
615 return class_def.intersects_class (glyphs, value);
617 static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
619 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
620 return (data+coverage).intersects (glyphs);
623 static inline bool intersects_array (hb_closure_context_t *c,
625 const HBUINT16 values[],
626 intersects_func_t intersects_func,
627 const void *intersects_data)
629 for (unsigned int i = 0; i < count; i++)
630 if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
636 static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
640 static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
642 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
643 class_def.add_class (glyphs, value);
645 static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
647 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
648 (data+coverage).add_coverage (glyphs);
650 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
653 const HBUINT16 values[],
654 collect_glyphs_func_t collect_func,
655 const void *collect_data)
657 for (unsigned int i = 0; i < count; i++)
658 collect_func (glyphs, values[i], collect_data);
662 static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
664 return glyph_id == value;
666 static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
668 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
669 return class_def.get_class (glyph_id) == value;
671 static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
673 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
674 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
677 static inline bool would_match_input (hb_would_apply_context_t *c,
678 unsigned int count, /* Including the first glyph (not matched) */
679 const HBUINT16 input[], /* Array of input values--start with second glyph */
680 match_func_t match_func,
681 const void *match_data)
686 for (unsigned int i = 1; i < count; i++)
687 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
692 static inline bool match_input (hb_ot_apply_context_t *c,
693 unsigned int count, /* Including the first glyph (not matched) */
694 const HBUINT16 input[], /* Array of input values--start with second glyph */
695 match_func_t match_func,
696 const void *match_data,
697 unsigned int *end_offset,
698 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
699 bool *p_is_mark_ligature = nullptr,
700 unsigned int *p_total_component_count = nullptr)
702 TRACE_APPLY (nullptr);
704 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
706 hb_buffer_t *buffer = c->buffer;
708 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
709 skippy_iter.reset (buffer->idx, count - 1);
710 skippy_iter.set_match_func (match_func, match_data, input);
713 * This is perhaps the trickiest part of OpenType... Remarks:
715 * - If all components of the ligature were marks, we call this a mark ligature.
717 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
718 * it as a ligature glyph.
720 * - Ligatures cannot be formed across glyphs attached to different components
721 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
722 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
723 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
724 * There are a couple of exceptions to this:
726 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
727 * assuming that the font designer knows what they are doing (otherwise it can
728 * break Indic stuff when a matra wants to ligate with a conjunct,
730 * o If two marks want to ligate and they belong to different components of the
731 * same ligature glyph, and said ligature glyph is to be ignored according to
732 * mark-filtering rules, then allow.
733 * https://github.com/harfbuzz/harfbuzz/issues/545
736 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
738 unsigned int total_component_count = 0;
739 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
741 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
742 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
746 LIGBASE_MAY_NOT_SKIP,
748 } ligbase = LIGBASE_NOT_CHECKED;
750 match_positions[0] = buffer->idx;
751 for (unsigned int i = 1; i < count; i++)
753 if (!skippy_iter.next ()) return_trace (false);
755 match_positions[i] = skippy_iter.idx;
757 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
758 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
760 if (first_lig_id && first_lig_comp)
762 /* If first component was attached to a previous ligature component,
763 * all subsequent components should be attached to the same ligature
764 * component, otherwise we shouldn't ligate them... */
765 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
767 /* ...unless, we are attached to a base ligature and that base
768 * ligature is ignorable. */
769 if (ligbase == LIGBASE_NOT_CHECKED)
772 const hb_glyph_info_t *out = buffer->out_info;
773 unsigned int j = buffer->out_len;
774 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
776 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
785 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
786 ligbase = LIGBASE_MAY_SKIP;
788 ligbase = LIGBASE_MAY_NOT_SKIP;
791 if (ligbase == LIGBASE_MAY_NOT_SKIP)
792 return_trace (false);
797 /* If first component was NOT attached to a previous ligature component,
798 * all subsequent components should also NOT be attached to any ligature
799 * component, unless they are attached to the first component itself! */
800 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
801 return_trace (false);
804 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
805 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
808 *end_offset = skippy_iter.idx - buffer->idx + 1;
810 if (p_is_mark_ligature)
811 *p_is_mark_ligature = is_mark_ligature;
813 if (p_total_component_count)
814 *p_total_component_count = total_component_count;
818 static inline bool ligate_input (hb_ot_apply_context_t *c,
819 unsigned int count, /* Including the first glyph */
820 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
821 unsigned int match_length,
822 hb_codepoint_t lig_glyph,
823 bool is_mark_ligature,
824 unsigned int total_component_count)
826 TRACE_APPLY (nullptr);
828 hb_buffer_t *buffer = c->buffer;
830 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
833 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
834 * the ligature to keep its old ligature id. This will allow it to attach to
835 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
836 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
837 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
838 * later, we don't want them to lose their ligature id/component, otherwise
839 * GPOS will fail to correctly position the mark ligature on top of the
840 * LAM,LAM,HEH ligature. See:
841 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
843 * - If a ligature is formed of components that some of which are also ligatures
844 * themselves, and those ligature components had marks attached to *their*
845 * components, we have to attach the marks to the new ligature component
846 * positions! Now *that*'s tricky! And these marks may be following the
847 * last component of the whole sequence, so we should loop forward looking
848 * for them and update them.
850 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
851 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
852 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
853 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
854 * the new ligature with a component value of 2.
856 * This in fact happened to a font... See:
857 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
860 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
861 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
862 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
863 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
864 unsigned int components_so_far = last_num_components;
866 if (!is_mark_ligature)
868 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
869 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
871 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
874 c->replace_glyph_with_ligature (lig_glyph, klass);
876 for (unsigned int i = 1; i < count; i++)
878 while (buffer->idx < match_positions[i] && buffer->successful)
880 if (!is_mark_ligature) {
881 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
883 this_comp = last_num_components;
884 unsigned int new_lig_comp = components_so_far - last_num_components +
885 MIN (this_comp, last_num_components);
886 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
888 buffer->next_glyph ();
891 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
892 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
893 components_so_far += last_num_components;
895 /* Skip the base glyph */
899 if (!is_mark_ligature && last_lig_id) {
900 /* Re-adjust components for any marks following. */
901 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
902 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
903 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
906 unsigned int new_lig_comp = components_so_far - last_num_components +
907 MIN (this_comp, last_num_components);
908 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
916 static inline bool match_backtrack (hb_ot_apply_context_t *c,
918 const HBUINT16 backtrack[],
919 match_func_t match_func,
920 const void *match_data,
921 unsigned int *match_start)
923 TRACE_APPLY (nullptr);
925 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
926 skippy_iter.reset (c->buffer->backtrack_len (), count);
927 skippy_iter.set_match_func (match_func, match_data, backtrack);
929 for (unsigned int i = 0; i < count; i++)
930 if (!skippy_iter.prev ())
931 return_trace (false);
933 *match_start = skippy_iter.idx;
938 static inline bool match_lookahead (hb_ot_apply_context_t *c,
940 const HBUINT16 lookahead[],
941 match_func_t match_func,
942 const void *match_data,
944 unsigned int *end_index)
946 TRACE_APPLY (nullptr);
948 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
949 skippy_iter.reset (c->buffer->idx + offset - 1, count);
950 skippy_iter.set_match_func (match_func, match_data, lookahead);
952 for (unsigned int i = 0; i < count; i++)
953 if (!skippy_iter.next ())
954 return_trace (false);
956 *end_index = skippy_iter.idx + 1;
965 inline bool sanitize (hb_sanitize_context_t *c) const
967 TRACE_SANITIZE (this);
968 return_trace (c->check_struct (this));
971 HBUINT16 sequenceIndex; /* Index into current glyph
972 * sequence--first glyph = 0 */
973 HBUINT16 lookupListIndex; /* Lookup to apply to that
974 * position--zero--based */
976 DEFINE_SIZE_STATIC (4);
980 template <typename context_t>
981 static inline void recurse_lookups (context_t *c,
982 unsigned int lookupCount,
983 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
985 for (unsigned int i = 0; i < lookupCount; i++)
986 c->recurse (lookupRecord[i].lookupListIndex);
989 static inline bool apply_lookup (hb_ot_apply_context_t *c,
990 unsigned int count, /* Including the first glyph */
991 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
992 unsigned int lookupCount,
993 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
994 unsigned int match_length)
996 TRACE_APPLY (nullptr);
998 hb_buffer_t *buffer = c->buffer;
1001 /* All positions are distance from beginning of *output* buffer.
1004 unsigned int bl = buffer->backtrack_len ();
1005 end = bl + match_length;
1007 int delta = bl - buffer->idx;
1008 /* Convert positions to new indexing. */
1009 for (unsigned int j = 0; j < count; j++)
1010 match_positions[j] += delta;
1013 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
1015 unsigned int idx = lookupRecord[i].sequenceIndex;
1019 /* Don't recurse to ourself at same position.
1020 * Note that this test is too naive, it doesn't catch longer loops. */
1021 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1024 if (unlikely (!buffer->move_to (match_positions[idx])))
1027 if (unlikely (buffer->max_ops <= 0))
1030 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1031 if (!c->recurse (lookupRecord[i].lookupListIndex))
1034 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1035 int delta = new_len - orig_len;
1040 /* Recursed lookup changed buffer len. Adjust.
1044 * Right now, if buffer length increased by n, we assume n new glyphs
1045 * were added right after the current position, and if buffer length
1046 * was decreased by n, we assume n match positions after the current
1047 * one where removed. The former (buffer length increased) case is
1048 * fine, but the decrease case can be improved in at least two ways,
1049 * both of which are significant:
1051 * - If recursed-to lookup is MultipleSubst and buffer length
1052 * decreased, then it's current match position that was deleted,
1053 * NOT the one after it.
1055 * - If buffer length was decreased by n, it does not necessarily
1056 * mean that n match positions where removed, as there might
1057 * have been marks and default-ignorables in the sequence. We
1058 * should instead drop match positions between current-position
1059 * and current-position + n instead.
1061 * It should be possible to construct tests for both of these cases.
1065 if (end <= int (match_positions[idx]))
1067 /* End might end up being smaller than match_positions[idx] if the recursed
1068 * lookup ended up removing many items, more than we have had matched.
1069 * Just never rewind end back and get out of here.
1070 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1071 end = match_positions[idx];
1072 /* There can't be any further changes. */
1076 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1080 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1085 /* NOTE: delta is negative. */
1086 delta = MAX (delta, (int) next - (int) count);
1091 memmove (match_positions + next + delta, match_positions + next,
1092 (count - next) * sizeof (match_positions[0]));
1096 /* Fill in new entries. */
1097 for (unsigned int j = idx + 1; j < next; j++)
1098 match_positions[j] = match_positions[j - 1] + 1;
1100 /* And fixup the rest. */
1101 for (; next < count; next++)
1102 match_positions[next] += delta;
1105 buffer->move_to (end);
1107 return_trace (true);
1112 /* Contextual lookups */
1114 struct ContextClosureLookupContext
1116 ContextClosureFuncs funcs;
1117 const void *intersects_data;
1120 struct ContextCollectGlyphsLookupContext
1122 ContextCollectGlyphsFuncs funcs;
1123 const void *collect_data;
1126 struct ContextApplyLookupContext
1128 ContextApplyFuncs funcs;
1129 const void *match_data;
1132 static inline void context_closure_lookup (hb_closure_context_t *c,
1133 unsigned int inputCount, /* Including the first glyph (not matched) */
1134 const HBUINT16 input[], /* Array of input values--start with second glyph */
1135 unsigned int lookupCount,
1136 const LookupRecord lookupRecord[],
1137 ContextClosureLookupContext &lookup_context)
1139 if (intersects_array (c,
1140 inputCount ? inputCount - 1 : 0, input,
1141 lookup_context.funcs.intersects, lookup_context.intersects_data))
1143 lookupCount, lookupRecord);
1146 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1147 unsigned int inputCount, /* Including the first glyph (not matched) */
1148 const HBUINT16 input[], /* Array of input values--start with second glyph */
1149 unsigned int lookupCount,
1150 const LookupRecord lookupRecord[],
1151 ContextCollectGlyphsLookupContext &lookup_context)
1153 collect_array (c, c->input,
1154 inputCount ? inputCount - 1 : 0, input,
1155 lookup_context.funcs.collect, lookup_context.collect_data);
1157 lookupCount, lookupRecord);
1160 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1161 unsigned int inputCount, /* Including the first glyph (not matched) */
1162 const HBUINT16 input[], /* Array of input values--start with second glyph */
1163 unsigned int lookupCount HB_UNUSED,
1164 const LookupRecord lookupRecord[] HB_UNUSED,
1165 ContextApplyLookupContext &lookup_context)
1167 return would_match_input (c,
1169 lookup_context.funcs.match, lookup_context.match_data);
1171 static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
1172 unsigned int inputCount, /* Including the first glyph (not matched) */
1173 const HBUINT16 input[], /* Array of input values--start with second glyph */
1174 unsigned int lookupCount,
1175 const LookupRecord lookupRecord[],
1176 ContextApplyLookupContext &lookup_context)
1178 unsigned int match_length = 0;
1179 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1180 return match_input (c,
1182 lookup_context.funcs.match, lookup_context.match_data,
1183 &match_length, match_positions)
1184 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1186 inputCount, match_positions,
1187 lookupCount, lookupRecord,
1193 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1195 TRACE_CLOSURE (this);
1196 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1197 context_closure_lookup (c,
1199 lookupCount, lookupRecord,
1203 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1205 TRACE_COLLECT_GLYPHS (this);
1206 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1207 context_collect_glyphs_lookup (c,
1209 lookupCount, lookupRecord,
1213 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1215 TRACE_WOULD_APPLY (this);
1216 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1217 return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
1220 inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1223 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1224 return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
1228 inline bool sanitize (hb_sanitize_context_t *c) const
1230 TRACE_SANITIZE (this);
1231 return_trace (inputCount.sanitize (c) &&
1232 lookupCount.sanitize (c) &&
1233 c->check_range (inputZ,
1234 inputZ[0].static_size * inputCount +
1235 LookupRecord::static_size * lookupCount));
1239 HBUINT16 inputCount; /* Total number of glyphs in input
1240 * glyph sequence--includes the first
1242 HBUINT16 lookupCount; /* Number of LookupRecords */
1243 HBUINT16 inputZ[VAR]; /* Array of match inputs--start with
1245 /*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in
1248 DEFINE_SIZE_ARRAY (4, inputZ);
1253 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1255 TRACE_CLOSURE (this);
1256 unsigned int num_rules = rule.len;
1257 for (unsigned int i = 0; i < num_rules; i++)
1258 (this+rule[i]).closure (c, lookup_context);
1261 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1263 TRACE_COLLECT_GLYPHS (this);
1264 unsigned int num_rules = rule.len;
1265 for (unsigned int i = 0; i < num_rules; i++)
1266 (this+rule[i]).collect_glyphs (c, lookup_context);
1269 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1271 TRACE_WOULD_APPLY (this);
1272 unsigned int num_rules = rule.len;
1273 for (unsigned int i = 0; i < num_rules; i++)
1275 if ((this+rule[i]).would_apply (c, lookup_context))
1276 return_trace (true);
1278 return_trace (false);
1281 inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1284 unsigned int num_rules = rule.len;
1285 for (unsigned int i = 0; i < num_rules; i++)
1287 if ((this+rule[i]).apply (c, lookup_context))
1288 return_trace (true);
1290 return_trace (false);
1293 inline bool sanitize (hb_sanitize_context_t *c) const
1295 TRACE_SANITIZE (this);
1296 return_trace (rule.sanitize (c, this));
1301 rule; /* Array of Rule tables
1302 * ordered by preference */
1304 DEFINE_SIZE_ARRAY (2, rule);
1308 struct ContextFormat1
1310 inline void closure (hb_closure_context_t *c) const
1312 TRACE_CLOSURE (this);
1314 const Coverage &cov = (this+coverage);
1316 struct ContextClosureLookupContext lookup_context = {
1321 unsigned int count = ruleSet.len;
1322 for (unsigned int i = 0; i < count; i++)
1323 if (cov.intersects_coverage (c->glyphs, i)) {
1324 const RuleSet &rule_set = this+ruleSet[i];
1325 rule_set.closure (c, lookup_context);
1329 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1331 TRACE_COLLECT_GLYPHS (this);
1332 (this+coverage).add_coverage (c->input);
1334 struct ContextCollectGlyphsLookupContext lookup_context = {
1339 unsigned int count = ruleSet.len;
1340 for (unsigned int i = 0; i < count; i++)
1341 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1344 inline bool would_apply (hb_would_apply_context_t *c) const
1346 TRACE_WOULD_APPLY (this);
1348 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1349 struct ContextApplyLookupContext lookup_context = {
1353 return_trace (rule_set.would_apply (c, lookup_context));
1356 inline const Coverage &get_coverage (void) const
1358 return this+coverage;
1361 inline bool apply (hb_ot_apply_context_t *c) const
1364 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1365 if (likely (index == NOT_COVERED))
1366 return_trace (false);
1368 const RuleSet &rule_set = this+ruleSet[index];
1369 struct ContextApplyLookupContext lookup_context = {
1373 return_trace (rule_set.apply (c, lookup_context));
1376 inline bool sanitize (hb_sanitize_context_t *c) const
1378 TRACE_SANITIZE (this);
1379 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1383 HBUINT16 format; /* Format identifier--format = 1 */
1385 coverage; /* Offset to Coverage table--from
1386 * beginning of table */
1387 OffsetArrayOf<RuleSet>
1388 ruleSet; /* Array of RuleSet tables
1389 * ordered by Coverage Index */
1391 DEFINE_SIZE_ARRAY (6, ruleSet);
1395 struct ContextFormat2
1397 inline void closure (hb_closure_context_t *c) const
1399 TRACE_CLOSURE (this);
1400 if (!(this+coverage).intersects (c->glyphs))
1403 const ClassDef &class_def = this+classDef;
1405 struct ContextClosureLookupContext lookup_context = {
1410 unsigned int count = ruleSet.len;
1411 for (unsigned int i = 0; i < count; i++)
1412 if (class_def.intersects_class (c->glyphs, i)) {
1413 const RuleSet &rule_set = this+ruleSet[i];
1414 rule_set.closure (c, lookup_context);
1418 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1420 TRACE_COLLECT_GLYPHS (this);
1421 (this+coverage).add_coverage (c->input);
1423 const ClassDef &class_def = this+classDef;
1424 struct ContextCollectGlyphsLookupContext lookup_context = {
1429 unsigned int count = ruleSet.len;
1430 for (unsigned int i = 0; i < count; i++)
1431 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1434 inline bool would_apply (hb_would_apply_context_t *c) const
1436 TRACE_WOULD_APPLY (this);
1438 const ClassDef &class_def = this+classDef;
1439 unsigned int index = class_def.get_class (c->glyphs[0]);
1440 const RuleSet &rule_set = this+ruleSet[index];
1441 struct ContextApplyLookupContext lookup_context = {
1445 return_trace (rule_set.would_apply (c, lookup_context));
1448 inline const Coverage &get_coverage (void) const
1450 return this+coverage;
1453 inline bool apply (hb_ot_apply_context_t *c) const
1456 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1457 if (likely (index == NOT_COVERED)) return_trace (false);
1459 const ClassDef &class_def = this+classDef;
1460 index = class_def.get_class (c->buffer->cur().codepoint);
1461 const RuleSet &rule_set = this+ruleSet[index];
1462 struct ContextApplyLookupContext lookup_context = {
1466 return_trace (rule_set.apply (c, lookup_context));
1469 inline bool sanitize (hb_sanitize_context_t *c) const
1471 TRACE_SANITIZE (this);
1472 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
1476 HBUINT16 format; /* Format identifier--format = 2 */
1478 coverage; /* Offset to Coverage table--from
1479 * beginning of table */
1481 classDef; /* Offset to glyph ClassDef table--from
1482 * beginning of table */
1483 OffsetArrayOf<RuleSet>
1484 ruleSet; /* Array of RuleSet tables
1485 * ordered by class */
1487 DEFINE_SIZE_ARRAY (8, ruleSet);
1491 struct ContextFormat3
1493 inline void closure (hb_closure_context_t *c) const
1495 TRACE_CLOSURE (this);
1496 if (!(this+coverageZ[0]).intersects (c->glyphs))
1499 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1500 struct ContextClosureLookupContext lookup_context = {
1501 {intersects_coverage},
1504 context_closure_lookup (c,
1505 glyphCount, (const HBUINT16 *) (coverageZ + 1),
1506 lookupCount, lookupRecord,
1510 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1512 TRACE_COLLECT_GLYPHS (this);
1513 (this+coverageZ[0]).add_coverage (c->input);
1515 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1516 struct ContextCollectGlyphsLookupContext lookup_context = {
1521 context_collect_glyphs_lookup (c,
1522 glyphCount, (const HBUINT16 *) (coverageZ + 1),
1523 lookupCount, lookupRecord,
1527 inline bool would_apply (hb_would_apply_context_t *c) const
1529 TRACE_WOULD_APPLY (this);
1531 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1532 struct ContextApplyLookupContext lookup_context = {
1536 return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
1539 inline const Coverage &get_coverage (void) const
1541 return this+coverageZ[0];
1544 inline bool apply (hb_ot_apply_context_t *c) const
1547 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
1548 if (likely (index == NOT_COVERED)) return_trace (false);
1550 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1551 struct ContextApplyLookupContext lookup_context = {
1555 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
1558 inline bool sanitize (hb_sanitize_context_t *c) const
1560 TRACE_SANITIZE (this);
1561 if (!c->check_struct (this)) return_trace (false);
1562 unsigned int count = glyphCount;
1563 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1564 if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
1565 for (unsigned int i = 0; i < count; i++)
1566 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
1567 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
1568 return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
1572 HBUINT16 format; /* Format identifier--format = 3 */
1573 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
1575 HBUINT16 lookupCount; /* Number of LookupRecords */
1577 coverageZ[VAR]; /* Array of offsets to Coverage
1578 * table in glyph sequence order */
1579 /*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in
1582 DEFINE_SIZE_ARRAY (6, coverageZ);
1587 template <typename context_t>
1588 inline typename context_t::return_t dispatch (context_t *c) const
1590 TRACE_DISPATCH (this, u.format);
1591 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1593 case 1: return_trace (c->dispatch (u.format1));
1594 case 2: return_trace (c->dispatch (u.format2));
1595 case 3: return_trace (c->dispatch (u.format3));
1596 default:return_trace (c->default_return_value ());
1602 HBUINT16 format; /* Format identifier */
1603 ContextFormat1 format1;
1604 ContextFormat2 format2;
1605 ContextFormat3 format3;
1610 /* Chaining Contextual lookups */
1612 struct ChainContextClosureLookupContext
1614 ContextClosureFuncs funcs;
1615 const void *intersects_data[3];
1618 struct ChainContextCollectGlyphsLookupContext
1620 ContextCollectGlyphsFuncs funcs;
1621 const void *collect_data[3];
1624 struct ChainContextApplyLookupContext
1626 ContextApplyFuncs funcs;
1627 const void *match_data[3];
1630 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1631 unsigned int backtrackCount,
1632 const HBUINT16 backtrack[],
1633 unsigned int inputCount, /* Including the first glyph (not matched) */
1634 const HBUINT16 input[], /* Array of input values--start with second glyph */
1635 unsigned int lookaheadCount,
1636 const HBUINT16 lookahead[],
1637 unsigned int lookupCount,
1638 const LookupRecord lookupRecord[],
1639 ChainContextClosureLookupContext &lookup_context)
1641 if (intersects_array (c,
1642 backtrackCount, backtrack,
1643 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1644 && intersects_array (c,
1645 inputCount ? inputCount - 1 : 0, input,
1646 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1647 && intersects_array (c,
1648 lookaheadCount, lookahead,
1649 lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
1651 lookupCount, lookupRecord);
1654 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1655 unsigned int backtrackCount,
1656 const HBUINT16 backtrack[],
1657 unsigned int inputCount, /* Including the first glyph (not matched) */
1658 const HBUINT16 input[], /* Array of input values--start with second glyph */
1659 unsigned int lookaheadCount,
1660 const HBUINT16 lookahead[],
1661 unsigned int lookupCount,
1662 const LookupRecord lookupRecord[],
1663 ChainContextCollectGlyphsLookupContext &lookup_context)
1665 collect_array (c, c->before,
1666 backtrackCount, backtrack,
1667 lookup_context.funcs.collect, lookup_context.collect_data[0]);
1668 collect_array (c, c->input,
1669 inputCount ? inputCount - 1 : 0, input,
1670 lookup_context.funcs.collect, lookup_context.collect_data[1]);
1671 collect_array (c, c->after,
1672 lookaheadCount, lookahead,
1673 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1675 lookupCount, lookupRecord);
1678 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1679 unsigned int backtrackCount,
1680 const HBUINT16 backtrack[] HB_UNUSED,
1681 unsigned int inputCount, /* Including the first glyph (not matched) */
1682 const HBUINT16 input[], /* Array of input values--start with second glyph */
1683 unsigned int lookaheadCount,
1684 const HBUINT16 lookahead[] HB_UNUSED,
1685 unsigned int lookupCount HB_UNUSED,
1686 const LookupRecord lookupRecord[] HB_UNUSED,
1687 ChainContextApplyLookupContext &lookup_context)
1689 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1690 && would_match_input (c,
1692 lookup_context.funcs.match, lookup_context.match_data[1]);
1695 static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
1696 unsigned int backtrackCount,
1697 const HBUINT16 backtrack[],
1698 unsigned int inputCount, /* Including the first glyph (not matched) */
1699 const HBUINT16 input[], /* Array of input values--start with second glyph */
1700 unsigned int lookaheadCount,
1701 const HBUINT16 lookahead[],
1702 unsigned int lookupCount,
1703 const LookupRecord lookupRecord[],
1704 ChainContextApplyLookupContext &lookup_context)
1706 unsigned int start_index = 0, match_length = 0, end_index = 0;
1707 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1708 return match_input (c,
1710 lookup_context.funcs.match, lookup_context.match_data[1],
1711 &match_length, match_positions)
1712 && match_backtrack (c,
1713 backtrackCount, backtrack,
1714 lookup_context.funcs.match, lookup_context.match_data[0],
1716 && match_lookahead (c,
1717 lookaheadCount, lookahead,
1718 lookup_context.funcs.match, lookup_context.match_data[2],
1719 match_length, &end_index)
1720 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1722 inputCount, match_positions,
1723 lookupCount, lookupRecord,
1729 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1731 TRACE_CLOSURE (this);
1732 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1733 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1734 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1735 chain_context_closure_lookup (c,
1736 backtrack.len, backtrack.arrayZ,
1737 input.len, input.arrayZ,
1738 lookahead.len, lookahead.arrayZ,
1739 lookup.len, lookup.arrayZ,
1743 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1745 TRACE_COLLECT_GLYPHS (this);
1746 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1747 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1748 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1749 chain_context_collect_glyphs_lookup (c,
1750 backtrack.len, backtrack.arrayZ,
1751 input.len, input.arrayZ,
1752 lookahead.len, lookahead.arrayZ,
1753 lookup.len, lookup.arrayZ,
1757 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1759 TRACE_WOULD_APPLY (this);
1760 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1761 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1762 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1763 return_trace (chain_context_would_apply_lookup (c,
1764 backtrack.len, backtrack.arrayZ,
1765 input.len, input.arrayZ,
1766 lookahead.len, lookahead.arrayZ, lookup.len,
1767 lookup.arrayZ, lookup_context));
1770 inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1773 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1774 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1775 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1776 return_trace (chain_context_apply_lookup (c,
1777 backtrack.len, backtrack.arrayZ,
1778 input.len, input.arrayZ,
1779 lookahead.len, lookahead.arrayZ, lookup.len,
1780 lookup.arrayZ, lookup_context));
1783 inline bool sanitize (hb_sanitize_context_t *c) const
1785 TRACE_SANITIZE (this);
1786 if (!backtrack.sanitize (c)) return_trace (false);
1787 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1788 if (!input.sanitize (c)) return_trace (false);
1789 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1790 if (!lookahead.sanitize (c)) return_trace (false);
1791 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1792 return_trace (lookup.sanitize (c));
1797 backtrack; /* Array of backtracking values
1798 * (to be matched before the input
1800 HeadlessArrayOf<HBUINT16>
1801 inputX; /* Array of input values (start with
1804 lookaheadX; /* Array of lookahead values's (to be
1805 * matched after the input sequence) */
1806 ArrayOf<LookupRecord>
1807 lookupX; /* Array of LookupRecords--in
1810 DEFINE_SIZE_MIN (8);
1815 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1817 TRACE_CLOSURE (this);
1818 unsigned int num_rules = rule.len;
1819 for (unsigned int i = 0; i < num_rules; i++)
1820 (this+rule[i]).closure (c, lookup_context);
1823 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1825 TRACE_COLLECT_GLYPHS (this);
1826 unsigned int num_rules = rule.len;
1827 for (unsigned int i = 0; i < num_rules; i++)
1828 (this+rule[i]).collect_glyphs (c, lookup_context);
1831 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1833 TRACE_WOULD_APPLY (this);
1834 unsigned int num_rules = rule.len;
1835 for (unsigned int i = 0; i < num_rules; i++)
1836 if ((this+rule[i]).would_apply (c, lookup_context))
1837 return_trace (true);
1839 return_trace (false);
1842 inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1845 unsigned int num_rules = rule.len;
1846 for (unsigned int i = 0; i < num_rules; i++)
1847 if ((this+rule[i]).apply (c, lookup_context))
1848 return_trace (true);
1850 return_trace (false);
1853 inline bool sanitize (hb_sanitize_context_t *c) const
1855 TRACE_SANITIZE (this);
1856 return_trace (rule.sanitize (c, this));
1860 OffsetArrayOf<ChainRule>
1861 rule; /* Array of ChainRule tables
1862 * ordered by preference */
1864 DEFINE_SIZE_ARRAY (2, rule);
1867 struct ChainContextFormat1
1869 inline void closure (hb_closure_context_t *c) const
1871 TRACE_CLOSURE (this);
1872 const Coverage &cov = (this+coverage);
1874 struct ChainContextClosureLookupContext lookup_context = {
1876 {nullptr, nullptr, nullptr}
1879 unsigned int count = ruleSet.len;
1880 for (unsigned int i = 0; i < count; i++)
1881 if (cov.intersects_coverage (c->glyphs, i)) {
1882 const ChainRuleSet &rule_set = this+ruleSet[i];
1883 rule_set.closure (c, lookup_context);
1887 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1889 TRACE_COLLECT_GLYPHS (this);
1890 (this+coverage).add_coverage (c->input);
1892 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1894 {nullptr, nullptr, nullptr}
1897 unsigned int count = ruleSet.len;
1898 for (unsigned int i = 0; i < count; i++)
1899 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1902 inline bool would_apply (hb_would_apply_context_t *c) const
1904 TRACE_WOULD_APPLY (this);
1906 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1907 struct ChainContextApplyLookupContext lookup_context = {
1909 {nullptr, nullptr, nullptr}
1911 return_trace (rule_set.would_apply (c, lookup_context));
1914 inline const Coverage &get_coverage (void) const
1916 return this+coverage;
1919 inline bool apply (hb_ot_apply_context_t *c) const
1922 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1923 if (likely (index == NOT_COVERED)) return_trace (false);
1925 const ChainRuleSet &rule_set = this+ruleSet[index];
1926 struct ChainContextApplyLookupContext lookup_context = {
1928 {nullptr, nullptr, nullptr}
1930 return_trace (rule_set.apply (c, lookup_context));
1933 inline bool sanitize (hb_sanitize_context_t *c) const
1935 TRACE_SANITIZE (this);
1936 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1940 HBUINT16 format; /* Format identifier--format = 1 */
1942 coverage; /* Offset to Coverage table--from
1943 * beginning of table */
1944 OffsetArrayOf<ChainRuleSet>
1945 ruleSet; /* Array of ChainRuleSet tables
1946 * ordered by Coverage Index */
1948 DEFINE_SIZE_ARRAY (6, ruleSet);
1951 struct ChainContextFormat2
1953 inline void closure (hb_closure_context_t *c) const
1955 TRACE_CLOSURE (this);
1956 if (!(this+coverage).intersects (c->glyphs))
1959 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1960 const ClassDef &input_class_def = this+inputClassDef;
1961 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1963 struct ChainContextClosureLookupContext lookup_context = {
1965 {&backtrack_class_def,
1967 &lookahead_class_def}
1970 unsigned int count = ruleSet.len;
1971 for (unsigned int i = 0; i < count; i++)
1972 if (input_class_def.intersects_class (c->glyphs, i)) {
1973 const ChainRuleSet &rule_set = this+ruleSet[i];
1974 rule_set.closure (c, lookup_context);
1978 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1980 TRACE_COLLECT_GLYPHS (this);
1981 (this+coverage).add_coverage (c->input);
1983 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1984 const ClassDef &input_class_def = this+inputClassDef;
1985 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1987 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1989 {&backtrack_class_def,
1991 &lookahead_class_def}
1994 unsigned int count = ruleSet.len;
1995 for (unsigned int i = 0; i < count; i++)
1996 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1999 inline bool would_apply (hb_would_apply_context_t *c) const
2001 TRACE_WOULD_APPLY (this);
2003 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2004 const ClassDef &input_class_def = this+inputClassDef;
2005 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2007 unsigned int index = input_class_def.get_class (c->glyphs[0]);
2008 const ChainRuleSet &rule_set = this+ruleSet[index];
2009 struct ChainContextApplyLookupContext lookup_context = {
2011 {&backtrack_class_def,
2013 &lookahead_class_def}
2015 return_trace (rule_set.would_apply (c, lookup_context));
2018 inline const Coverage &get_coverage (void) const
2020 return this+coverage;
2023 inline bool apply (hb_ot_apply_context_t *c) const
2026 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2027 if (likely (index == NOT_COVERED)) return_trace (false);
2029 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2030 const ClassDef &input_class_def = this+inputClassDef;
2031 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2033 index = input_class_def.get_class (c->buffer->cur().codepoint);
2034 const ChainRuleSet &rule_set = this+ruleSet[index];
2035 struct ChainContextApplyLookupContext lookup_context = {
2037 {&backtrack_class_def,
2039 &lookahead_class_def}
2041 return_trace (rule_set.apply (c, lookup_context));
2044 inline bool sanitize (hb_sanitize_context_t *c) const
2046 TRACE_SANITIZE (this);
2047 return_trace (coverage.sanitize (c, this) &&
2048 backtrackClassDef.sanitize (c, this) &&
2049 inputClassDef.sanitize (c, this) &&
2050 lookaheadClassDef.sanitize (c, this) &&
2051 ruleSet.sanitize (c, this));
2055 HBUINT16 format; /* Format identifier--format = 2 */
2057 coverage; /* Offset to Coverage table--from
2058 * beginning of table */
2060 backtrackClassDef; /* Offset to glyph ClassDef table
2061 * containing backtrack sequence
2062 * data--from beginning of table */
2064 inputClassDef; /* Offset to glyph ClassDef
2065 * table containing input sequence
2066 * data--from beginning of table */
2068 lookaheadClassDef; /* Offset to glyph ClassDef table
2069 * containing lookahead sequence
2070 * data--from beginning of table */
2071 OffsetArrayOf<ChainRuleSet>
2072 ruleSet; /* Array of ChainRuleSet tables
2073 * ordered by class */
2075 DEFINE_SIZE_ARRAY (12, ruleSet);
2078 struct ChainContextFormat3
2080 inline void closure (hb_closure_context_t *c) const
2082 TRACE_CLOSURE (this);
2083 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2085 if (!(this+input[0]).intersects (c->glyphs))
2088 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2089 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2090 struct ChainContextClosureLookupContext lookup_context = {
2091 {intersects_coverage},
2094 chain_context_closure_lookup (c,
2095 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2096 input.len, (const HBUINT16 *) input.arrayZ + 1,
2097 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2098 lookup.len, lookup.arrayZ,
2102 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2104 TRACE_COLLECT_GLYPHS (this);
2105 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2107 (this+input[0]).add_coverage (c->input);
2109 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2110 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2111 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2115 chain_context_collect_glyphs_lookup (c,
2116 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2117 input.len, (const HBUINT16 *) input.arrayZ + 1,
2118 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2119 lookup.len, lookup.arrayZ,
2123 inline bool would_apply (hb_would_apply_context_t *c) const
2125 TRACE_WOULD_APPLY (this);
2127 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2128 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2129 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2130 struct ChainContextApplyLookupContext lookup_context = {
2134 return_trace (chain_context_would_apply_lookup (c,
2135 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2136 input.len, (const HBUINT16 *) input.arrayZ + 1,
2137 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2138 lookup.len, lookup.arrayZ, lookup_context));
2141 inline const Coverage &get_coverage (void) const
2143 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2144 return this+input[0];
2147 inline bool apply (hb_ot_apply_context_t *c) const
2150 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2152 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2153 if (likely (index == NOT_COVERED)) return_trace (false);
2155 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2156 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2157 struct ChainContextApplyLookupContext lookup_context = {
2161 return_trace (chain_context_apply_lookup (c,
2162 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2163 input.len, (const HBUINT16 *) input.arrayZ + 1,
2164 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2165 lookup.len, lookup.arrayZ, lookup_context));
2168 inline bool sanitize (hb_sanitize_context_t *c) const
2170 TRACE_SANITIZE (this);
2171 if (!backtrack.sanitize (c, this)) return_trace (false);
2172 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2173 if (!input.sanitize (c, this)) return_trace (false);
2174 if (!input.len) return_trace (false); /* To be consistent with Context. */
2175 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2176 if (!lookahead.sanitize (c, this)) return_trace (false);
2177 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2178 return_trace (lookup.sanitize (c));
2182 HBUINT16 format; /* Format identifier--format = 3 */
2183 OffsetArrayOf<Coverage>
2184 backtrack; /* Array of coverage tables
2185 * in backtracking sequence, in glyph
2187 OffsetArrayOf<Coverage>
2188 inputX ; /* Array of coverage
2189 * tables in input sequence, in glyph
2191 OffsetArrayOf<Coverage>
2192 lookaheadX; /* Array of coverage tables
2193 * in lookahead sequence, in glyph
2195 ArrayOf<LookupRecord>
2196 lookupX; /* Array of LookupRecords--in
2199 DEFINE_SIZE_MIN (10);
2204 template <typename context_t>
2205 inline typename context_t::return_t dispatch (context_t *c) const
2207 TRACE_DISPATCH (this, u.format);
2208 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2210 case 1: return_trace (c->dispatch (u.format1));
2211 case 2: return_trace (c->dispatch (u.format2));
2212 case 3: return_trace (c->dispatch (u.format3));
2213 default:return_trace (c->default_return_value ());
2219 HBUINT16 format; /* Format identifier */
2220 ChainContextFormat1 format1;
2221 ChainContextFormat2 format2;
2222 ChainContextFormat3 format3;
2227 template <typename T>
2228 struct ExtensionFormat1
2230 inline unsigned int get_type (void) const { return extensionLookupType; }
2232 template <typename X>
2233 inline const X& get_subtable (void) const
2235 unsigned int offset = extensionOffset;
2236 if (unlikely (!offset)) return Null(typename T::LookupSubTable);
2237 return StructAtOffset<typename T::LookupSubTable> (this, offset);
2240 template <typename context_t>
2241 inline typename context_t::return_t dispatch (context_t *c) const
2243 TRACE_DISPATCH (this, format);
2244 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
2245 return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
2248 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
2249 inline bool sanitize (hb_sanitize_context_t *c) const
2251 TRACE_SANITIZE (this);
2252 return_trace (c->check_struct (this) &&
2253 extensionOffset != 0 &&
2254 extensionLookupType != T::LookupSubTable::Extension);
2258 HBUINT16 format; /* Format identifier. Set to 1. */
2259 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
2260 * by ExtensionOffset (i.e. the
2261 * extension subtable). */
2262 HBUINT32 extensionOffset; /* Offset to the extension subtable,
2263 * of lookup type subtable. */
2265 DEFINE_SIZE_STATIC (8);
2268 template <typename T>
2271 inline unsigned int get_type (void) const
2274 case 1: return u.format1.get_type ();
2278 template <typename X>
2279 inline const X& get_subtable (void) const
2282 case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
2283 default:return Null(typename T::LookupSubTable);
2287 template <typename context_t>
2288 inline typename context_t::return_t dispatch (context_t *c) const
2290 TRACE_DISPATCH (this, u.format);
2291 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2293 case 1: return_trace (u.format1.dispatch (c));
2294 default:return_trace (c->default_return_value ());
2300 HBUINT16 format; /* Format identifier */
2301 ExtensionFormat1<T> format1;
2312 inline unsigned int get_script_count (void) const
2313 { return (this+scriptList).len; }
2314 inline const Tag& get_script_tag (unsigned int i) const
2315 { return (this+scriptList).get_tag (i); }
2316 inline unsigned int get_script_tags (unsigned int start_offset,
2317 unsigned int *script_count /* IN/OUT */,
2318 hb_tag_t *script_tags /* OUT */) const
2319 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
2320 inline const Script& get_script (unsigned int i) const
2321 { return (this+scriptList)[i]; }
2322 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
2323 { return (this+scriptList).find_index (tag, index); }
2325 inline unsigned int get_feature_count (void) const
2326 { return (this+featureList).len; }
2327 inline hb_tag_t get_feature_tag (unsigned int i) const
2328 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
2329 inline unsigned int get_feature_tags (unsigned int start_offset,
2330 unsigned int *feature_count /* IN/OUT */,
2331 hb_tag_t *feature_tags /* OUT */) const
2332 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
2333 inline const Feature& get_feature (unsigned int i) const
2334 { return (this+featureList)[i]; }
2335 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2336 { return (this+featureList).find_index (tag, index); }
2338 inline unsigned int get_lookup_count (void) const
2339 { return (this+lookupList).len; }
2340 inline const Lookup& get_lookup (unsigned int i) const
2341 { return (this+lookupList)[i]; }
2343 inline bool find_variations_index (const int *coords, unsigned int num_coords,
2344 unsigned int *index) const
2345 { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2346 .find_index (coords, num_coords, index); }
2347 inline const Feature& get_feature_variation (unsigned int feature_index,
2348 unsigned int variations_index) const
2350 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2351 version.to_int () >= 0x00010001u)
2353 const Feature *feature = (this+featureVars).find_substitute (variations_index,
2358 return get_feature (feature_index);
2361 inline bool sanitize (hb_sanitize_context_t *c) const
2363 TRACE_SANITIZE (this);
2364 return_trace (version.sanitize (c) &&
2365 likely (version.major == 1) &&
2366 scriptList.sanitize (c, this) &&
2367 featureList.sanitize (c, this) &&
2368 lookupList.sanitize (c, this) &&
2369 (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
2373 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
2375 OffsetTo<ScriptList>
2376 scriptList; /* ScriptList table */
2377 OffsetTo<FeatureList>
2378 featureList; /* FeatureList table */
2379 OffsetTo<LookupList>
2380 lookupList; /* LookupList table */
2381 LOffsetTo<FeatureVariations>
2382 featureVars; /* Offset to Feature Variations
2383 table--from beginning of table
2384 * (may be NULL). Introduced
2385 * in version 0x00010001. */
2387 DEFINE_SIZE_MIN (10);
2391 } /* namespace OT */
2394 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */