1#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
2#define OT_LAYOUT_GSUB_SUBSTLOOKUP_HH
3
4#include "Common.hh"
5#include "SubstLookupSubTable.hh"
6
7namespace OT {
8namespace Layout {
9namespace GSUB_impl {
10
11struct SubstLookup : Lookup
12{
13 using SubTable = SubstLookupSubTable;
14
15 bool sanitize (hb_sanitize_context_t *c) const
16 { return Lookup::sanitize<SubTable> (c); }
17
18 const SubTable& get_subtable (unsigned int i) const
19 { return Lookup::get_subtable<SubTable> (i); }
20
21 static inline bool lookup_type_is_reverse (unsigned int lookup_type)
22 { return lookup_type == SubTable::ReverseChainSingle; }
23
24 bool is_reverse () const
25 {
26 unsigned int type = get_type ();
27 if (unlikely (type == SubTable::Extension))
28 return get_subtable (0).u.extension.is_reverse ();
29 return lookup_type_is_reverse (type);
30 }
31
32 bool may_have_non_1to1 () const
33 {
34 hb_have_non_1to1_context_t c;
35 return dispatch (&c);
36 }
37
38 bool apply (hb_ot_apply_context_t *c) const
39 {
40 TRACE_APPLY (this);
41 return_trace (dispatch (c));
42 }
43
44 bool intersects (const hb_set_t *glyphs) const
45 {
46 hb_intersects_context_t c (glyphs);
47 return dispatch (&c);
48 }
49
50 hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
51 {
52 if (!c->should_visit_lookup (this_index))
53 return hb_closure_context_t::default_return_value ();
54
55 c->set_recurse_func (dispatch_closure_recurse_func);
56
57 hb_closure_context_t::return_t ret = dispatch (c);
58
59 c->flush ();
60
61 return ret;
62 }
63
64 hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
65 {
66 if (c->is_lookup_visited (this_index))
67 return hb_closure_lookups_context_t::default_return_value ();
68
69 c->set_lookup_visited (this_index);
70 if (!intersects (c->glyphs))
71 {
72 c->set_lookup_inactive (this_index);
73 return hb_closure_lookups_context_t::default_return_value ();
74 }
75
76 hb_closure_lookups_context_t::return_t ret = dispatch (c);
77 return ret;
78 }
79
80 hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
81 {
82 c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
83 return dispatch (c);
84 }
85
86 template <typename set_t>
87 void collect_coverage (set_t *glyphs) const
88 {
89 hb_collect_coverage_context_t<set_t> c (glyphs);
90 dispatch (&c);
91 }
92
93 bool would_apply (hb_would_apply_context_t *c,
94 const hb_ot_layout_lookup_accelerator_t *accel) const
95 {
96 if (unlikely (!c->len)) return false;
97 if (!accel->may_have (c->glyphs[0])) return false;
98 return dispatch (c);
99 }
100
101 template<typename Glyphs, typename Substitutes,
102 hb_requires (hb_is_sorted_source_of (Glyphs,
103 const hb_codepoint_t) &&
104 hb_is_source_of (Substitutes,
105 const hb_codepoint_t))>
106 bool serialize_single (hb_serialize_context_t *c,
107 uint32_t lookup_props,
108 Glyphs glyphs,
109 Substitutes substitutes)
110 {
111 TRACE_SERIALIZE (this);
112 if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
113 if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
114 {
115 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
116 return_trace (true);
117 }
118 c->pop_discard ();
119 return_trace (false);
120 }
121
122 template<typename Iterator,
123 hb_requires (hb_is_sorted_iterator (Iterator))>
124 bool serialize (hb_serialize_context_t *c,
125 uint32_t lookup_props,
126 Iterator it)
127 {
128 TRACE_SERIALIZE (this);
129 if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
130 if (c->push<SubTable> ()->u.multiple.
131 serialize (c, it))
132 {
133 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
134 return_trace (true);
135 }
136 c->pop_discard ();
137 return_trace (false);
138 }
139
140 bool serialize_alternate (hb_serialize_context_t *c,
141 uint32_t lookup_props,
142 hb_sorted_array_t<const HBGlyphID16> glyphs,
143 hb_array_t<const unsigned int> alternate_len_list,
144 hb_array_t<const HBGlyphID16> alternate_glyphs_list)
145 {
146 TRACE_SERIALIZE (this);
147 if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
148
149 if (c->push<SubTable> ()->u.alternate.
150 serialize (c,
151 glyphs,
152 alternate_len_list,
153 alternate_glyphs_list))
154 {
155 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
156 return_trace (true);
157 }
158 c->pop_discard ();
159 return_trace (false);
160 }
161
162 bool serialize_ligature (hb_serialize_context_t *c,
163 uint32_t lookup_props,
164 hb_sorted_array_t<const HBGlyphID16> first_glyphs,
165 hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
166 hb_array_t<const HBGlyphID16> ligatures_list,
167 hb_array_t<const unsigned int> component_count_list,
168 hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
169 {
170 TRACE_SERIALIZE (this);
171 if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
172 if (c->push<SubTable> ()->u.ligature.
173 serialize (c,
174 first_glyphs,
175 ligature_per_first_glyph_count_list,
176 ligatures_list,
177 component_count_list,
178 component_list))
179 {
180 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
181 return_trace (true);
182 }
183 c->pop_discard ();
184 return_trace (false);
185 }
186
187 template <typename context_t>
188 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
189
190 static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
191
192 static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
193 {
194 if (!c->should_visit_lookup (lookup_index))
195 return hb_empty_t ();
196
197 hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index);
198
199 /* While in theory we should flush here, it will cause timeouts because a recursive
200 * lookup can keep growing the glyph set. Skip, and outer loop will retry up to
201 * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
202 //c->flush ();
203
204 return ret;
205 }
206
207 template <typename context_t, typename ...Ts>
208 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
209 { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
210
211 bool subset (hb_subset_context_t *c) const
212 { return Lookup::subset<SubTable> (c); }
213};
214
215
216}
217}
218}
219
220#endif /* OT_LAYOUT_GSUB_SUBSTLOOKUP_HH */
221