1 | #ifndef OT_LAYOUT_GSUB_SUBSTLOOKUP_HH |
2 | #define OT_LAYOUT_GSUB_SUBSTLOOKUP_HH |
3 | |
4 | #include "Common.hh" |
5 | #include "SubstLookupSubTable.hh" |
6 | |
7 | namespace OT { |
8 | namespace Layout { |
9 | namespace GSUB_impl { |
10 | |
11 | struct 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 | |