/src/harfbuzz/src/hb-subset-plan-layout.cc
Line | Count | Source |
1 | | /* |
2 | | * Copyright © 2023 Google, Inc. |
3 | | * |
4 | | * This is part of HarfBuzz, a text shaping library. |
5 | | * |
6 | | * Permission is hereby granted, without written agreement and without |
7 | | * license or royalty fees, to use, copy, modify, and distribute this |
8 | | * software and its documentation for any purpose, provided that the |
9 | | * above copyright notice and the following two paragraphs appear in |
10 | | * all copies of this software. |
11 | | * |
12 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | | * DAMAGE. |
17 | | * |
18 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | | * |
24 | | * Google Author(s): Garret Rieger, Qunxin Liu, Roderick Sheeter |
25 | | */ |
26 | | |
27 | | #include "hb-subset-plan.hh" |
28 | | |
29 | | #include "hb-ot-layout-gdef-table.hh" |
30 | | #include "hb-ot-layout-gpos-table.hh" |
31 | | #include "hb-ot-layout-gsub-table.hh" |
32 | | |
33 | | using OT::Layout::GSUB; |
34 | | using OT::Layout::GPOS; |
35 | | |
36 | | #ifndef HB_NO_SUBSET_LAYOUT |
37 | | |
38 | | void |
39 | | remap_used_mark_sets (hb_subset_plan_t *plan, |
40 | | hb_map_t& used_mark_sets_map) |
41 | 38.3k | { |
42 | 38.3k | hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> (); |
43 | | |
44 | 38.3k | if (!gdef->has_data () || !gdef->has_mark_glyph_sets ()) |
45 | 34.9k | { |
46 | 34.9k | gdef.destroy (); |
47 | 34.9k | return; |
48 | 34.9k | } |
49 | | |
50 | 3.43k | hb_set_t used_mark_sets; |
51 | 3.43k | gdef->get_mark_glyph_sets ().collect_used_mark_sets (plan->_glyphset_gsub, used_mark_sets); |
52 | 3.43k | gdef.destroy (); |
53 | | |
54 | 3.43k | remap_indexes (&used_mark_sets, &used_mark_sets_map); |
55 | 3.43k | } |
56 | | |
57 | | /* |
58 | | * Removes all tags from 'tags' that are not in filter. Additionally eliminates any duplicates. |
59 | | * Returns true if anything was removed (not including duplicates). |
60 | | */ |
61 | | static bool _filter_tag_list(hb_vector_t<hb_tag_t>* tags, /* IN/OUT */ |
62 | | const hb_set_t* filter) |
63 | 155k | { |
64 | 155k | hb_vector_t<hb_tag_t> out; |
65 | 155k | out.alloc (tags->get_size() + 1); // +1 is to allocate room for the null terminator. |
66 | | |
67 | 155k | bool removed = false; |
68 | 155k | hb_set_t visited; |
69 | | |
70 | 155k | for (hb_tag_t tag : *tags) |
71 | 639k | { |
72 | 639k | if (!tag) continue; |
73 | 111k | if (visited.has (tag)) continue; |
74 | | |
75 | 103k | if (!filter->has (tag)) |
76 | 18.6k | { |
77 | 18.6k | removed = true; |
78 | 18.6k | continue; |
79 | 18.6k | } |
80 | | |
81 | 84.5k | visited.add (tag); |
82 | 84.5k | out.push (tag); |
83 | 84.5k | } |
84 | | |
85 | | // The collect function needs a null element to signal end of the array. |
86 | 155k | out.push (HB_TAG_NONE); |
87 | | |
88 | 155k | hb_swap (out, *tags); |
89 | 155k | return removed; |
90 | 155k | } |
91 | | |
92 | | template <typename T> |
93 | | static void _collect_layout_indices (hb_subset_plan_t *plan, |
94 | | const T& table, |
95 | | hb_set_t *lookup_indices, /* OUT */ |
96 | | hb_set_t *feature_indices, /* OUT */ |
97 | | hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */ |
98 | | hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, /* OUT */ |
99 | | hb_set_t& catch_all_record_feature_idxes, /* OUT */ |
100 | | hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map /* OUT */) |
101 | 78.0k | { |
102 | 78.0k | unsigned num_features = table.get_feature_count (); |
103 | 78.0k | hb_vector_t<hb_tag_t> features; |
104 | 78.0k | if (!plan->check_success (features.resize (num_features))) return; |
105 | 77.7k | table.get_feature_tags (0, &num_features, features.arrayZ); |
106 | 77.7k | bool retain_all_features = !_filter_tag_list (&features, &plan->layout_features); |
107 | | |
108 | 77.7k | unsigned num_scripts = table.get_script_count (); |
109 | 77.7k | hb_vector_t<hb_tag_t> scripts; |
110 | 77.7k | if (!plan->check_success (scripts.resize (num_scripts))) return; |
111 | 77.7k | table.get_script_tags (0, &num_scripts, scripts.arrayZ); |
112 | 77.7k | bool retain_all_scripts = !_filter_tag_list (&scripts, &plan->layout_scripts); |
113 | | |
114 | 77.7k | if (!plan->check_success (!features.in_error ()) || !features |
115 | 77.3k | || !plan->check_success (!scripts.in_error ()) || !scripts) |
116 | 620 | return; |
117 | | |
118 | 77.0k | hb_ot_layout_collect_features (plan->source, |
119 | 77.0k | T::tableTag, |
120 | 77.0k | retain_all_scripts ? nullptr : scripts.arrayZ, |
121 | 77.0k | nullptr, |
122 | 77.0k | retain_all_features ? nullptr : features.arrayZ, |
123 | 77.0k | feature_indices); |
124 | | |
125 | 77.0k | #ifndef HB_NO_VAR |
126 | | // collect feature substitutes with variations |
127 | 77.0k | if (!plan->user_axes_location.is_empty ()) |
128 | 4.81k | { |
129 | 4.81k | hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map; |
130 | 4.81k | OT::hb_collect_feature_substitutes_with_var_context_t c = |
131 | 4.81k | { |
132 | 4.81k | &plan->axes_old_index_tag_map, |
133 | 4.81k | &plan->axes_location, |
134 | 4.81k | feature_record_cond_idx_map, |
135 | 4.81k | feature_substitutes_map, |
136 | 4.81k | catch_all_record_feature_idxes, |
137 | 4.81k | feature_indices, |
138 | 4.81k | false, |
139 | 4.81k | false, |
140 | 4.81k | false, |
141 | 4.81k | 0, |
142 | 4.81k | &conditionset_map |
143 | 4.81k | }; |
144 | 4.81k | table.collect_feature_substitutes_with_variations (&c); |
145 | 4.81k | } |
146 | 77.0k | #endif |
147 | | |
148 | 77.0k | for (unsigned feature_index : *feature_indices) |
149 | 387k | { |
150 | 387k | const OT::Feature* f = &(table.get_feature (feature_index)); |
151 | 387k | const OT::Feature **p = nullptr; |
152 | 387k | if (feature_substitutes_map->has (feature_index, &p)) |
153 | 0 | f = *p; |
154 | | |
155 | 387k | f->add_lookup_indexes_to (lookup_indices); |
156 | 387k | } |
157 | | |
158 | 77.0k | #ifndef HB_NO_VAR |
159 | 77.0k | if (catch_all_record_feature_idxes) |
160 | 0 | { |
161 | 0 | for (unsigned feature_index : catch_all_record_feature_idxes) |
162 | 0 | { |
163 | 0 | const OT::Feature& f = table.get_feature (feature_index); |
164 | 0 | f.add_lookup_indexes_to (lookup_indices); |
165 | 0 | const void *tag = reinterpret_cast<const void*> (&(table.get_feature_list ().get_tag (feature_index))); |
166 | 0 | catch_all_record_idx_feature_map.set (feature_index, hb_pair (&f, tag)); |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | | // If all axes are pinned then all feature variations will be dropped so there's no need |
171 | | // to collect lookups from them. |
172 | 77.0k | if (!plan->all_axes_pinned) |
173 | 75.8k | table.feature_variation_collect_lookups (feature_indices, |
174 | 75.8k | plan->user_axes_location.is_empty () ? nullptr: feature_record_cond_idx_map, |
175 | 75.8k | lookup_indices); |
176 | 77.0k | #endif |
177 | 77.0k | } hb-subset-plan-layout.cc:void _collect_layout_indices<OT::Layout::GSUB>(hb_subset_plan_t*, OT::Layout::GSUB const&, hb_set_t*, hb_set_t*, hb_hashmap_t<unsigned int, hb::shared_ptr<hb_set_t>, false>*, hb_hashmap_t<unsigned int, OT::Feature const*, false>*, hb_set_t&, hb_hashmap_t<unsigned int, hb_pair_t<void const*, void const*>, false>&) Line | Count | Source | 101 | 39.0k | { | 102 | 39.0k | unsigned num_features = table.get_feature_count (); | 103 | 39.0k | hb_vector_t<hb_tag_t> features; | 104 | 39.0k | if (!plan->check_success (features.resize (num_features))) return; | 105 | 39.0k | table.get_feature_tags (0, &num_features, features.arrayZ); | 106 | 39.0k | bool retain_all_features = !_filter_tag_list (&features, &plan->layout_features); | 107 | | | 108 | 39.0k | unsigned num_scripts = table.get_script_count (); | 109 | 39.0k | hb_vector_t<hb_tag_t> scripts; | 110 | 39.0k | if (!plan->check_success (scripts.resize (num_scripts))) return; | 111 | 39.0k | table.get_script_tags (0, &num_scripts, scripts.arrayZ); | 112 | 39.0k | bool retain_all_scripts = !_filter_tag_list (&scripts, &plan->layout_scripts); | 113 | | | 114 | 39.0k | if (!plan->check_success (!features.in_error ()) || !features | 115 | 38.8k | || !plan->check_success (!scripts.in_error ()) || !scripts) | 116 | 308 | return; | 117 | | | 118 | 38.7k | hb_ot_layout_collect_features (plan->source, | 119 | 38.7k | T::tableTag, | 120 | 38.7k | retain_all_scripts ? nullptr : scripts.arrayZ, | 121 | 38.7k | nullptr, | 122 | 38.7k | retain_all_features ? nullptr : features.arrayZ, | 123 | 38.7k | feature_indices); | 124 | | | 125 | 38.7k | #ifndef HB_NO_VAR | 126 | | // collect feature substitutes with variations | 127 | 38.7k | if (!plan->user_axes_location.is_empty ()) | 128 | 2.40k | { | 129 | 2.40k | hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map; | 130 | 2.40k | OT::hb_collect_feature_substitutes_with_var_context_t c = | 131 | 2.40k | { | 132 | 2.40k | &plan->axes_old_index_tag_map, | 133 | 2.40k | &plan->axes_location, | 134 | 2.40k | feature_record_cond_idx_map, | 135 | 2.40k | feature_substitutes_map, | 136 | 2.40k | catch_all_record_feature_idxes, | 137 | 2.40k | feature_indices, | 138 | 2.40k | false, | 139 | 2.40k | false, | 140 | 2.40k | false, | 141 | 2.40k | 0, | 142 | 2.40k | &conditionset_map | 143 | 2.40k | }; | 144 | 2.40k | table.collect_feature_substitutes_with_variations (&c); | 145 | 2.40k | } | 146 | 38.7k | #endif | 147 | | | 148 | 38.7k | for (unsigned feature_index : *feature_indices) | 149 | 229k | { | 150 | 229k | const OT::Feature* f = &(table.get_feature (feature_index)); | 151 | 229k | const OT::Feature **p = nullptr; | 152 | 229k | if (feature_substitutes_map->has (feature_index, &p)) | 153 | 0 | f = *p; | 154 | | | 155 | 229k | f->add_lookup_indexes_to (lookup_indices); | 156 | 229k | } | 157 | | | 158 | 38.7k | #ifndef HB_NO_VAR | 159 | 38.7k | if (catch_all_record_feature_idxes) | 160 | 0 | { | 161 | 0 | for (unsigned feature_index : catch_all_record_feature_idxes) | 162 | 0 | { | 163 | 0 | const OT::Feature& f = table.get_feature (feature_index); | 164 | 0 | f.add_lookup_indexes_to (lookup_indices); | 165 | 0 | const void *tag = reinterpret_cast<const void*> (&(table.get_feature_list ().get_tag (feature_index))); | 166 | 0 | catch_all_record_idx_feature_map.set (feature_index, hb_pair (&f, tag)); | 167 | 0 | } | 168 | 0 | } | 169 | | | 170 | | // If all axes are pinned then all feature variations will be dropped so there's no need | 171 | | // to collect lookups from them. | 172 | 38.7k | if (!plan->all_axes_pinned) | 173 | 38.1k | table.feature_variation_collect_lookups (feature_indices, | 174 | 38.1k | plan->user_axes_location.is_empty () ? nullptr: feature_record_cond_idx_map, | 175 | 38.1k | lookup_indices); | 176 | 38.7k | #endif | 177 | 38.7k | } |
hb-subset-plan-layout.cc:void _collect_layout_indices<OT::Layout::GPOS>(hb_subset_plan_t*, OT::Layout::GPOS const&, hb_set_t*, hb_set_t*, hb_hashmap_t<unsigned int, hb::shared_ptr<hb_set_t>, false>*, hb_hashmap_t<unsigned int, OT::Feature const*, false>*, hb_set_t&, hb_hashmap_t<unsigned int, hb_pair_t<void const*, void const*>, false>&) Line | Count | Source | 101 | 39.0k | { | 102 | 39.0k | unsigned num_features = table.get_feature_count (); | 103 | 39.0k | hb_vector_t<hb_tag_t> features; | 104 | 39.0k | if (!plan->check_success (features.resize (num_features))) return; | 105 | 38.6k | table.get_feature_tags (0, &num_features, features.arrayZ); | 106 | 38.6k | bool retain_all_features = !_filter_tag_list (&features, &plan->layout_features); | 107 | | | 108 | 38.6k | unsigned num_scripts = table.get_script_count (); | 109 | 38.6k | hb_vector_t<hb_tag_t> scripts; | 110 | 38.6k | if (!plan->check_success (scripts.resize (num_scripts))) return; | 111 | 38.6k | table.get_script_tags (0, &num_scripts, scripts.arrayZ); | 112 | 38.6k | bool retain_all_scripts = !_filter_tag_list (&scripts, &plan->layout_scripts); | 113 | | | 114 | 38.6k | if (!plan->check_success (!features.in_error ()) || !features | 115 | 38.5k | || !plan->check_success (!scripts.in_error ()) || !scripts) | 116 | 312 | return; | 117 | | | 118 | 38.3k | hb_ot_layout_collect_features (plan->source, | 119 | 38.3k | T::tableTag, | 120 | 38.3k | retain_all_scripts ? nullptr : scripts.arrayZ, | 121 | 38.3k | nullptr, | 122 | 38.3k | retain_all_features ? nullptr : features.arrayZ, | 123 | 38.3k | feature_indices); | 124 | | | 125 | 38.3k | #ifndef HB_NO_VAR | 126 | | // collect feature substitutes with variations | 127 | 38.3k | if (!plan->user_axes_location.is_empty ()) | 128 | 2.40k | { | 129 | 2.40k | hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map; | 130 | 2.40k | OT::hb_collect_feature_substitutes_with_var_context_t c = | 131 | 2.40k | { | 132 | 2.40k | &plan->axes_old_index_tag_map, | 133 | 2.40k | &plan->axes_location, | 134 | 2.40k | feature_record_cond_idx_map, | 135 | 2.40k | feature_substitutes_map, | 136 | 2.40k | catch_all_record_feature_idxes, | 137 | 2.40k | feature_indices, | 138 | 2.40k | false, | 139 | 2.40k | false, | 140 | 2.40k | false, | 141 | 2.40k | 0, | 142 | 2.40k | &conditionset_map | 143 | 2.40k | }; | 144 | 2.40k | table.collect_feature_substitutes_with_variations (&c); | 145 | 2.40k | } | 146 | 38.3k | #endif | 147 | | | 148 | 38.3k | for (unsigned feature_index : *feature_indices) | 149 | 157k | { | 150 | 157k | const OT::Feature* f = &(table.get_feature (feature_index)); | 151 | 157k | const OT::Feature **p = nullptr; | 152 | 157k | if (feature_substitutes_map->has (feature_index, &p)) | 153 | 0 | f = *p; | 154 | | | 155 | 157k | f->add_lookup_indexes_to (lookup_indices); | 156 | 157k | } | 157 | | | 158 | 38.3k | #ifndef HB_NO_VAR | 159 | 38.3k | if (catch_all_record_feature_idxes) | 160 | 0 | { | 161 | 0 | for (unsigned feature_index : catch_all_record_feature_idxes) | 162 | 0 | { | 163 | 0 | const OT::Feature& f = table.get_feature (feature_index); | 164 | 0 | f.add_lookup_indexes_to (lookup_indices); | 165 | 0 | const void *tag = reinterpret_cast<const void*> (&(table.get_feature_list ().get_tag (feature_index))); | 166 | 0 | catch_all_record_idx_feature_map.set (feature_index, hb_pair (&f, tag)); | 167 | 0 | } | 168 | 0 | } | 169 | | | 170 | | // If all axes are pinned then all feature variations will be dropped so there's no need | 171 | | // to collect lookups from them. | 172 | 38.3k | if (!plan->all_axes_pinned) | 173 | 37.7k | table.feature_variation_collect_lookups (feature_indices, | 174 | 37.7k | plan->user_axes_location.is_empty () ? nullptr: feature_record_cond_idx_map, | 175 | 37.7k | lookup_indices); | 176 | 38.3k | #endif | 177 | 38.3k | } |
|
178 | | |
179 | | |
180 | | static inline void |
181 | | _GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g, |
182 | | const hb_map_t *lookup_indices, |
183 | | const hb_set_t *feature_indices, |
184 | | const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, |
185 | | hb_map_t *duplicate_feature_map /* OUT */) |
186 | 78.0k | { |
187 | 78.0k | if (feature_indices->is_empty ()) return; |
188 | 13.6k | hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features; |
189 | | //find out duplicate features after subset |
190 | 13.6k | for (unsigned i : feature_indices->iter ()) |
191 | 29.3k | { |
192 | 29.3k | hb_tag_t t = g.get_feature_tag (i); |
193 | 29.3k | if (t == HB_MAP_VALUE_INVALID) continue; |
194 | 29.3k | if (!unique_features.has (t)) |
195 | 20.5k | { |
196 | 20.5k | if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()}))) |
197 | 50 | return; |
198 | 20.5k | if (unique_features.has (t)) |
199 | 20.5k | unique_features.get (t)->add (i); |
200 | 20.5k | duplicate_feature_map->set (i, i); |
201 | 20.5k | continue; |
202 | 20.5k | } |
203 | | |
204 | 8.73k | bool found = false; |
205 | | |
206 | 8.73k | hb_set_t* same_tag_features = unique_features.get (t); |
207 | 8.73k | for (unsigned other_f_index : same_tag_features->iter ()) |
208 | 8.35k | { |
209 | 8.35k | const OT::Feature* f = &(g.get_feature (i)); |
210 | 8.35k | const OT::Feature **p = nullptr; |
211 | 8.35k | if (feature_substitutes_map->has (i, &p)) |
212 | 0 | f = *p; |
213 | | |
214 | 8.35k | const OT::Feature* other_f = &(g.get_feature (other_f_index)); |
215 | 8.35k | if (feature_substitutes_map->has (other_f_index, &p)) |
216 | 0 | other_f = *p; |
217 | | |
218 | 8.35k | auto f_iter = |
219 | 8.35k | + hb_iter (f->lookupIndex) |
220 | 8.35k | | hb_filter (lookup_indices) |
221 | 8.35k | ; |
222 | | |
223 | 8.35k | auto other_f_iter = |
224 | 8.35k | + hb_iter (other_f->lookupIndex) |
225 | 8.35k | | hb_filter (lookup_indices) |
226 | 8.35k | ; |
227 | | |
228 | 8.35k | bool is_equal = true; |
229 | 105k | for (; f_iter && other_f_iter; f_iter++, other_f_iter++) |
230 | 97.1k | { |
231 | 97.1k | unsigned a = *f_iter; |
232 | 97.1k | unsigned b = *other_f_iter; |
233 | 97.1k | if (a != b) { is_equal = false; break; } |
234 | 97.1k | } |
235 | | |
236 | 8.35k | if (is_equal == false || f_iter || other_f_iter) continue; |
237 | | |
238 | 7.91k | found = true; |
239 | 7.91k | duplicate_feature_map->set (i, other_f_index); |
240 | 7.91k | break; |
241 | 8.35k | } |
242 | | |
243 | 8.73k | if (found == false) |
244 | 819 | { |
245 | 819 | same_tag_features->add (i); |
246 | 819 | duplicate_feature_map->set (i, i); |
247 | 819 | } |
248 | 8.73k | } |
249 | 13.6k | } |
250 | | |
251 | | static void |
252 | | remap_feature_indices (const hb_set_t &feature_indices, |
253 | | const hb_map_t &duplicate_feature_map, |
254 | | const hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map, |
255 | | hb_map_t *mapping, /* OUT */ |
256 | | hb_map_t *mapping_w_duplicates /* OUT */) |
257 | 78.0k | { |
258 | 78.0k | unsigned i = 0; |
259 | 78.0k | for (const auto _ : feature_indices) |
260 | 21.7k | { |
261 | | // retain those features in case we need to insert a catch-all record to reinstate the old features |
262 | 21.7k | if (catch_all_record_idx_feature_map.has (_)) |
263 | 0 | { |
264 | 0 | mapping->set (_, i); |
265 | 0 | mapping_w_duplicates->set (_, i); |
266 | 0 | i++; |
267 | 0 | } |
268 | 21.7k | else |
269 | 21.7k | { |
270 | 21.7k | uint32_t f_idx = duplicate_feature_map.get (_); |
271 | 21.7k | uint32_t *new_idx; |
272 | 21.7k | if (mapping-> has (f_idx, &new_idx)) |
273 | 1.59k | { |
274 | 1.59k | mapping_w_duplicates->set (_, *new_idx); |
275 | 1.59k | } |
276 | 20.1k | else |
277 | 20.1k | { |
278 | 20.1k | mapping->set (_, i); |
279 | 20.1k | mapping_w_duplicates->set (_, i); |
280 | 20.1k | i++; |
281 | 20.1k | } |
282 | 21.7k | } |
283 | 21.7k | } |
284 | 78.0k | } |
285 | | |
286 | | template <typename T> |
287 | | static void |
288 | | _closure_glyphs_lookups_features (hb_subset_plan_t *plan, |
289 | | hb_set_t *gids_to_retain, |
290 | | hb_map_t *lookups, |
291 | | hb_map_t *features, |
292 | | hb_map_t *features_w_duplicates, |
293 | | script_langsys_map *langsys_map, |
294 | | hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, |
295 | | hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, |
296 | | hb_set_t &catch_all_record_feature_idxes, |
297 | | hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map) |
298 | 78.0k | { |
299 | 78.0k | hb_blob_ptr_t<T> table = plan->source_table<T> (); |
300 | 78.0k | hb_tag_t table_tag = table->tableTag; |
301 | 78.0k | hb_set_t lookup_indices, feature_indices; |
302 | 78.0k | _collect_layout_indices<T> (plan, |
303 | 78.0k | *table, |
304 | 78.0k | &lookup_indices, |
305 | 78.0k | &feature_indices, |
306 | 78.0k | feature_record_cond_idx_map, |
307 | 78.0k | feature_substitutes_map, |
308 | 78.0k | catch_all_record_feature_idxes, |
309 | 78.0k | catch_all_record_idx_feature_map); |
310 | | |
311 | 78.0k | if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE)) |
312 | 32.9k | hb_ot_layout_lookups_substitute_closure (plan->source, |
313 | 32.9k | &lookup_indices, |
314 | 32.9k | gids_to_retain); |
315 | 78.0k | table->closure_lookups (plan->source, |
316 | 78.0k | gids_to_retain, |
317 | 78.0k | &lookup_indices); |
318 | 78.0k | remap_indexes (&lookup_indices, lookups); |
319 | | |
320 | | // prune features |
321 | 78.0k | table->prune_features (lookups, |
322 | 78.0k | plan->user_axes_location.is_empty () ? nullptr : feature_record_cond_idx_map, |
323 | 78.0k | feature_substitutes_map, |
324 | 78.0k | &feature_indices); |
325 | 78.0k | hb_map_t duplicate_feature_map; |
326 | 78.0k | _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map); |
327 | | |
328 | 78.0k | feature_indices.clear (); |
329 | 78.0k | table->prune_langsys (&duplicate_feature_map, &plan->layout_scripts, langsys_map, &feature_indices); |
330 | 78.0k | remap_feature_indices (feature_indices, duplicate_feature_map, catch_all_record_idx_feature_map, features, features_w_duplicates); |
331 | | |
332 | 78.0k | table.destroy (); |
333 | 78.0k | } hb-subset-plan-layout.cc:void _closure_glyphs_lookups_features<OT::Layout::GSUB>(hb_subset_plan_t*, hb_set_t*, hb_map_t*, hb_map_t*, hb_map_t*, hb_hashmap_t<unsigned int, hb::unique_ptr<hb_set_t>, false>*, hb_hashmap_t<unsigned int, hb::shared_ptr<hb_set_t>, false>*, hb_hashmap_t<unsigned int, OT::Feature const*, false>*, hb_set_t&, hb_hashmap_t<unsigned int, hb_pair_t<void const*, void const*>, false>&) Line | Count | Source | 298 | 39.0k | { | 299 | 39.0k | hb_blob_ptr_t<T> table = plan->source_table<T> (); | 300 | 39.0k | hb_tag_t table_tag = table->tableTag; | 301 | 39.0k | hb_set_t lookup_indices, feature_indices; | 302 | 39.0k | _collect_layout_indices<T> (plan, | 303 | 39.0k | *table, | 304 | 39.0k | &lookup_indices, | 305 | 39.0k | &feature_indices, | 306 | 39.0k | feature_record_cond_idx_map, | 307 | 39.0k | feature_substitutes_map, | 308 | 39.0k | catch_all_record_feature_idxes, | 309 | 39.0k | catch_all_record_idx_feature_map); | 310 | | | 311 | 39.0k | if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE)) | 312 | 32.9k | hb_ot_layout_lookups_substitute_closure (plan->source, | 313 | 32.9k | &lookup_indices, | 314 | 32.9k | gids_to_retain); | 315 | 39.0k | table->closure_lookups (plan->source, | 316 | 39.0k | gids_to_retain, | 317 | 39.0k | &lookup_indices); | 318 | 39.0k | remap_indexes (&lookup_indices, lookups); | 319 | | | 320 | | // prune features | 321 | 39.0k | table->prune_features (lookups, | 322 | 39.0k | plan->user_axes_location.is_empty () ? nullptr : feature_record_cond_idx_map, | 323 | 39.0k | feature_substitutes_map, | 324 | 39.0k | &feature_indices); | 325 | 39.0k | hb_map_t duplicate_feature_map; | 326 | 39.0k | _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map); | 327 | | | 328 | 39.0k | feature_indices.clear (); | 329 | 39.0k | table->prune_langsys (&duplicate_feature_map, &plan->layout_scripts, langsys_map, &feature_indices); | 330 | 39.0k | remap_feature_indices (feature_indices, duplicate_feature_map, catch_all_record_idx_feature_map, features, features_w_duplicates); | 331 | | | 332 | 39.0k | table.destroy (); | 333 | 39.0k | } |
hb-subset-plan-layout.cc:void _closure_glyphs_lookups_features<OT::Layout::GPOS>(hb_subset_plan_t*, hb_set_t*, hb_map_t*, hb_map_t*, hb_map_t*, hb_hashmap_t<unsigned int, hb::unique_ptr<hb_set_t>, false>*, hb_hashmap_t<unsigned int, hb::shared_ptr<hb_set_t>, false>*, hb_hashmap_t<unsigned int, OT::Feature const*, false>*, hb_set_t&, hb_hashmap_t<unsigned int, hb_pair_t<void const*, void const*>, false>&) Line | Count | Source | 298 | 39.0k | { | 299 | 39.0k | hb_blob_ptr_t<T> table = plan->source_table<T> (); | 300 | 39.0k | hb_tag_t table_tag = table->tableTag; | 301 | 39.0k | hb_set_t lookup_indices, feature_indices; | 302 | 39.0k | _collect_layout_indices<T> (plan, | 303 | 39.0k | *table, | 304 | 39.0k | &lookup_indices, | 305 | 39.0k | &feature_indices, | 306 | 39.0k | feature_record_cond_idx_map, | 307 | 39.0k | feature_substitutes_map, | 308 | 39.0k | catch_all_record_feature_idxes, | 309 | 39.0k | catch_all_record_idx_feature_map); | 310 | | | 311 | 39.0k | if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE)) | 312 | 0 | hb_ot_layout_lookups_substitute_closure (plan->source, | 313 | 0 | &lookup_indices, | 314 | 0 | gids_to_retain); | 315 | 39.0k | table->closure_lookups (plan->source, | 316 | 39.0k | gids_to_retain, | 317 | 39.0k | &lookup_indices); | 318 | 39.0k | remap_indexes (&lookup_indices, lookups); | 319 | | | 320 | | // prune features | 321 | 39.0k | table->prune_features (lookups, | 322 | 39.0k | plan->user_axes_location.is_empty () ? nullptr : feature_record_cond_idx_map, | 323 | 39.0k | feature_substitutes_map, | 324 | 39.0k | &feature_indices); | 325 | 39.0k | hb_map_t duplicate_feature_map; | 326 | 39.0k | _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map); | 327 | | | 328 | 39.0k | feature_indices.clear (); | 329 | 39.0k | table->prune_langsys (&duplicate_feature_map, &plan->layout_scripts, langsys_map, &feature_indices); | 330 | 39.0k | remap_feature_indices (feature_indices, duplicate_feature_map, catch_all_record_idx_feature_map, features, features_w_duplicates); | 331 | | | 332 | 39.0k | table.destroy (); | 333 | 39.0k | } |
|
334 | | |
335 | | void layout_nameid_closure (hb_subset_plan_t* plan, |
336 | | hb_set_t* drop_tables) |
337 | 39.0k | { |
338 | 39.0k | if (!drop_tables->has (HB_OT_TAG_GPOS)) |
339 | 39.0k | { |
340 | 39.0k | hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> (); |
341 | 39.0k | gpos->collect_name_ids (&plan->gpos_features, &plan->name_ids); |
342 | 39.0k | gpos.destroy (); |
343 | 39.0k | } |
344 | 39.0k | if (!drop_tables->has (HB_OT_TAG_GSUB)) |
345 | 39.0k | { |
346 | 39.0k | hb_blob_ptr_t<GSUB> gsub = plan->source_table<GSUB> (); |
347 | 39.0k | gsub->collect_name_ids (&plan->gsub_features, &plan->name_ids); |
348 | 39.0k | gsub.destroy (); |
349 | 39.0k | } |
350 | 39.0k | } |
351 | | |
352 | | void |
353 | | layout_populate_gids_to_retain (hb_subset_plan_t* plan, |
354 | 39.0k | hb_set_t* drop_tables) { |
355 | 39.0k | if (!drop_tables->has (HB_OT_TAG_GSUB)) |
356 | | // closure all glyphs/lookups/features needed for GSUB substitutions. |
357 | 39.0k | _closure_glyphs_lookups_features<GSUB> ( |
358 | 39.0k | plan, |
359 | 39.0k | &plan->_glyphset_gsub, |
360 | 39.0k | &plan->gsub_lookups, |
361 | 39.0k | &plan->gsub_features, |
362 | 39.0k | &plan->gsub_features_w_duplicates, |
363 | 39.0k | &plan->gsub_langsys, |
364 | 39.0k | &plan->gsub_feature_record_cond_idx_map, |
365 | 39.0k | &plan->gsub_feature_substitutes_map, |
366 | 39.0k | plan->gsub_old_features, |
367 | 39.0k | plan->gsub_old_feature_idx_tag_map); |
368 | | |
369 | 39.0k | if (!drop_tables->has (HB_OT_TAG_GPOS)) |
370 | 39.0k | _closure_glyphs_lookups_features<GPOS> ( |
371 | 39.0k | plan, |
372 | 39.0k | &plan->_glyphset_gsub, |
373 | 39.0k | &plan->gpos_lookups, |
374 | 39.0k | &plan->gpos_features, |
375 | 39.0k | &plan->gpos_features_w_duplicates, |
376 | 39.0k | &plan->gpos_langsys, |
377 | 39.0k | &plan->gpos_feature_record_cond_idx_map, |
378 | 39.0k | &plan->gpos_feature_substitutes_map, |
379 | 39.0k | plan->gpos_old_features, |
380 | 39.0k | plan->gpos_old_feature_idx_tag_map); |
381 | 39.0k | } |
382 | | |
383 | | #ifndef HB_NO_VAR |
384 | | void |
385 | | collect_layout_variation_indices (hb_subset_plan_t* plan) |
386 | 39.0k | { |
387 | 39.0k | hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> (); |
388 | 39.0k | hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> (); |
389 | | |
390 | 39.0k | if (!gdef->has_data () || !gdef->has_var_store ()) |
391 | 35.0k | { |
392 | 35.0k | gdef.destroy (); |
393 | 35.0k | gpos.destroy (); |
394 | 35.0k | return; |
395 | 35.0k | } |
396 | | |
397 | 3.95k | hb_set_t varidx_set; |
398 | 3.95k | OT::hb_collect_variation_indices_context_t c (&varidx_set, |
399 | 3.95k | &plan->_glyphset_gsub, |
400 | 3.95k | &plan->gpos_lookups); |
401 | 3.95k | gdef->collect_variation_indices (&c); |
402 | | |
403 | 3.95k | if (hb_ot_layout_has_positioning (plan->source)) |
404 | 3.36k | gpos->collect_variation_indices (&c); |
405 | | |
406 | 3.95k | remap_variation_indices (gdef->get_var_store (), |
407 | 3.95k | varidx_set, plan->normalized_coords, |
408 | 3.95k | !plan->pinned_at_default, |
409 | 3.95k | plan->all_axes_pinned, |
410 | 3.95k | plan->layout_variation_idx_delta_map); |
411 | | |
412 | 3.95k | unsigned subtable_count = gdef->get_var_store ().get_sub_table_count (); |
413 | 3.95k | generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps); |
414 | | |
415 | 3.95k | gdef.destroy (); |
416 | 3.95k | gpos.destroy (); |
417 | 3.95k | } |
418 | | #endif |
419 | | |
420 | | #endif |