1 #ifndef OT_LAYOUT_GSUB_LIGATURESET_HH
2 #define OT_LAYOUT_GSUB_LIGATURESET_HH
11 template <typename Types>
15 Array16OfOffset16To<Ligature<Types>>
16 ligature; /* Array LigatureSet tables
17 * ordered by preference */
19 DEFINE_SIZE_ARRAY (2, ligature);
21 bool sanitize (hb_sanitize_context_t *c) const
23 TRACE_SANITIZE (this);
24 return_trace (ligature.sanitize (c, this));
27 bool intersects (const hb_set_t *glyphs) const
31 | hb_map (hb_add (this))
32 | hb_map ([glyphs] (const Ligature<Types> &_) { return _.intersects (glyphs); })
37 bool intersects_lig_glyph (const hb_set_t *glyphs) const
41 | hb_map (hb_add (this))
42 | hb_map ([glyphs] (const Ligature<Types> &_) {
43 return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs);
49 void closure (hb_closure_context_t *c) const
52 | hb_map (hb_add (this))
53 | hb_apply ([c] (const Ligature<Types> &_) { _.closure (c); })
57 void collect_glyphs (hb_collect_glyphs_context_t *c) const
60 | hb_map (hb_add (this))
61 | hb_apply ([c] (const Ligature<Types> &_) { _.collect_glyphs (c); })
65 bool would_apply (hb_would_apply_context_t *c) const
69 | hb_map (hb_add (this))
70 | hb_map ([c] (const Ligature<Types> &_) { return _.would_apply (c); })
75 bool apply (hb_ot_apply_context_t *c) const
79 unsigned int num_ligs = ligature.len;
81 #ifndef HB_NO_OT_RULESETS_FAST_PATH
82 if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4)
86 for (unsigned int i = 0; i < num_ligs; i++)
88 const auto &lig = this+ligature.arrayZ[i];
89 if (lig.apply (c)) return_trace (true);
94 /* This version is optimized for speed by matching the first component
95 * of the ligature here, instead of calling into the ligation code.
97 * This is replicated in ChainRuleSet and RuleSet. */
99 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
100 skippy_iter.reset (c->buffer->idx);
101 skippy_iter.set_match_func (match_always, nullptr);
102 skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
104 hb_codepoint_t first = (unsigned) -1;
105 bool matched = skippy_iter.next (&unsafe_to);
106 if (likely (matched))
108 first = c->buffer->info[skippy_iter.idx].codepoint;
109 unsafe_to = skippy_iter.idx + 1;
111 if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
113 /* Can't use the fast path if eg. the next char is a default-ignorable
114 * or other skippable. */
121 bool unsafe_to_concat = false;
123 for (unsigned int i = 0; i < num_ligs; i++)
125 const auto &lig = this+ligature.arrayZ[i];
126 if (unlikely (lig.component.lenP1 <= 1) ||
127 lig.component.arrayZ[0] == first)
131 if (unsafe_to_concat)
132 c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
136 else if (likely (lig.component.lenP1 > 1))
137 unsafe_to_concat = true;
139 if (likely (unsafe_to_concat))
140 c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
142 return_trace (false);
145 bool serialize (hb_serialize_context_t *c,
146 hb_array_t<const HBGlyphID16> ligatures,
147 hb_array_t<const unsigned int> component_count_list,
148 hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */)
150 TRACE_SERIALIZE (this);
151 if (unlikely (!c->extend_min (this))) return_trace (false);
152 if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
153 for (unsigned int i = 0; i < ligatures.length; i++)
155 unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
156 if (unlikely (!ligature[i].serialize_serialize (c,
158 component_list.sub_array (0, component_count))))
159 return_trace (false);
160 component_list += component_count;
165 bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
168 auto *out = c->serializer->start_embed (*this);
169 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
172 | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx))
176 if (bool (out->ligature))
177 // Ensure Coverage table is always packed after this.
178 c->serializer->add_virtual_link (coverage_idx);
180 return_trace (bool (out->ligature));
188 #endif /* OT_LAYOUT_GSUB_LIGATURESET_HH */