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-ot-layout-gdef-table.hh"
36 #include "hb-set-private.hh"
42 struct hb_closure_context_t :
43 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
45 inline const char *get_name (void) { return "CLOSURE"; }
46 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
48 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
49 static return_t default_return_value (void) { return HB_VOID; }
50 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
51 return_t recurse (unsigned int lookup_index)
53 if (unlikely (nesting_level_left == 0 || !recurse_func))
54 return default_return_value ();
57 recurse_func (this, lookup_index);
64 recurse_func_t recurse_func;
65 unsigned int nesting_level_left;
66 unsigned int debug_depth;
68 hb_closure_context_t (hb_face_t *face_,
70 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
73 recurse_func (nullptr),
74 nesting_level_left (nesting_level_left_),
77 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
81 struct hb_would_apply_context_t :
82 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
84 inline const char *get_name (void) { return "WOULD_APPLY"; }
86 inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
87 static return_t default_return_value (void) { return false; }
88 bool stop_sublookup_iteration (return_t r) const { return r; }
91 const hb_codepoint_t *glyphs;
94 unsigned int debug_depth;
96 hb_would_apply_context_t (hb_face_t *face_,
97 const hb_codepoint_t *glyphs_,
103 zero_context (zero_context_),
108 struct hb_collect_glyphs_context_t :
109 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
111 inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
112 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
113 template <typename T>
114 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
115 static return_t default_return_value (void) { return HB_VOID; }
116 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
117 return_t recurse (unsigned int lookup_index)
119 if (unlikely (nesting_level_left == 0 || !recurse_func))
120 return default_return_value ();
122 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
123 * past the previous check. For GSUB, we only want to collect the output
124 * glyphs in the recursion. If output is not requested, we can go home now.
126 * Note further, that the above is not exactly correct. A recursed lookup
127 * is allowed to match input that is not matched in the context, but that's
128 * not how most fonts are built. It's possible to relax that and recurse
129 * with all sets here if it proves to be an issue.
132 if (output == hb_set_get_empty ())
135 /* Return if new lookup was recursed to before. */
136 if (recursed_lookups->has (lookup_index))
139 hb_set_t *old_before = before;
140 hb_set_t *old_input = input;
141 hb_set_t *old_after = after;
142 before = input = after = hb_set_get_empty ();
144 nesting_level_left--;
145 recurse_func (this, lookup_index);
146 nesting_level_left++;
152 recursed_lookups->add (lookup_index);
162 recurse_func_t recurse_func;
163 hb_set_t *recursed_lookups;
164 unsigned int nesting_level_left;
165 unsigned int debug_depth;
167 hb_collect_glyphs_context_t (hb_face_t *face_,
168 hb_set_t *glyphs_before, /* OUT. May be nullptr */
169 hb_set_t *glyphs_input, /* OUT. May be nullptr */
170 hb_set_t *glyphs_after, /* OUT. May be nullptr */
171 hb_set_t *glyphs_output, /* OUT. May be nullptr */
172 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
174 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
175 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
176 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
177 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
178 recurse_func (nullptr),
179 recursed_lookups (nullptr),
180 nesting_level_left (nesting_level_left_),
183 recursed_lookups = hb_set_create ();
185 ~hb_collect_glyphs_context_t (void)
187 hb_set_destroy (recursed_lookups);
190 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
195 /* XXX Can we remove this? */
197 template <typename set_t>
198 struct hb_add_coverage_context_t :
199 hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
201 inline const char *get_name (void) { return "GET_COVERAGE"; }
202 typedef const Coverage &return_t;
203 template <typename T>
204 inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
205 static return_t default_return_value (void) { return Null(Coverage); }
206 bool stop_sublookup_iteration (return_t r) const
208 r.add_coverage (set);
212 hb_add_coverage_context_t (set_t *set_) :
217 unsigned int debug_depth;
221 struct hb_ot_apply_context_t :
222 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
226 inline matcher_t (void) :
231 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
234 match_func (nullptr),
235 match_data (nullptr) {};
237 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
239 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
240 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
241 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
242 inline void set_mask (hb_mask_t mask_) { mask = mask_; }
243 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; }
244 inline void set_match_func (match_func_t match_func_,
245 const void *match_data_)
246 { match_func = match_func_; match_data = match_data_; }
254 inline may_match_t may_match (const hb_glyph_info_t &info,
255 const HBUINT16 *glyph_data) const
257 if (!(info.mask & mask) ||
258 (syllable && syllable != info.syllable ()))
262 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
274 may_skip (const hb_ot_apply_context_t *c,
275 const hb_glyph_info_t &info) const
277 if (!c->check_glyph_property (&info, lookup_props))
280 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
281 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
282 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
289 unsigned int lookup_props;
294 match_func_t match_func;
295 const void *match_data;
298 struct skipping_iterator_t
300 inline void init (hb_ot_apply_context_t *c_, bool context_match = false)
303 match_glyph_data = nullptr;
304 matcher.set_match_func (nullptr, nullptr);
305 matcher.set_lookup_props (c->lookup_props);
306 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
307 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
308 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
309 matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj));
310 matcher.set_mask (context_match ? -1 : c->lookup_mask);
312 inline void set_lookup_props (unsigned int lookup_props)
314 matcher.set_lookup_props (lookup_props);
316 inline void set_match_func (matcher_t::match_func_t match_func_,
317 const void *match_data_,
318 const HBUINT16 glyph_data[])
320 matcher.set_match_func (match_func_, match_data_);
321 match_glyph_data = glyph_data;
324 inline void reset (unsigned int start_index_,
325 unsigned int num_items_)
328 num_items = num_items_;
329 end = c->buffer->len;
330 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
333 inline void reject (void) { num_items++; match_glyph_data--; }
335 inline matcher_t::may_skip_t
336 may_skip (const hb_glyph_info_t &info) const
338 return matcher.may_skip (c, info);
341 inline bool next (void)
343 assert (num_items > 0);
344 while (idx + num_items < end)
347 const hb_glyph_info_t &info = c->buffer->info[idx];
349 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
350 if (unlikely (skip == matcher_t::SKIP_YES))
353 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
354 if (match == matcher_t::MATCH_YES ||
355 (match == matcher_t::MATCH_MAYBE &&
356 skip == matcher_t::SKIP_NO))
363 if (skip == matcher_t::SKIP_NO)
368 inline bool prev (void)
370 assert (num_items > 0);
371 while (idx >= num_items)
374 const hb_glyph_info_t &info = c->buffer->out_info[idx];
376 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
377 if (unlikely (skip == matcher_t::SKIP_YES))
380 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
381 if (match == matcher_t::MATCH_YES ||
382 (match == matcher_t::MATCH_MAYBE &&
383 skip == matcher_t::SKIP_NO))
390 if (skip == matcher_t::SKIP_NO)
398 hb_ot_apply_context_t *c;
400 const HBUINT16 *match_glyph_data;
402 unsigned int num_items;
407 inline const char *get_name (void) { return "APPLY"; }
408 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
409 template <typename T>
410 inline return_t dispatch (const T &obj) { return obj.apply (this); }
411 static return_t default_return_value (void) { return false; }
412 bool stop_sublookup_iteration (return_t r) const { return r; }
413 return_t recurse (unsigned int sub_lookup_index)
415 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
416 return default_return_value ();
418 nesting_level_left--;
419 bool ret = recurse_func (this, sub_lookup_index);
420 nesting_level_left++;
424 skipping_iterator_t iter_input, iter_context;
429 recurse_func_t recurse_func;
431 const VariationStore &var_store;
433 hb_direction_t direction;
434 hb_mask_t lookup_mask;
435 unsigned int table_index; /* GSUB/GPOS */
436 unsigned int lookup_index;
437 unsigned int lookup_props;
438 unsigned int nesting_level_left;
439 unsigned int debug_depth;
443 bool has_glyph_classes;
446 hb_ot_apply_context_t (unsigned int table_index_,
448 hb_buffer_t *buffer_) :
449 iter_input (), iter_context (),
450 font (font_), face (font->face), buffer (buffer_),
451 recurse_func (nullptr),
452 gdef (*hb_ot_layout_from_face (face)->gdef),
453 var_store (gdef.get_var_store ()),
454 direction (buffer_->props.direction),
456 table_index (table_index_),
457 lookup_index ((unsigned int) -1),
459 nesting_level_left (HB_MAX_NESTING_LEVEL),
463 has_glyph_classes (gdef.has_glyph_classes ()) {}
465 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
466 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
467 inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
468 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
469 inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
470 inline void set_lookup_props (unsigned int lookup_props_)
472 lookup_props = lookup_props_;
473 iter_input.init (this, false);
474 iter_context.init (this, true);
478 match_properties_mark (hb_codepoint_t glyph,
479 unsigned int glyph_props,
480 unsigned int match_props) const
482 /* If using mark filtering sets, the high short of
483 * match_props has the set index.
485 if (match_props & LookupFlag::UseMarkFilteringSet)
486 return gdef.mark_set_covers (match_props >> 16, glyph);
488 /* The second byte of match_props has the meaning
489 * "ignore marks of attachment type different than
490 * the attachment type specified."
492 if (match_props & LookupFlag::MarkAttachmentType)
493 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
499 check_glyph_property (const hb_glyph_info_t *info,
500 unsigned int match_props) const
502 hb_codepoint_t glyph = info->codepoint;
503 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
505 /* Not covered, if, for example, glyph class is ligature and
506 * match_props includes LookupFlags::IgnoreLigatures
508 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
511 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
512 return match_properties_mark (glyph, glyph_props, match_props);
517 inline void _set_glyph_props (hb_codepoint_t glyph_index,
518 unsigned int class_guess = 0,
519 bool ligature = false,
520 bool component = false) const
522 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
523 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
524 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
527 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
528 /* In the only place that the MULTIPLIED bit is used, Uniscribe
529 * seems to only care about the "last" transformation between
530 * Ligature and Multiple substitions. Ie. if you ligate, expand,
531 * and ligate again, it forgives the multiplication and acts as
532 * if only ligation happened. As such, clear MULTIPLIED bit.
534 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
537 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
538 if (likely (has_glyph_classes))
539 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
540 else if (class_guess)
541 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
544 inline void replace_glyph (hb_codepoint_t glyph_index) const
546 _set_glyph_props (glyph_index);
547 buffer->replace_glyph (glyph_index);
549 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
551 _set_glyph_props (glyph_index);
552 buffer->cur().codepoint = glyph_index;
554 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
555 unsigned int class_guess) const
557 _set_glyph_props (glyph_index, class_guess, true);
558 buffer->replace_glyph (glyph_index);
560 inline void output_glyph_for_component (hb_codepoint_t glyph_index,
561 unsigned int class_guess) const
563 _set_glyph_props (glyph_index, class_guess, false, true);
564 buffer->output_glyph (glyph_index);
570 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
571 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
572 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
574 struct ContextClosureFuncs
576 intersects_func_t intersects;
578 struct ContextCollectGlyphsFuncs
580 collect_glyphs_func_t collect;
582 struct ContextApplyFuncs
588 static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
590 return glyphs->has (value);
592 static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
594 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
595 return class_def.intersects_class (glyphs, value);
597 static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
599 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
600 return (data+coverage).intersects (glyphs);
603 static inline bool intersects_array (hb_closure_context_t *c,
605 const HBUINT16 values[],
606 intersects_func_t intersects_func,
607 const void *intersects_data)
609 for (unsigned int i = 0; i < count; i++)
610 if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
616 static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
620 static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
622 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
623 class_def.add_class (glyphs, value);
625 static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
627 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
628 (data+coverage).add_coverage (glyphs);
630 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
633 const HBUINT16 values[],
634 collect_glyphs_func_t collect_func,
635 const void *collect_data)
637 for (unsigned int i = 0; i < count; i++)
638 collect_func (glyphs, values[i], collect_data);
642 static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
644 return glyph_id == value;
646 static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
648 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
649 return class_def.get_class (glyph_id) == value;
651 static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
653 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
654 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
657 static inline bool would_match_input (hb_would_apply_context_t *c,
658 unsigned int count, /* Including the first glyph (not matched) */
659 const HBUINT16 input[], /* Array of input values--start with second glyph */
660 match_func_t match_func,
661 const void *match_data)
666 for (unsigned int i = 1; i < count; i++)
667 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
672 static inline bool match_input (hb_ot_apply_context_t *c,
673 unsigned int count, /* Including the first glyph (not matched) */
674 const HBUINT16 input[], /* Array of input values--start with second glyph */
675 match_func_t match_func,
676 const void *match_data,
677 unsigned int *end_offset,
678 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
679 bool *p_is_mark_ligature = nullptr,
680 unsigned int *p_total_component_count = nullptr)
682 TRACE_APPLY (nullptr);
684 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
686 hb_buffer_t *buffer = c->buffer;
688 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
689 skippy_iter.reset (buffer->idx, count - 1);
690 skippy_iter.set_match_func (match_func, match_data, input);
693 * This is perhaps the trickiest part of OpenType... Remarks:
695 * - If all components of the ligature were marks, we call this a mark ligature.
697 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
698 * it as a ligature glyph.
700 * - Ligatures cannot be formed across glyphs attached to different components
701 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
702 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
703 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
704 * There are a couple of exceptions to this:
706 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
707 * assuming that the font designer knows what they are doing (otherwise it can
708 * break Indic stuff when a matra wants to ligate with a conjunct,
710 * o If two marks want to ligate and they belong to different components of the
711 * same ligature glyph, and said ligature glyph is to be ignored according to
712 * mark-filtering rules, then allow.
713 * https://github.com/harfbuzz/harfbuzz/issues/545
716 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
718 unsigned int total_component_count = 0;
719 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
721 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
722 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
726 LIGBASE_MAY_NOT_SKIP,
728 } ligbase = LIGBASE_NOT_CHECKED;
730 match_positions[0] = buffer->idx;
731 for (unsigned int i = 1; i < count; i++)
733 if (!skippy_iter.next ()) return_trace (false);
735 match_positions[i] = skippy_iter.idx;
737 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
738 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
740 if (first_lig_id && first_lig_comp)
742 /* If first component was attached to a previous ligature component,
743 * all subsequent components should be attached to the same ligature
744 * component, otherwise we shouldn't ligate them... */
745 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
747 /* ...unless, we are attached to a base ligature and that base
748 * ligature is ignorable. */
749 if (ligbase == LIGBASE_NOT_CHECKED)
752 const hb_glyph_info_t *out = buffer->out_info;
753 unsigned int j = buffer->out_len;
754 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
756 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
765 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
766 ligbase = LIGBASE_MAY_SKIP;
768 ligbase = LIGBASE_MAY_NOT_SKIP;
771 if (ligbase == LIGBASE_MAY_NOT_SKIP)
772 return_trace (false);
777 /* If first component was NOT attached to a previous ligature component,
778 * all subsequent components should also NOT be attached to any ligature
779 * component, unless they are attached to the first component itself! */
780 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
781 return_trace (false);
784 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
785 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
788 *end_offset = skippy_iter.idx - buffer->idx + 1;
790 if (p_is_mark_ligature)
791 *p_is_mark_ligature = is_mark_ligature;
793 if (p_total_component_count)
794 *p_total_component_count = total_component_count;
798 static inline bool ligate_input (hb_ot_apply_context_t *c,
799 unsigned int count, /* Including the first glyph */
800 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
801 unsigned int match_length,
802 hb_codepoint_t lig_glyph,
803 bool is_mark_ligature,
804 unsigned int total_component_count)
806 TRACE_APPLY (nullptr);
808 hb_buffer_t *buffer = c->buffer;
810 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
813 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
814 * the ligature to keep its old ligature id. This will allow it to attach to
815 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
816 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
817 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
818 * later, we don't want them to lose their ligature id/component, otherwise
819 * GPOS will fail to correctly position the mark ligature on top of the
820 * LAM,LAM,HEH ligature. See:
821 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
823 * - If a ligature is formed of components that some of which are also ligatures
824 * themselves, and those ligature components had marks attached to *their*
825 * components, we have to attach the marks to the new ligature component
826 * positions! Now *that*'s tricky! And these marks may be following the
827 * last component of the whole sequence, so we should loop forward looking
828 * for them and update them.
830 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
831 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
832 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
833 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
834 * the new ligature with a component value of 2.
836 * This in fact happened to a font... See:
837 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
840 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
841 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
842 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
843 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
844 unsigned int components_so_far = last_num_components;
846 if (!is_mark_ligature)
848 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
849 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
851 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
854 c->replace_glyph_with_ligature (lig_glyph, klass);
856 for (unsigned int i = 1; i < count; i++)
858 while (buffer->idx < match_positions[i] && !buffer->in_error)
860 if (!is_mark_ligature) {
861 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
863 this_comp = last_num_components;
864 unsigned int new_lig_comp = components_so_far - last_num_components +
865 MIN (this_comp, last_num_components);
866 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
868 buffer->next_glyph ();
871 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
872 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
873 components_so_far += last_num_components;
875 /* Skip the base glyph */
879 if (!is_mark_ligature && last_lig_id) {
880 /* Re-adjust components for any marks following. */
881 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
882 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
883 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
886 unsigned int new_lig_comp = components_so_far - last_num_components +
887 MIN (this_comp, last_num_components);
888 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
896 static inline bool match_backtrack (hb_ot_apply_context_t *c,
898 const HBUINT16 backtrack[],
899 match_func_t match_func,
900 const void *match_data,
901 unsigned int *match_start)
903 TRACE_APPLY (nullptr);
905 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
906 skippy_iter.reset (c->buffer->backtrack_len (), count);
907 skippy_iter.set_match_func (match_func, match_data, backtrack);
909 for (unsigned int i = 0; i < count; i++)
910 if (!skippy_iter.prev ())
911 return_trace (false);
913 *match_start = skippy_iter.idx;
918 static inline bool match_lookahead (hb_ot_apply_context_t *c,
920 const HBUINT16 lookahead[],
921 match_func_t match_func,
922 const void *match_data,
924 unsigned int *end_index)
926 TRACE_APPLY (nullptr);
928 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
929 skippy_iter.reset (c->buffer->idx + offset - 1, count);
930 skippy_iter.set_match_func (match_func, match_data, lookahead);
932 for (unsigned int i = 0; i < count; i++)
933 if (!skippy_iter.next ())
934 return_trace (false);
936 *end_index = skippy_iter.idx + 1;
945 inline bool sanitize (hb_sanitize_context_t *c) const
947 TRACE_SANITIZE (this);
948 return_trace (c->check_struct (this));
951 HBUINT16 sequenceIndex; /* Index into current glyph
952 * sequence--first glyph = 0 */
953 HBUINT16 lookupListIndex; /* Lookup to apply to that
954 * position--zero--based */
956 DEFINE_SIZE_STATIC (4);
960 template <typename context_t>
961 static inline void recurse_lookups (context_t *c,
962 unsigned int lookupCount,
963 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
965 for (unsigned int i = 0; i < lookupCount; i++)
966 c->recurse (lookupRecord[i].lookupListIndex);
969 static inline bool apply_lookup (hb_ot_apply_context_t *c,
970 unsigned int count, /* Including the first glyph */
971 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
972 unsigned int lookupCount,
973 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
974 unsigned int match_length)
976 TRACE_APPLY (nullptr);
978 hb_buffer_t *buffer = c->buffer;
981 /* All positions are distance from beginning of *output* buffer.
984 unsigned int bl = buffer->backtrack_len ();
985 end = bl + match_length;
987 int delta = bl - buffer->idx;
988 /* Convert positions to new indexing. */
989 for (unsigned int j = 0; j < count; j++)
990 match_positions[j] += delta;
993 for (unsigned int i = 0; i < lookupCount && !buffer->in_error; i++)
995 unsigned int idx = lookupRecord[i].sequenceIndex;
999 /* Don't recurse to ourself at same position.
1000 * Note that this test is too naive, it doesn't catch longer loops. */
1001 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1004 if (unlikely (!buffer->move_to (match_positions[idx])))
1007 if (unlikely (buffer->max_ops <= 0))
1010 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1011 if (!c->recurse (lookupRecord[i].lookupListIndex))
1014 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1015 int delta = new_len - orig_len;
1020 /* Recursed lookup changed buffer len. Adjust.
1024 * Right now, if buffer length increased by n, we assume n new glyphs
1025 * were added right after the current position, and if buffer length
1026 * was decreased by n, we assume n match positions after the current
1027 * one where removed. The former (buffer length increased) case is
1028 * fine, but the decrease case can be improved in at least two ways,
1029 * both of which are significant:
1031 * - If recursed-to lookup is MultipleSubst and buffer length
1032 * decreased, then it's current match position that was deleted,
1033 * NOT the one after it.
1035 * - If buffer length was decreased by n, it does not necessarily
1036 * mean that n match positions where removed, as there might
1037 * have been marks and default-ignorables in the sequence. We
1038 * should instead drop match positions between current-position
1039 * and current-position + n instead.
1041 * It should be possible to construct tests for both of these cases.
1045 if (end <= int (match_positions[idx]))
1047 /* End might end up being smaller than match_positions[idx] if the recursed
1048 * lookup ended up removing many items, more than we have had matched.
1049 * Just never rewind end back and get out of here.
1050 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1051 end = match_positions[idx];
1052 /* There can't be any further changes. */
1056 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1060 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1065 /* NOTE: delta is negative. */
1066 delta = MAX (delta, (int) next - (int) count);
1071 memmove (match_positions + next + delta, match_positions + next,
1072 (count - next) * sizeof (match_positions[0]));
1076 /* Fill in new entries. */
1077 for (unsigned int j = idx + 1; j < next; j++)
1078 match_positions[j] = match_positions[j - 1] + 1;
1080 /* And fixup the rest. */
1081 for (; next < count; next++)
1082 match_positions[next] += delta;
1085 buffer->move_to (end);
1087 return_trace (true);
1092 /* Contextual lookups */
1094 struct ContextClosureLookupContext
1096 ContextClosureFuncs funcs;
1097 const void *intersects_data;
1100 struct ContextCollectGlyphsLookupContext
1102 ContextCollectGlyphsFuncs funcs;
1103 const void *collect_data;
1106 struct ContextApplyLookupContext
1108 ContextApplyFuncs funcs;
1109 const void *match_data;
1112 static inline void context_closure_lookup (hb_closure_context_t *c,
1113 unsigned int inputCount, /* Including the first glyph (not matched) */
1114 const HBUINT16 input[], /* Array of input values--start with second glyph */
1115 unsigned int lookupCount,
1116 const LookupRecord lookupRecord[],
1117 ContextClosureLookupContext &lookup_context)
1119 if (intersects_array (c,
1120 inputCount ? inputCount - 1 : 0, input,
1121 lookup_context.funcs.intersects, lookup_context.intersects_data))
1123 lookupCount, lookupRecord);
1126 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1127 unsigned int inputCount, /* Including the first glyph (not matched) */
1128 const HBUINT16 input[], /* Array of input values--start with second glyph */
1129 unsigned int lookupCount,
1130 const LookupRecord lookupRecord[],
1131 ContextCollectGlyphsLookupContext &lookup_context)
1133 collect_array (c, c->input,
1134 inputCount ? inputCount - 1 : 0, input,
1135 lookup_context.funcs.collect, lookup_context.collect_data);
1137 lookupCount, lookupRecord);
1140 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1141 unsigned int inputCount, /* Including the first glyph (not matched) */
1142 const HBUINT16 input[], /* Array of input values--start with second glyph */
1143 unsigned int lookupCount HB_UNUSED,
1144 const LookupRecord lookupRecord[] HB_UNUSED,
1145 ContextApplyLookupContext &lookup_context)
1147 return would_match_input (c,
1149 lookup_context.funcs.match, lookup_context.match_data);
1151 static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
1152 unsigned int inputCount, /* Including the first glyph (not matched) */
1153 const HBUINT16 input[], /* Array of input values--start with second glyph */
1154 unsigned int lookupCount,
1155 const LookupRecord lookupRecord[],
1156 ContextApplyLookupContext &lookup_context)
1158 unsigned int match_length = 0;
1159 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1160 return match_input (c,
1162 lookup_context.funcs.match, lookup_context.match_data,
1163 &match_length, match_positions)
1164 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1166 inputCount, match_positions,
1167 lookupCount, lookupRecord,
1173 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1175 TRACE_CLOSURE (this);
1176 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1177 context_closure_lookup (c,
1179 lookupCount, lookupRecord,
1183 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1185 TRACE_COLLECT_GLYPHS (this);
1186 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1187 context_collect_glyphs_lookup (c,
1189 lookupCount, lookupRecord,
1193 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1195 TRACE_WOULD_APPLY (this);
1196 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1197 return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
1200 inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1203 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1204 return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
1208 inline bool sanitize (hb_sanitize_context_t *c) const
1210 TRACE_SANITIZE (this);
1211 return_trace (inputCount.sanitize (c) &&
1212 lookupCount.sanitize (c) &&
1213 c->check_range (inputZ,
1214 inputZ[0].static_size * inputCount +
1215 LookupRecord::static_size * lookupCount));
1219 HBUINT16 inputCount; /* Total number of glyphs in input
1220 * glyph sequence--includes the first
1222 HBUINT16 lookupCount; /* Number of LookupRecords */
1223 HBUINT16 inputZ[VAR]; /* Array of match inputs--start with
1225 /*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in
1228 DEFINE_SIZE_ARRAY (4, inputZ);
1233 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1235 TRACE_CLOSURE (this);
1236 unsigned int num_rules = rule.len;
1237 for (unsigned int i = 0; i < num_rules; i++)
1238 (this+rule[i]).closure (c, lookup_context);
1241 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1243 TRACE_COLLECT_GLYPHS (this);
1244 unsigned int num_rules = rule.len;
1245 for (unsigned int i = 0; i < num_rules; i++)
1246 (this+rule[i]).collect_glyphs (c, lookup_context);
1249 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1251 TRACE_WOULD_APPLY (this);
1252 unsigned int num_rules = rule.len;
1253 for (unsigned int i = 0; i < num_rules; i++)
1255 if ((this+rule[i]).would_apply (c, lookup_context))
1256 return_trace (true);
1258 return_trace (false);
1261 inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1264 unsigned int num_rules = rule.len;
1265 for (unsigned int i = 0; i < num_rules; i++)
1267 if ((this+rule[i]).apply (c, lookup_context))
1268 return_trace (true);
1270 return_trace (false);
1273 inline bool sanitize (hb_sanitize_context_t *c) const
1275 TRACE_SANITIZE (this);
1276 return_trace (rule.sanitize (c, this));
1281 rule; /* Array of Rule tables
1282 * ordered by preference */
1284 DEFINE_SIZE_ARRAY (2, rule);
1288 struct ContextFormat1
1290 inline void closure (hb_closure_context_t *c) const
1292 TRACE_CLOSURE (this);
1294 const Coverage &cov = (this+coverage);
1296 struct ContextClosureLookupContext lookup_context = {
1301 unsigned int count = ruleSet.len;
1302 for (unsigned int i = 0; i < count; i++)
1303 if (cov.intersects_coverage (c->glyphs, i)) {
1304 const RuleSet &rule_set = this+ruleSet[i];
1305 rule_set.closure (c, lookup_context);
1309 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1311 TRACE_COLLECT_GLYPHS (this);
1312 (this+coverage).add_coverage (c->input);
1314 struct ContextCollectGlyphsLookupContext lookup_context = {
1319 unsigned int count = ruleSet.len;
1320 for (unsigned int i = 0; i < count; i++)
1321 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1324 inline bool would_apply (hb_would_apply_context_t *c) const
1326 TRACE_WOULD_APPLY (this);
1328 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1329 struct ContextApplyLookupContext lookup_context = {
1333 return_trace (rule_set.would_apply (c, lookup_context));
1336 inline const Coverage &get_coverage (void) const
1338 return this+coverage;
1341 inline bool apply (hb_ot_apply_context_t *c) const
1344 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1345 if (likely (index == NOT_COVERED))
1346 return_trace (false);
1348 const RuleSet &rule_set = this+ruleSet[index];
1349 struct ContextApplyLookupContext lookup_context = {
1353 return_trace (rule_set.apply (c, lookup_context));
1356 inline bool sanitize (hb_sanitize_context_t *c) const
1358 TRACE_SANITIZE (this);
1359 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1363 HBUINT16 format; /* Format identifier--format = 1 */
1365 coverage; /* Offset to Coverage table--from
1366 * beginning of table */
1367 OffsetArrayOf<RuleSet>
1368 ruleSet; /* Array of RuleSet tables
1369 * ordered by Coverage Index */
1371 DEFINE_SIZE_ARRAY (6, ruleSet);
1375 struct ContextFormat2
1377 inline void closure (hb_closure_context_t *c) const
1379 TRACE_CLOSURE (this);
1380 if (!(this+coverage).intersects (c->glyphs))
1383 const ClassDef &class_def = this+classDef;
1385 struct ContextClosureLookupContext lookup_context = {
1390 unsigned int count = ruleSet.len;
1391 for (unsigned int i = 0; i < count; i++)
1392 if (class_def.intersects_class (c->glyphs, i)) {
1393 const RuleSet &rule_set = this+ruleSet[i];
1394 rule_set.closure (c, lookup_context);
1398 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1400 TRACE_COLLECT_GLYPHS (this);
1401 (this+coverage).add_coverage (c->input);
1403 const ClassDef &class_def = this+classDef;
1404 struct ContextCollectGlyphsLookupContext lookup_context = {
1409 unsigned int count = ruleSet.len;
1410 for (unsigned int i = 0; i < count; i++)
1411 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1414 inline bool would_apply (hb_would_apply_context_t *c) const
1416 TRACE_WOULD_APPLY (this);
1418 const ClassDef &class_def = this+classDef;
1419 unsigned int index = class_def.get_class (c->glyphs[0]);
1420 const RuleSet &rule_set = this+ruleSet[index];
1421 struct ContextApplyLookupContext lookup_context = {
1425 return_trace (rule_set.would_apply (c, lookup_context));
1428 inline const Coverage &get_coverage (void) const
1430 return this+coverage;
1433 inline bool apply (hb_ot_apply_context_t *c) const
1436 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1437 if (likely (index == NOT_COVERED)) return_trace (false);
1439 const ClassDef &class_def = this+classDef;
1440 index = class_def.get_class (c->buffer->cur().codepoint);
1441 const RuleSet &rule_set = this+ruleSet[index];
1442 struct ContextApplyLookupContext lookup_context = {
1446 return_trace (rule_set.apply (c, lookup_context));
1449 inline bool sanitize (hb_sanitize_context_t *c) const
1451 TRACE_SANITIZE (this);
1452 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
1456 HBUINT16 format; /* Format identifier--format = 2 */
1458 coverage; /* Offset to Coverage table--from
1459 * beginning of table */
1461 classDef; /* Offset to glyph ClassDef table--from
1462 * beginning of table */
1463 OffsetArrayOf<RuleSet>
1464 ruleSet; /* Array of RuleSet tables
1465 * ordered by class */
1467 DEFINE_SIZE_ARRAY (8, ruleSet);
1471 struct ContextFormat3
1473 inline void closure (hb_closure_context_t *c) const
1475 TRACE_CLOSURE (this);
1476 if (!(this+coverageZ[0]).intersects (c->glyphs))
1479 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1480 struct ContextClosureLookupContext lookup_context = {
1481 {intersects_coverage},
1484 context_closure_lookup (c,
1485 glyphCount, (const HBUINT16 *) (coverageZ + 1),
1486 lookupCount, lookupRecord,
1490 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1492 TRACE_COLLECT_GLYPHS (this);
1493 (this+coverageZ[0]).add_coverage (c->input);
1495 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1496 struct ContextCollectGlyphsLookupContext lookup_context = {
1501 context_collect_glyphs_lookup (c,
1502 glyphCount, (const HBUINT16 *) (coverageZ + 1),
1503 lookupCount, lookupRecord,
1507 inline bool would_apply (hb_would_apply_context_t *c) const
1509 TRACE_WOULD_APPLY (this);
1511 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1512 struct ContextApplyLookupContext lookup_context = {
1516 return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
1519 inline const Coverage &get_coverage (void) const
1521 return this+coverageZ[0];
1524 inline bool apply (hb_ot_apply_context_t *c) const
1527 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
1528 if (likely (index == NOT_COVERED)) return_trace (false);
1530 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1531 struct ContextApplyLookupContext lookup_context = {
1535 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
1538 inline bool sanitize (hb_sanitize_context_t *c) const
1540 TRACE_SANITIZE (this);
1541 if (!c->check_struct (this)) return_trace (false);
1542 unsigned int count = glyphCount;
1543 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1544 if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
1545 for (unsigned int i = 0; i < count; i++)
1546 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
1547 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
1548 return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
1552 HBUINT16 format; /* Format identifier--format = 3 */
1553 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
1555 HBUINT16 lookupCount; /* Number of LookupRecords */
1557 coverageZ[VAR]; /* Array of offsets to Coverage
1558 * table in glyph sequence order */
1559 /*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in
1562 DEFINE_SIZE_ARRAY (6, coverageZ);
1567 template <typename context_t>
1568 inline typename context_t::return_t dispatch (context_t *c) const
1570 TRACE_DISPATCH (this, u.format);
1571 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1573 case 1: return_trace (c->dispatch (u.format1));
1574 case 2: return_trace (c->dispatch (u.format2));
1575 case 3: return_trace (c->dispatch (u.format3));
1576 default:return_trace (c->default_return_value ());
1582 HBUINT16 format; /* Format identifier */
1583 ContextFormat1 format1;
1584 ContextFormat2 format2;
1585 ContextFormat3 format3;
1590 /* Chaining Contextual lookups */
1592 struct ChainContextClosureLookupContext
1594 ContextClosureFuncs funcs;
1595 const void *intersects_data[3];
1598 struct ChainContextCollectGlyphsLookupContext
1600 ContextCollectGlyphsFuncs funcs;
1601 const void *collect_data[3];
1604 struct ChainContextApplyLookupContext
1606 ContextApplyFuncs funcs;
1607 const void *match_data[3];
1610 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1611 unsigned int backtrackCount,
1612 const HBUINT16 backtrack[],
1613 unsigned int inputCount, /* Including the first glyph (not matched) */
1614 const HBUINT16 input[], /* Array of input values--start with second glyph */
1615 unsigned int lookaheadCount,
1616 const HBUINT16 lookahead[],
1617 unsigned int lookupCount,
1618 const LookupRecord lookupRecord[],
1619 ChainContextClosureLookupContext &lookup_context)
1621 if (intersects_array (c,
1622 backtrackCount, backtrack,
1623 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1624 && intersects_array (c,
1625 inputCount ? inputCount - 1 : 0, input,
1626 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1627 && intersects_array (c,
1628 lookaheadCount, lookahead,
1629 lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
1631 lookupCount, lookupRecord);
1634 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1635 unsigned int backtrackCount,
1636 const HBUINT16 backtrack[],
1637 unsigned int inputCount, /* Including the first glyph (not matched) */
1638 const HBUINT16 input[], /* Array of input values--start with second glyph */
1639 unsigned int lookaheadCount,
1640 const HBUINT16 lookahead[],
1641 unsigned int lookupCount,
1642 const LookupRecord lookupRecord[],
1643 ChainContextCollectGlyphsLookupContext &lookup_context)
1645 collect_array (c, c->before,
1646 backtrackCount, backtrack,
1647 lookup_context.funcs.collect, lookup_context.collect_data[0]);
1648 collect_array (c, c->input,
1649 inputCount ? inputCount - 1 : 0, input,
1650 lookup_context.funcs.collect, lookup_context.collect_data[1]);
1651 collect_array (c, c->after,
1652 lookaheadCount, lookahead,
1653 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1655 lookupCount, lookupRecord);
1658 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1659 unsigned int backtrackCount,
1660 const HBUINT16 backtrack[] HB_UNUSED,
1661 unsigned int inputCount, /* Including the first glyph (not matched) */
1662 const HBUINT16 input[], /* Array of input values--start with second glyph */
1663 unsigned int lookaheadCount,
1664 const HBUINT16 lookahead[] HB_UNUSED,
1665 unsigned int lookupCount HB_UNUSED,
1666 const LookupRecord lookupRecord[] HB_UNUSED,
1667 ChainContextApplyLookupContext &lookup_context)
1669 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1670 && would_match_input (c,
1672 lookup_context.funcs.match, lookup_context.match_data[1]);
1675 static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
1676 unsigned int backtrackCount,
1677 const HBUINT16 backtrack[],
1678 unsigned int inputCount, /* Including the first glyph (not matched) */
1679 const HBUINT16 input[], /* Array of input values--start with second glyph */
1680 unsigned int lookaheadCount,
1681 const HBUINT16 lookahead[],
1682 unsigned int lookupCount,
1683 const LookupRecord lookupRecord[],
1684 ChainContextApplyLookupContext &lookup_context)
1686 unsigned int start_index = 0, match_length = 0, end_index = 0;
1687 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1688 return match_input (c,
1690 lookup_context.funcs.match, lookup_context.match_data[1],
1691 &match_length, match_positions)
1692 && match_backtrack (c,
1693 backtrackCount, backtrack,
1694 lookup_context.funcs.match, lookup_context.match_data[0],
1696 && match_lookahead (c,
1697 lookaheadCount, lookahead,
1698 lookup_context.funcs.match, lookup_context.match_data[2],
1699 match_length, &end_index)
1700 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1702 inputCount, match_positions,
1703 lookupCount, lookupRecord,
1709 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1711 TRACE_CLOSURE (this);
1712 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1713 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1714 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1715 chain_context_closure_lookup (c,
1716 backtrack.len, backtrack.array,
1717 input.len, input.array,
1718 lookahead.len, lookahead.array,
1719 lookup.len, lookup.array,
1723 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1725 TRACE_COLLECT_GLYPHS (this);
1726 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1727 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1728 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1729 chain_context_collect_glyphs_lookup (c,
1730 backtrack.len, backtrack.array,
1731 input.len, input.array,
1732 lookahead.len, lookahead.array,
1733 lookup.len, lookup.array,
1737 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1739 TRACE_WOULD_APPLY (this);
1740 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1741 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1742 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1743 return_trace (chain_context_would_apply_lookup (c,
1744 backtrack.len, backtrack.array,
1745 input.len, input.array,
1746 lookahead.len, lookahead.array, lookup.len,
1747 lookup.array, lookup_context));
1750 inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1753 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1754 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1755 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1756 return_trace (chain_context_apply_lookup (c,
1757 backtrack.len, backtrack.array,
1758 input.len, input.array,
1759 lookahead.len, lookahead.array, lookup.len,
1760 lookup.array, lookup_context));
1763 inline bool sanitize (hb_sanitize_context_t *c) const
1765 TRACE_SANITIZE (this);
1766 if (!backtrack.sanitize (c)) return_trace (false);
1767 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1768 if (!input.sanitize (c)) return_trace (false);
1769 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1770 if (!lookahead.sanitize (c)) return_trace (false);
1771 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1772 return_trace (lookup.sanitize (c));
1777 backtrack; /* Array of backtracking values
1778 * (to be matched before the input
1780 HeadlessArrayOf<HBUINT16>
1781 inputX; /* Array of input values (start with
1784 lookaheadX; /* Array of lookahead values's (to be
1785 * matched after the input sequence) */
1786 ArrayOf<LookupRecord>
1787 lookupX; /* Array of LookupRecords--in
1790 DEFINE_SIZE_MIN (8);
1795 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1797 TRACE_CLOSURE (this);
1798 unsigned int num_rules = rule.len;
1799 for (unsigned int i = 0; i < num_rules; i++)
1800 (this+rule[i]).closure (c, lookup_context);
1803 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1805 TRACE_COLLECT_GLYPHS (this);
1806 unsigned int num_rules = rule.len;
1807 for (unsigned int i = 0; i < num_rules; i++)
1808 (this+rule[i]).collect_glyphs (c, lookup_context);
1811 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1813 TRACE_WOULD_APPLY (this);
1814 unsigned int num_rules = rule.len;
1815 for (unsigned int i = 0; i < num_rules; i++)
1816 if ((this+rule[i]).would_apply (c, lookup_context))
1817 return_trace (true);
1819 return_trace (false);
1822 inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1825 unsigned int num_rules = rule.len;
1826 for (unsigned int i = 0; i < num_rules; i++)
1827 if ((this+rule[i]).apply (c, lookup_context))
1828 return_trace (true);
1830 return_trace (false);
1833 inline bool sanitize (hb_sanitize_context_t *c) const
1835 TRACE_SANITIZE (this);
1836 return_trace (rule.sanitize (c, this));
1840 OffsetArrayOf<ChainRule>
1841 rule; /* Array of ChainRule tables
1842 * ordered by preference */
1844 DEFINE_SIZE_ARRAY (2, rule);
1847 struct ChainContextFormat1
1849 inline void closure (hb_closure_context_t *c) const
1851 TRACE_CLOSURE (this);
1852 const Coverage &cov = (this+coverage);
1854 struct ChainContextClosureLookupContext lookup_context = {
1856 {nullptr, nullptr, nullptr}
1859 unsigned int count = ruleSet.len;
1860 for (unsigned int i = 0; i < count; i++)
1861 if (cov.intersects_coverage (c->glyphs, i)) {
1862 const ChainRuleSet &rule_set = this+ruleSet[i];
1863 rule_set.closure (c, lookup_context);
1867 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1869 TRACE_COLLECT_GLYPHS (this);
1870 (this+coverage).add_coverage (c->input);
1872 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1874 {nullptr, nullptr, nullptr}
1877 unsigned int count = ruleSet.len;
1878 for (unsigned int i = 0; i < count; i++)
1879 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1882 inline bool would_apply (hb_would_apply_context_t *c) const
1884 TRACE_WOULD_APPLY (this);
1886 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1887 struct ChainContextApplyLookupContext lookup_context = {
1889 {nullptr, nullptr, nullptr}
1891 return_trace (rule_set.would_apply (c, lookup_context));
1894 inline const Coverage &get_coverage (void) const
1896 return this+coverage;
1899 inline bool apply (hb_ot_apply_context_t *c) const
1902 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1903 if (likely (index == NOT_COVERED)) return_trace (false);
1905 const ChainRuleSet &rule_set = this+ruleSet[index];
1906 struct ChainContextApplyLookupContext lookup_context = {
1908 {nullptr, nullptr, nullptr}
1910 return_trace (rule_set.apply (c, lookup_context));
1913 inline bool sanitize (hb_sanitize_context_t *c) const
1915 TRACE_SANITIZE (this);
1916 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1920 HBUINT16 format; /* Format identifier--format = 1 */
1922 coverage; /* Offset to Coverage table--from
1923 * beginning of table */
1924 OffsetArrayOf<ChainRuleSet>
1925 ruleSet; /* Array of ChainRuleSet tables
1926 * ordered by Coverage Index */
1928 DEFINE_SIZE_ARRAY (6, ruleSet);
1931 struct ChainContextFormat2
1933 inline void closure (hb_closure_context_t *c) const
1935 TRACE_CLOSURE (this);
1936 if (!(this+coverage).intersects (c->glyphs))
1939 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1940 const ClassDef &input_class_def = this+inputClassDef;
1941 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1943 struct ChainContextClosureLookupContext lookup_context = {
1945 {&backtrack_class_def,
1947 &lookahead_class_def}
1950 unsigned int count = ruleSet.len;
1951 for (unsigned int i = 0; i < count; i++)
1952 if (input_class_def.intersects_class (c->glyphs, i)) {
1953 const ChainRuleSet &rule_set = this+ruleSet[i];
1954 rule_set.closure (c, lookup_context);
1958 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1960 TRACE_COLLECT_GLYPHS (this);
1961 (this+coverage).add_coverage (c->input);
1963 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1964 const ClassDef &input_class_def = this+inputClassDef;
1965 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1967 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1969 {&backtrack_class_def,
1971 &lookahead_class_def}
1974 unsigned int count = ruleSet.len;
1975 for (unsigned int i = 0; i < count; i++)
1976 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1979 inline bool would_apply (hb_would_apply_context_t *c) const
1981 TRACE_WOULD_APPLY (this);
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 unsigned int index = input_class_def.get_class (c->glyphs[0]);
1988 const ChainRuleSet &rule_set = this+ruleSet[index];
1989 struct ChainContextApplyLookupContext lookup_context = {
1991 {&backtrack_class_def,
1993 &lookahead_class_def}
1995 return_trace (rule_set.would_apply (c, lookup_context));
1998 inline const Coverage &get_coverage (void) const
2000 return this+coverage;
2003 inline bool apply (hb_ot_apply_context_t *c) const
2006 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2007 if (likely (index == NOT_COVERED)) return_trace (false);
2009 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2010 const ClassDef &input_class_def = this+inputClassDef;
2011 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2013 index = input_class_def.get_class (c->buffer->cur().codepoint);
2014 const ChainRuleSet &rule_set = this+ruleSet[index];
2015 struct ChainContextApplyLookupContext lookup_context = {
2017 {&backtrack_class_def,
2019 &lookahead_class_def}
2021 return_trace (rule_set.apply (c, lookup_context));
2024 inline bool sanitize (hb_sanitize_context_t *c) const
2026 TRACE_SANITIZE (this);
2027 return_trace (coverage.sanitize (c, this) &&
2028 backtrackClassDef.sanitize (c, this) &&
2029 inputClassDef.sanitize (c, this) &&
2030 lookaheadClassDef.sanitize (c, this) &&
2031 ruleSet.sanitize (c, this));
2035 HBUINT16 format; /* Format identifier--format = 2 */
2037 coverage; /* Offset to Coverage table--from
2038 * beginning of table */
2040 backtrackClassDef; /* Offset to glyph ClassDef table
2041 * containing backtrack sequence
2042 * data--from beginning of table */
2044 inputClassDef; /* Offset to glyph ClassDef
2045 * table containing input sequence
2046 * data--from beginning of table */
2048 lookaheadClassDef; /* Offset to glyph ClassDef table
2049 * containing lookahead sequence
2050 * data--from beginning of table */
2051 OffsetArrayOf<ChainRuleSet>
2052 ruleSet; /* Array of ChainRuleSet tables
2053 * ordered by class */
2055 DEFINE_SIZE_ARRAY (12, ruleSet);
2058 struct ChainContextFormat3
2060 inline void closure (hb_closure_context_t *c) const
2062 TRACE_CLOSURE (this);
2063 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2065 if (!(this+input[0]).intersects (c->glyphs))
2068 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2069 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2070 struct ChainContextClosureLookupContext lookup_context = {
2071 {intersects_coverage},
2074 chain_context_closure_lookup (c,
2075 backtrack.len, (const HBUINT16 *) backtrack.array,
2076 input.len, (const HBUINT16 *) input.array + 1,
2077 lookahead.len, (const HBUINT16 *) lookahead.array,
2078 lookup.len, lookup.array,
2082 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2084 TRACE_COLLECT_GLYPHS (this);
2085 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2087 (this+input[0]).add_coverage (c->input);
2089 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2090 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2091 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2095 chain_context_collect_glyphs_lookup (c,
2096 backtrack.len, (const HBUINT16 *) backtrack.array,
2097 input.len, (const HBUINT16 *) input.array + 1,
2098 lookahead.len, (const HBUINT16 *) lookahead.array,
2099 lookup.len, lookup.array,
2103 inline bool would_apply (hb_would_apply_context_t *c) const
2105 TRACE_WOULD_APPLY (this);
2107 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2108 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2109 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2110 struct ChainContextApplyLookupContext lookup_context = {
2114 return_trace (chain_context_would_apply_lookup (c,
2115 backtrack.len, (const HBUINT16 *) backtrack.array,
2116 input.len, (const HBUINT16 *) input.array + 1,
2117 lookahead.len, (const HBUINT16 *) lookahead.array,
2118 lookup.len, lookup.array, lookup_context));
2121 inline const Coverage &get_coverage (void) const
2123 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2124 return this+input[0];
2127 inline bool apply (hb_ot_apply_context_t *c) const
2130 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2132 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2133 if (likely (index == NOT_COVERED)) return_trace (false);
2135 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2136 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2137 struct ChainContextApplyLookupContext lookup_context = {
2141 return_trace (chain_context_apply_lookup (c,
2142 backtrack.len, (const HBUINT16 *) backtrack.array,
2143 input.len, (const HBUINT16 *) input.array + 1,
2144 lookahead.len, (const HBUINT16 *) lookahead.array,
2145 lookup.len, lookup.array, lookup_context));
2148 inline bool sanitize (hb_sanitize_context_t *c) const
2150 TRACE_SANITIZE (this);
2151 if (!backtrack.sanitize (c, this)) return_trace (false);
2152 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2153 if (!input.sanitize (c, this)) return_trace (false);
2154 if (!input.len) return_trace (false); /* To be consistent with Context. */
2155 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2156 if (!lookahead.sanitize (c, this)) return_trace (false);
2157 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2158 return_trace (lookup.sanitize (c));
2162 HBUINT16 format; /* Format identifier--format = 3 */
2163 OffsetArrayOf<Coverage>
2164 backtrack; /* Array of coverage tables
2165 * in backtracking sequence, in glyph
2167 OffsetArrayOf<Coverage>
2168 inputX ; /* Array of coverage
2169 * tables in input sequence, in glyph
2171 OffsetArrayOf<Coverage>
2172 lookaheadX; /* Array of coverage tables
2173 * in lookahead sequence, in glyph
2175 ArrayOf<LookupRecord>
2176 lookupX; /* Array of LookupRecords--in
2179 DEFINE_SIZE_MIN (10);
2184 template <typename context_t>
2185 inline typename context_t::return_t dispatch (context_t *c) const
2187 TRACE_DISPATCH (this, u.format);
2188 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2190 case 1: return_trace (c->dispatch (u.format1));
2191 case 2: return_trace (c->dispatch (u.format2));
2192 case 3: return_trace (c->dispatch (u.format3));
2193 default:return_trace (c->default_return_value ());
2199 HBUINT16 format; /* Format identifier */
2200 ChainContextFormat1 format1;
2201 ChainContextFormat2 format2;
2202 ChainContextFormat3 format3;
2207 template <typename T>
2208 struct ExtensionFormat1
2210 inline unsigned int get_type (void) const { return extensionLookupType; }
2212 template <typename X>
2213 inline const X& get_subtable (void) const
2215 unsigned int offset = extensionOffset;
2216 if (unlikely (!offset)) return Null(typename T::LookupSubTable);
2217 return StructAtOffset<typename T::LookupSubTable> (this, offset);
2220 template <typename context_t>
2221 inline typename context_t::return_t dispatch (context_t *c) const
2223 TRACE_DISPATCH (this, format);
2224 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
2225 return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
2228 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
2229 inline bool sanitize (hb_sanitize_context_t *c) const
2231 TRACE_SANITIZE (this);
2232 return_trace (c->check_struct (this) &&
2233 extensionOffset != 0 &&
2234 extensionLookupType != T::LookupSubTable::Extension);
2238 HBUINT16 format; /* Format identifier. Set to 1. */
2239 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
2240 * by ExtensionOffset (i.e. the
2241 * extension subtable). */
2242 HBUINT32 extensionOffset; /* Offset to the extension subtable,
2243 * of lookup type subtable. */
2245 DEFINE_SIZE_STATIC (8);
2248 template <typename T>
2251 inline unsigned int get_type (void) const
2254 case 1: return u.format1.get_type ();
2258 template <typename X>
2259 inline const X& get_subtable (void) const
2262 case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
2263 default:return Null(typename T::LookupSubTable);
2267 template <typename context_t>
2268 inline typename context_t::return_t dispatch (context_t *c) const
2270 TRACE_DISPATCH (this, u.format);
2271 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2273 case 1: return_trace (u.format1.dispatch (c));
2274 default:return_trace (c->default_return_value ());
2280 HBUINT16 format; /* Format identifier */
2281 ExtensionFormat1<T> format1;
2292 inline unsigned int get_script_count (void) const
2293 { return (this+scriptList).len; }
2294 inline const Tag& get_script_tag (unsigned int i) const
2295 { return (this+scriptList).get_tag (i); }
2296 inline unsigned int get_script_tags (unsigned int start_offset,
2297 unsigned int *script_count /* IN/OUT */,
2298 hb_tag_t *script_tags /* OUT */) const
2299 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
2300 inline const Script& get_script (unsigned int i) const
2301 { return (this+scriptList)[i]; }
2302 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
2303 { return (this+scriptList).find_index (tag, index); }
2305 inline unsigned int get_feature_count (void) const
2306 { return (this+featureList).len; }
2307 inline hb_tag_t get_feature_tag (unsigned int i) const
2308 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
2309 inline unsigned int get_feature_tags (unsigned int start_offset,
2310 unsigned int *feature_count /* IN/OUT */,
2311 hb_tag_t *feature_tags /* OUT */) const
2312 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
2313 inline const Feature& get_feature (unsigned int i) const
2314 { return (this+featureList)[i]; }
2315 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2316 { return (this+featureList).find_index (tag, index); }
2318 inline unsigned int get_lookup_count (void) const
2319 { return (this+lookupList).len; }
2320 inline const Lookup& get_lookup (unsigned int i) const
2321 { return (this+lookupList)[i]; }
2323 inline bool find_variations_index (const int *coords, unsigned int num_coords,
2324 unsigned int *index) const
2325 { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2326 .find_index (coords, num_coords, index); }
2327 inline const Feature& get_feature_variation (unsigned int feature_index,
2328 unsigned int variations_index) const
2330 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2331 version.to_int () >= 0x00010001u)
2333 const Feature *feature = (this+featureVars).find_substitute (variations_index,
2338 return get_feature (feature_index);
2341 inline bool sanitize (hb_sanitize_context_t *c) const
2343 TRACE_SANITIZE (this);
2344 return_trace (version.sanitize (c) &&
2345 likely (version.major == 1) &&
2346 scriptList.sanitize (c, this) &&
2347 featureList.sanitize (c, this) &&
2348 lookupList.sanitize (c, this) &&
2349 (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
2353 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
2355 OffsetTo<ScriptList>
2356 scriptList; /* ScriptList table */
2357 OffsetTo<FeatureList>
2358 featureList; /* FeatureList table */
2359 OffsetTo<LookupList>
2360 lookupList; /* LookupList table */
2361 LOffsetTo<FeatureVariations>
2362 featureVars; /* Offset to Feature Variations
2363 table--from beginning of table
2364 * (may be NULL). Introduced
2365 * in version 0x00010001. */
2367 DEFINE_SIZE_MIN (10);
2371 } /* namespace OT */
2374 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */