/work/workdir/UnpackedTarball/harfbuzz/src/hb-subset-input.cc
Line | Count | Source |
1 | | /* |
2 | | * Copyright © 2018 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, Rod Sheeter, Behdad Esfahbod |
25 | | */ |
26 | | |
27 | | #include "hb-subset-instancer-solver.hh" |
28 | | #include "hb-subset.hh" |
29 | | #include "hb-set.hh" |
30 | | #include "hb-utf.hh" |
31 | | |
32 | | |
33 | | hb_subset_input_t::hb_subset_input_t () |
34 | 15.5k | { |
35 | 15.5k | for (auto& set : sets_iter ()) |
36 | 124k | set = hb::shared_ptr<hb_set_t> (hb_set_create ()); |
37 | | |
38 | 15.5k | if (in_error ()) |
39 | 0 | return; |
40 | | |
41 | 15.5k | flags = HB_SUBSET_FLAGS_DEFAULT; |
42 | | |
43 | 15.5k | hb_set_add_range (sets.name_ids, 0, 6); |
44 | 15.5k | hb_set_add (sets.name_languages, 0x0409); |
45 | | |
46 | 15.5k | hb_tag_t default_drop_tables[] = { |
47 | | // Layout disabled by default |
48 | 15.5k | HB_TAG ('m', 'o', 'r', 'x'), |
49 | 15.5k | HB_TAG ('m', 'o', 'r', 't'), |
50 | 15.5k | HB_TAG ('k', 'e', 'r', 'x'), |
51 | 15.5k | HB_TAG ('k', 'e', 'r', 'n'), |
52 | | |
53 | | // Copied from fontTools: |
54 | 15.5k | HB_TAG ('J', 'S', 'T', 'F'), |
55 | 15.5k | HB_TAG ('D', 'S', 'I', 'G'), |
56 | 15.5k | HB_TAG ('E', 'B', 'D', 'T'), |
57 | 15.5k | HB_TAG ('E', 'B', 'L', 'C'), |
58 | 15.5k | HB_TAG ('E', 'B', 'S', 'C'), |
59 | 15.5k | HB_TAG ('S', 'V', 'G', ' '), |
60 | 15.5k | HB_TAG ('P', 'C', 'L', 'T'), |
61 | 15.5k | HB_TAG ('L', 'T', 'S', 'H'), |
62 | | // Graphite tables |
63 | 15.5k | HB_TAG ('F', 'e', 'a', 't'), |
64 | 15.5k | HB_TAG ('G', 'l', 'a', 't'), |
65 | 15.5k | HB_TAG ('G', 'l', 'o', 'c'), |
66 | 15.5k | HB_TAG ('S', 'i', 'l', 'f'), |
67 | 15.5k | HB_TAG ('S', 'i', 'l', 'l'), |
68 | 15.5k | }; |
69 | 15.5k | sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables)); |
70 | | |
71 | 15.5k | hb_tag_t default_no_subset_tables[] = { |
72 | 15.5k | HB_TAG ('g', 'a', 's', 'p'), |
73 | 15.5k | HB_TAG ('f', 'p', 'g', 'm'), |
74 | 15.5k | HB_TAG ('p', 'r', 'e', 'p'), |
75 | 15.5k | HB_TAG ('V', 'D', 'M', 'X'), |
76 | 15.5k | HB_TAG ('D', 'S', 'I', 'G'), |
77 | 15.5k | }; |
78 | 15.5k | sets.no_subset_tables->add_array (default_no_subset_tables, |
79 | 15.5k | ARRAY_LENGTH (default_no_subset_tables)); |
80 | | |
81 | | //copied from _layout_features_groups in fonttools |
82 | 15.5k | hb_tag_t default_layout_features[] = { |
83 | | // default shaper |
84 | | // common |
85 | 15.5k | HB_TAG ('r', 'v', 'r', 'n'), |
86 | 15.5k | HB_TAG ('c', 'c', 'm', 'p'), |
87 | 15.5k | HB_TAG ('l', 'i', 'g', 'a'), |
88 | 15.5k | HB_TAG ('l', 'o', 'c', 'l'), |
89 | 15.5k | HB_TAG ('m', 'a', 'r', 'k'), |
90 | 15.5k | HB_TAG ('m', 'k', 'm', 'k'), |
91 | 15.5k | HB_TAG ('r', 'l', 'i', 'g'), |
92 | | |
93 | | //fractions |
94 | 15.5k | HB_TAG ('f', 'r', 'a', 'c'), |
95 | 15.5k | HB_TAG ('n', 'u', 'm', 'r'), |
96 | 15.5k | HB_TAG ('d', 'n', 'o', 'm'), |
97 | | |
98 | | //horizontal |
99 | 15.5k | HB_TAG ('c', 'a', 'l', 't'), |
100 | 15.5k | HB_TAG ('c', 'l', 'i', 'g'), |
101 | 15.5k | HB_TAG ('c', 'u', 'r', 's'), |
102 | 15.5k | HB_TAG ('k', 'e', 'r', 'n'), |
103 | 15.5k | HB_TAG ('r', 'c', 'l', 't'), |
104 | | |
105 | | //vertical |
106 | 15.5k | HB_TAG ('v', 'a', 'l', 't'), |
107 | 15.5k | HB_TAG ('v', 'e', 'r', 't'), |
108 | 15.5k | HB_TAG ('v', 'k', 'r', 'n'), |
109 | 15.5k | HB_TAG ('v', 'p', 'a', 'l'), |
110 | 15.5k | HB_TAG ('v', 'r', 't', '2'), |
111 | | |
112 | | //ltr |
113 | 15.5k | HB_TAG ('l', 't', 'r', 'a'), |
114 | 15.5k | HB_TAG ('l', 't', 'r', 'm'), |
115 | | |
116 | | //rtl |
117 | 15.5k | HB_TAG ('r', 't', 'l', 'a'), |
118 | 15.5k | HB_TAG ('r', 't', 'l', 'm'), |
119 | | |
120 | | //random |
121 | 15.5k | HB_TAG ('r', 'a', 'n', 'd'), |
122 | | |
123 | | //justify |
124 | 15.5k | HB_TAG ('j', 'a', 'l', 't'), // HarfBuzz doesn't use; others might |
125 | | |
126 | | //East Asian spacing |
127 | 15.5k | HB_TAG ('c', 'h', 'w', 's'), |
128 | 15.5k | HB_TAG ('v', 'c', 'h', 'w'), |
129 | 15.5k | HB_TAG ('h', 'a', 'l', 't'), |
130 | 15.5k | HB_TAG ('v', 'h', 'a', 'l'), |
131 | 15.5k | HB_TAG ('p', 'a', 'l', 't'), |
132 | | |
133 | | //private |
134 | 15.5k | HB_TAG ('H', 'a', 'r', 'f'), |
135 | 15.5k | HB_TAG ('H', 'A', 'R', 'F'), |
136 | 15.5k | HB_TAG ('B', 'u', 'z', 'z'), |
137 | 15.5k | HB_TAG ('B', 'U', 'Z', 'Z'), |
138 | | |
139 | | //shapers |
140 | | |
141 | | //arabic |
142 | 15.5k | HB_TAG ('i', 'n', 'i', 't'), |
143 | 15.5k | HB_TAG ('m', 'e', 'd', 'i'), |
144 | 15.5k | HB_TAG ('f', 'i', 'n', 'a'), |
145 | 15.5k | HB_TAG ('i', 's', 'o', 'l'), |
146 | 15.5k | HB_TAG ('m', 'e', 'd', '2'), |
147 | 15.5k | HB_TAG ('f', 'i', 'n', '2'), |
148 | 15.5k | HB_TAG ('f', 'i', 'n', '3'), |
149 | 15.5k | HB_TAG ('c', 's', 'w', 'h'), |
150 | 15.5k | HB_TAG ('m', 's', 'e', 't'), |
151 | 15.5k | HB_TAG ('s', 't', 'c', 'h'), |
152 | | |
153 | | //hangul |
154 | 15.5k | HB_TAG ('l', 'j', 'm', 'o'), |
155 | 15.5k | HB_TAG ('v', 'j', 'm', 'o'), |
156 | 15.5k | HB_TAG ('t', 'j', 'm', 'o'), |
157 | | |
158 | | //tibetan |
159 | 15.5k | HB_TAG ('a', 'b', 'v', 's'), |
160 | 15.5k | HB_TAG ('b', 'l', 'w', 's'), |
161 | 15.5k | HB_TAG ('a', 'b', 'v', 'm'), |
162 | 15.5k | HB_TAG ('b', 'l', 'w', 'm'), |
163 | | |
164 | | //indic |
165 | 15.5k | HB_TAG ('n', 'u', 'k', 't'), |
166 | 15.5k | HB_TAG ('a', 'k', 'h', 'n'), |
167 | 15.5k | HB_TAG ('r', 'p', 'h', 'f'), |
168 | 15.5k | HB_TAG ('r', 'k', 'r', 'f'), |
169 | 15.5k | HB_TAG ('p', 'r', 'e', 'f'), |
170 | 15.5k | HB_TAG ('b', 'l', 'w', 'f'), |
171 | 15.5k | HB_TAG ('h', 'a', 'l', 'f'), |
172 | 15.5k | HB_TAG ('a', 'b', 'v', 'f'), |
173 | 15.5k | HB_TAG ('p', 's', 't', 'f'), |
174 | 15.5k | HB_TAG ('c', 'f', 'a', 'r'), |
175 | 15.5k | HB_TAG ('v', 'a', 't', 'u'), |
176 | 15.5k | HB_TAG ('c', 'j', 'c', 't'), |
177 | 15.5k | HB_TAG ('i', 'n', 'i', 't'), |
178 | 15.5k | HB_TAG ('p', 'r', 'e', 's'), |
179 | 15.5k | HB_TAG ('a', 'b', 'v', 's'), |
180 | 15.5k | HB_TAG ('b', 'l', 'w', 's'), |
181 | 15.5k | HB_TAG ('p', 's', 't', 's'), |
182 | 15.5k | HB_TAG ('h', 'a', 'l', 'n'), |
183 | 15.5k | HB_TAG ('d', 'i', 's', 't'), |
184 | 15.5k | HB_TAG ('a', 'b', 'v', 'm'), |
185 | 15.5k | HB_TAG ('b', 'l', 'w', 'm'), |
186 | 15.5k | }; |
187 | | |
188 | 15.5k | sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features)); |
189 | | |
190 | 15.5k | sets.layout_scripts->invert (); // Default to all scripts. |
191 | 15.5k | } |
192 | | |
193 | | /** |
194 | | * hb_subset_input_create_or_fail: |
195 | | * |
196 | | * Creates a new subset input object. |
197 | | * |
198 | | * Return value: (transfer full): New subset input, or `NULL` if failed. Destroy |
199 | | * with hb_subset_input_destroy(). |
200 | | * |
201 | | * Since: 1.8.0 |
202 | | **/ |
203 | | hb_subset_input_t * |
204 | | hb_subset_input_create_or_fail (void) |
205 | 15.5k | { |
206 | 15.5k | hb_subset_input_t *input = hb_object_create<hb_subset_input_t>(); |
207 | | |
208 | 15.5k | if (unlikely (!input)) |
209 | 0 | return nullptr; |
210 | | |
211 | 15.5k | if (input->in_error ()) |
212 | 0 | { |
213 | 0 | hb_subset_input_destroy (input); |
214 | 0 | return nullptr; |
215 | 0 | } |
216 | | |
217 | 15.5k | return input; |
218 | 15.5k | } |
219 | | |
220 | | /** |
221 | | * hb_subset_input_reference: (skip) |
222 | | * @input: a #hb_subset_input_t object. |
223 | | * |
224 | | * Increases the reference count on @input. |
225 | | * |
226 | | * Return value: @input. |
227 | | * |
228 | | * Since: 1.8.0 |
229 | | **/ |
230 | | hb_subset_input_t * |
231 | | hb_subset_input_reference (hb_subset_input_t *input) |
232 | 0 | { |
233 | 0 | return hb_object_reference (input); |
234 | 0 | } |
235 | | |
236 | | /** |
237 | | * hb_subset_input_destroy: |
238 | | * @input: a #hb_subset_input_t object. |
239 | | * |
240 | | * Decreases the reference count on @input, and if it reaches zero, destroys |
241 | | * @input, freeing all memory. |
242 | | * |
243 | | * Since: 1.8.0 |
244 | | **/ |
245 | | void |
246 | | hb_subset_input_destroy (hb_subset_input_t *input) |
247 | 15.5k | { |
248 | 15.5k | if (!hb_object_destroy (input)) return; |
249 | | |
250 | 15.5k | hb_free (input); |
251 | 15.5k | } |
252 | | |
253 | | /** |
254 | | * hb_subset_input_unicode_set: |
255 | | * @input: a #hb_subset_input_t object. |
256 | | * |
257 | | * Gets the set of Unicode code points to retain, the caller should modify the |
258 | | * set as needed. |
259 | | * |
260 | | * Return value: (transfer none): pointer to the #hb_set_t of Unicode code |
261 | | * points. |
262 | | * |
263 | | * Since: 1.8.0 |
264 | | **/ |
265 | | HB_EXTERN hb_set_t * |
266 | | hb_subset_input_unicode_set (hb_subset_input_t *input) |
267 | 0 | { |
268 | 0 | return input->sets.unicodes; |
269 | 0 | } |
270 | | |
271 | | /** |
272 | | * hb_subset_input_glyph_set: |
273 | | * @input: a #hb_subset_input_t object. |
274 | | * |
275 | | * Gets the set of glyph IDs to retain, the caller should modify the set as |
276 | | * needed. |
277 | | * |
278 | | * Return value: (transfer none): pointer to the #hb_set_t of glyph IDs. |
279 | | * |
280 | | * Since: 1.8.0 |
281 | | **/ |
282 | | HB_EXTERN hb_set_t * |
283 | | hb_subset_input_glyph_set (hb_subset_input_t *input) |
284 | 15.5k | { |
285 | 15.5k | return input->sets.glyphs; |
286 | 15.5k | } |
287 | | |
288 | | /** |
289 | | * hb_subset_input_set: |
290 | | * @input: a #hb_subset_input_t object. |
291 | | * @set_type: a #hb_subset_sets_t set type. |
292 | | * |
293 | | * Gets the set of the specified type. |
294 | | * |
295 | | * Return value: (transfer none): pointer to the #hb_set_t of the specified type. |
296 | | * |
297 | | * Since: 2.9.1 |
298 | | **/ |
299 | | HB_EXTERN hb_set_t * |
300 | | hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type) |
301 | 15.5k | { |
302 | 15.5k | return input->sets_iter () [set_type]; |
303 | 15.5k | } |
304 | | |
305 | | /** |
306 | | * hb_subset_input_get_flags: |
307 | | * @input: a #hb_subset_input_t object. |
308 | | * |
309 | | * Gets all of the subsetting flags in the input object. |
310 | | * |
311 | | * Return value: the subsetting flags bit field. |
312 | | * |
313 | | * Since: 2.9.0 |
314 | | **/ |
315 | | HB_EXTERN hb_subset_flags_t |
316 | | hb_subset_input_get_flags (hb_subset_input_t *input) |
317 | 0 | { |
318 | 0 | return (hb_subset_flags_t) input->flags; |
319 | 0 | } |
320 | | |
321 | | /** |
322 | | * hb_subset_input_set_flags: |
323 | | * @input: a #hb_subset_input_t object. |
324 | | * @value: bit field of flags |
325 | | * |
326 | | * Sets all of the flags in the input object to the values specified by the bit |
327 | | * field. |
328 | | * |
329 | | * Since: 2.9.0 |
330 | | **/ |
331 | | HB_EXTERN void |
332 | | hb_subset_input_set_flags (hb_subset_input_t *input, |
333 | | unsigned value) |
334 | 15.5k | { |
335 | 15.5k | input->flags = (hb_subset_flags_t) value; |
336 | 15.5k | } |
337 | | |
338 | | /** |
339 | | * hb_subset_input_set_user_data: (skip) |
340 | | * @input: a #hb_subset_input_t object. |
341 | | * @key: The user-data key to set |
342 | | * @data: A pointer to the user data |
343 | | * @destroy: (nullable): A callback to call when @data is not needed anymore |
344 | | * @replace: Whether to replace an existing data with the same key |
345 | | * |
346 | | * Attaches a user-data key/data pair to the given subset input object. |
347 | | * |
348 | | * Return value: `true` if success, `false` otherwise |
349 | | * |
350 | | * Since: 2.9.0 |
351 | | **/ |
352 | | hb_bool_t |
353 | | hb_subset_input_set_user_data (hb_subset_input_t *input, |
354 | | hb_user_data_key_t *key, |
355 | | void * data, |
356 | | hb_destroy_func_t destroy, |
357 | | hb_bool_t replace) |
358 | 0 | { |
359 | 0 | return hb_object_set_user_data (input, key, data, destroy, replace); |
360 | 0 | } |
361 | | |
362 | | /** |
363 | | * hb_subset_input_get_user_data: (skip) |
364 | | * @input: a #hb_subset_input_t object. |
365 | | * @key: The user-data key to query |
366 | | * |
367 | | * Fetches the user data associated with the specified key, |
368 | | * attached to the specified subset input object. |
369 | | * |
370 | | * Return value: (transfer none): A pointer to the user data |
371 | | * |
372 | | * Since: 2.9.0 |
373 | | **/ |
374 | | void * |
375 | | hb_subset_input_get_user_data (const hb_subset_input_t *input, |
376 | | hb_user_data_key_t *key) |
377 | 0 | { |
378 | 0 | return hb_object_get_user_data (input, key); |
379 | 0 | } |
380 | | |
381 | | /** |
382 | | * hb_subset_input_keep_everything: |
383 | | * @input: a #hb_subset_input_t object |
384 | | * |
385 | | * Configure input object to keep everything in the font face. |
386 | | * That is, all Unicodes, glyphs, names, layout items, |
387 | | * glyph names, etc. |
388 | | * |
389 | | * The input can be tailored afterwards by the caller. |
390 | | * |
391 | | * Since: 7.0.0 |
392 | | */ |
393 | | void |
394 | | hb_subset_input_keep_everything (hb_subset_input_t *input) |
395 | 0 | { |
396 | 0 | const hb_subset_sets_t indices[] = {HB_SUBSET_SETS_UNICODE, |
397 | 0 | HB_SUBSET_SETS_GLYPH_INDEX, |
398 | 0 | HB_SUBSET_SETS_NAME_ID, |
399 | 0 | HB_SUBSET_SETS_NAME_LANG_ID, |
400 | 0 | HB_SUBSET_SETS_LAYOUT_FEATURE_TAG, |
401 | 0 | HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG}; |
402 | |
|
403 | 0 | for (auto idx : hb_iter (indices)) |
404 | 0 | { |
405 | 0 | hb_set_t *set = hb_subset_input_set (input, idx); |
406 | 0 | hb_set_clear (set); |
407 | 0 | hb_set_invert (set); |
408 | 0 | } |
409 | | |
410 | | // Don't drop any tables |
411 | 0 | hb_set_clear (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG)); |
412 | |
|
413 | 0 | hb_subset_input_set_flags (input, |
414 | 0 | HB_SUBSET_FLAGS_NOTDEF_OUTLINE | |
415 | 0 | HB_SUBSET_FLAGS_GLYPH_NAMES | |
416 | 0 | HB_SUBSET_FLAGS_NAME_LEGACY | |
417 | 0 | HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES | |
418 | 0 | HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED); |
419 | 0 | } |
420 | | |
421 | | #ifndef HB_NO_VAR |
422 | | /** |
423 | | * hb_subset_input_pin_all_axes_to_default: (skip) |
424 | | * @input: a #hb_subset_input_t object. |
425 | | * @face: a #hb_face_t object. |
426 | | * |
427 | | * Pin all axes to default locations in the given subset input object. |
428 | | * |
429 | | * The `CFF2` table, if present, will be de-subroutinized. |
430 | | * |
431 | | * Return value: `true` if success, `false` otherwise |
432 | | * |
433 | | * Since: 8.3.1 |
434 | | **/ |
435 | | HB_EXTERN hb_bool_t |
436 | | hb_subset_input_pin_all_axes_to_default (hb_subset_input_t *input, |
437 | | hb_face_t *face) |
438 | 0 | { |
439 | 0 | unsigned axis_count = hb_ot_var_get_axis_count (face); |
440 | 0 | if (!axis_count) return false; |
441 | | |
442 | 0 | hb_ot_var_axis_info_t *axis_infos = (hb_ot_var_axis_info_t *) hb_calloc (axis_count, sizeof (hb_ot_var_axis_info_t)); |
443 | 0 | if (unlikely (!axis_infos)) return false; |
444 | | |
445 | 0 | (void) hb_ot_var_get_axis_infos (face, 0, &axis_count, axis_infos); |
446 | |
|
447 | 0 | for (unsigned i = 0; i < axis_count; i++) |
448 | 0 | { |
449 | 0 | hb_tag_t axis_tag = axis_infos[i].tag; |
450 | 0 | double default_val = (double) axis_infos[i].default_value; |
451 | 0 | if (!input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val))) |
452 | 0 | { |
453 | 0 | hb_free (axis_infos); |
454 | 0 | return false; |
455 | 0 | } |
456 | 0 | } |
457 | 0 | hb_free (axis_infos); |
458 | 0 | return true; |
459 | 0 | } |
460 | | |
461 | | /** |
462 | | * hb_subset_input_pin_axis_to_default: (skip) |
463 | | * @input: a #hb_subset_input_t object. |
464 | | * @face: a #hb_face_t object. |
465 | | * @axis_tag: Tag of the axis to be pinned |
466 | | * |
467 | | * Pin an axis to its default location in the given subset input object. |
468 | | * |
469 | | * The `CFF2` table, if present, will be de-subroutinized. |
470 | | * |
471 | | * Return value: `true` if success, `false` otherwise |
472 | | * |
473 | | * Since: 6.0.0 |
474 | | **/ |
475 | | HB_EXTERN hb_bool_t |
476 | | hb_subset_input_pin_axis_to_default (hb_subset_input_t *input, |
477 | | hb_face_t *face, |
478 | | hb_tag_t axis_tag) |
479 | 0 | { |
480 | 0 | hb_ot_var_axis_info_t axis_info; |
481 | 0 | if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) |
482 | 0 | return false; |
483 | | |
484 | 0 | double default_val = (double) axis_info.default_value; |
485 | 0 | return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)); |
486 | 0 | } |
487 | | |
488 | | /** |
489 | | * hb_subset_input_pin_axis_location: (skip) |
490 | | * @input: a #hb_subset_input_t object. |
491 | | * @face: a #hb_face_t object. |
492 | | * @axis_tag: Tag of the axis to be pinned |
493 | | * @axis_value: Location on the axis to be pinned at |
494 | | * |
495 | | * Pin an axis to a fixed location in the given subset input object. |
496 | | * |
497 | | * The `CFF2` table, if present, will be de-subroutinized. |
498 | | * |
499 | | * Return value: `true` if success, `false` otherwise |
500 | | * |
501 | | * Since: 6.0.0 |
502 | | **/ |
503 | | HB_EXTERN hb_bool_t |
504 | | hb_subset_input_pin_axis_location (hb_subset_input_t *input, |
505 | | hb_face_t *face, |
506 | | hb_tag_t axis_tag, |
507 | | float axis_value) |
508 | 0 | { |
509 | 0 | hb_ot_var_axis_info_t axis_info; |
510 | 0 | if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) |
511 | 0 | return false; |
512 | | |
513 | 0 | double val = hb_clamp((double) axis_value, (double) axis_info.min_value, (double) axis_info.max_value); |
514 | 0 | return input->axes_location.set (axis_tag, Triple (val, val, val)); |
515 | 0 | } |
516 | | |
517 | | /** |
518 | | * hb_subset_input_set_axis_range: (skip) |
519 | | * @input: a #hb_subset_input_t object. |
520 | | * @face: a #hb_face_t object. |
521 | | * @axis_tag: Tag of the axis |
522 | | * @axis_min_value: Minimum value of the axis variation range to set, if NaN the existing min will be used. |
523 | | * @axis_max_value: Maximum value of the axis variation range to set if NaN the existing max will be used. |
524 | | * @axis_def_value: Default value of the axis variation range to set, if NaN the existing default will be used. |
525 | | * |
526 | | * Restricting the range of variation on an axis in the given subset input object. |
527 | | * New min/default/max values will be clamped if they're not within the fvar axis range. |
528 | | * |
529 | | * If the fvar axis default value is not within the new range, the new default |
530 | | * value will be changed to the new min or max value, whichever is closer to the fvar |
531 | | * axis default. |
532 | | * |
533 | | * Note: input min value can not be bigger than input max value. If the input |
534 | | * default value is not within the new min/max range, it'll be clamped. |
535 | | * |
536 | | * Return value: `true` if success, `false` otherwise |
537 | | * |
538 | | * Since: 8.5.0 |
539 | | **/ |
540 | | HB_EXTERN hb_bool_t |
541 | | hb_subset_input_set_axis_range (hb_subset_input_t *input, |
542 | | hb_face_t *face, |
543 | | hb_tag_t axis_tag, |
544 | | float axis_min_value, |
545 | | float axis_max_value, |
546 | | float axis_def_value) |
547 | 0 | { |
548 | 0 | hb_ot_var_axis_info_t axis_info; |
549 | 0 | if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) |
550 | 0 | return false; |
551 | | |
552 | 0 | float min = !std::isnan(axis_min_value) ? axis_min_value : axis_info.min_value; |
553 | 0 | float max = !std::isnan(axis_max_value) ? axis_max_value : axis_info.max_value; |
554 | 0 | float def = !std::isnan(axis_def_value) ? axis_def_value : axis_info.default_value; |
555 | |
|
556 | 0 | if (min > max) |
557 | 0 | return false; |
558 | | |
559 | 0 | float new_min_val = hb_clamp(min, axis_info.min_value, axis_info.max_value); |
560 | 0 | float new_max_val = hb_clamp(max, axis_info.min_value, axis_info.max_value); |
561 | 0 | float new_default_val = hb_clamp(def, new_min_val, new_max_val); |
562 | 0 | return input->axes_location.set (axis_tag, Triple ((double) new_min_val, (double) new_default_val, (double) new_max_val)); |
563 | 0 | } |
564 | | |
565 | | /** |
566 | | * hb_subset_input_get_axis_range: (skip) |
567 | | * @input: a #hb_subset_input_t object. |
568 | | * @axis_tag: Tag of the axis |
569 | | * @axis_min_value: Set to the previously configured minimum value of the axis variation range. |
570 | | * @axis_max_value: Set to the previously configured maximum value of the axis variation range. |
571 | | * @axis_def_value: Set to the previously configured default value of the axis variation range. |
572 | | * |
573 | | * Gets the axis range assigned by previous calls to hb_subset_input_set_axis_range. |
574 | | * |
575 | | * Return value: `true` if a range has been set for this axis tag, `false` otherwise. |
576 | | * |
577 | | * Since: 8.5.0 |
578 | | **/ |
579 | | HB_EXTERN hb_bool_t |
580 | | hb_subset_input_get_axis_range (hb_subset_input_t *input, |
581 | | hb_tag_t axis_tag, |
582 | | float *axis_min_value, |
583 | | float *axis_max_value, |
584 | | float *axis_def_value) |
585 | | |
586 | 0 | { |
587 | 0 | Triple* triple; |
588 | 0 | if (!input->axes_location.has(axis_tag, &triple)) { |
589 | 0 | return false; |
590 | 0 | } |
591 | | |
592 | 0 | *axis_min_value = triple->minimum; |
593 | 0 | *axis_def_value = triple->middle; |
594 | 0 | *axis_max_value = triple->maximum; |
595 | 0 | return true; |
596 | 0 | } |
597 | | |
598 | | /** |
599 | | * hb_subset_axis_range_from_string: |
600 | | * @str: a string to parse |
601 | | * @len: length of @str, or -1 if str is NULL terminated |
602 | | * @axis_min_value: (out): the axis min value to initialize with the parsed value |
603 | | * @axis_max_value: (out): the axis max value to initialize with the parsed value |
604 | | * @axis_def_value: (out): the axis default value to initialize with the parse |
605 | | * value |
606 | | * |
607 | | * Parses a string into a subset axis range(min, def, max). |
608 | | * Axis positions string is in the format of min:def:max or min:max |
609 | | * When parsing axis positions, empty values as meaning the existing value for that part |
610 | | * E.g: :300:500 |
611 | | * Specifies min = existing, def = 300, max = 500 |
612 | | * In the output axis_range, if a value should be set to it's default value, |
613 | | * then it will be set to NaN |
614 | | * |
615 | | * Return value: |
616 | | * `true` if @str is successfully parsed, `false` otherwise |
617 | | * |
618 | | * Since: 10.2.0 |
619 | | */ |
620 | | HB_EXTERN hb_bool_t |
621 | | hb_subset_axis_range_from_string (const char *str, int len, |
622 | | float *axis_min_value, |
623 | | float *axis_max_value, |
624 | | float *axis_def_value) |
625 | 0 | { |
626 | 0 | if (len < 0) |
627 | 0 | len = strlen (str); |
628 | |
|
629 | 0 | const char *end = str + len; |
630 | 0 | const char* part = strpbrk (str, ":"); |
631 | 0 | if (!part) |
632 | 0 | { |
633 | | // Single value. |
634 | 0 | if (strcmp (str, "drop") == 0) |
635 | 0 | { |
636 | 0 | *axis_min_value = NAN; |
637 | 0 | *axis_def_value = NAN; |
638 | 0 | *axis_max_value = NAN; |
639 | 0 | return true; |
640 | 0 | } |
641 | | |
642 | 0 | double v; |
643 | 0 | if (!hb_parse_double (&str, end, &v)) return false; |
644 | | |
645 | 0 | *axis_min_value = v; |
646 | 0 | *axis_def_value = v; |
647 | 0 | *axis_max_value = v; |
648 | 0 | return true; |
649 | 0 | } |
650 | | |
651 | 0 | float values[3]; |
652 | 0 | int count = 0; |
653 | 0 | for (int i = 0; i < 3; i++) { |
654 | 0 | count++; |
655 | 0 | if (!*str || part == str) |
656 | 0 | { |
657 | 0 | values[i] = NAN; |
658 | |
|
659 | 0 | if (part == NULL) break; |
660 | 0 | str = part + 1; |
661 | 0 | part = strpbrk (str, ":"); |
662 | 0 | continue; |
663 | 0 | } |
664 | | |
665 | 0 | double v; |
666 | 0 | if (!hb_parse_double (&str, part, &v)) return false; |
667 | 0 | values[i] = v; |
668 | |
|
669 | 0 | if (part == NULL) break; |
670 | 0 | str = part + 1; |
671 | 0 | part = strpbrk (str, ":"); |
672 | 0 | } |
673 | | |
674 | 0 | if (count == 2) |
675 | 0 | { |
676 | 0 | *axis_min_value = values[0]; |
677 | 0 | *axis_def_value = NAN; |
678 | 0 | *axis_max_value = values[1]; |
679 | 0 | return true; |
680 | 0 | } |
681 | 0 | else if (count == 3) |
682 | 0 | { |
683 | 0 | *axis_min_value = values[0]; |
684 | 0 | *axis_def_value = values[1]; |
685 | 0 | *axis_max_value = values[2]; |
686 | 0 | return true; |
687 | 0 | } |
688 | 0 | return false; |
689 | 0 | } |
690 | | |
691 | | /** |
692 | | * hb_subset_axis_range_to_string: |
693 | | * @input: a #hb_subset_input_t object. |
694 | | * @axis_tag: an axis to convert |
695 | | * @buf: (array length=size) (out caller-allocates): output string |
696 | | * @size: the allocated size of @buf |
697 | | * |
698 | | * Converts an axis range into a `NULL`-terminated string in the format |
699 | | * understood by hb_subset_axis_range_from_string(). The client in responsible for |
700 | | * allocating big enough size for @buf, 128 bytes is more than enough. |
701 | | * |
702 | | * Since: 10.2.0 |
703 | | */ |
704 | | HB_EXTERN void |
705 | | hb_subset_axis_range_to_string (hb_subset_input_t *input, |
706 | | hb_tag_t axis_tag, |
707 | | char *buf, unsigned size) |
708 | 0 | { |
709 | 0 | if (unlikely (!size)) return; |
710 | 0 | Triple* triple; |
711 | 0 | if (!input->axes_location.has(axis_tag, &triple)) { |
712 | 0 | return; |
713 | 0 | } |
714 | | |
715 | 0 | char s[128]; |
716 | 0 | unsigned len = 0; |
717 | |
|
718 | 0 | hb_locale_t clocale HB_UNUSED; |
719 | 0 | hb_locale_t oldlocale HB_UNUSED; |
720 | 0 | oldlocale = hb_uselocale (clocale = newlocale (LC_ALL_MASK, "C", NULL)); |
721 | 0 | len += hb_max (0, snprintf (s, ARRAY_LENGTH (s) - len, "%g", (double) triple->minimum)); |
722 | 0 | s[len++] = ':'; |
723 | |
|
724 | 0 | len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) triple->middle)); |
725 | 0 | s[len++] = ':'; |
726 | |
|
727 | 0 | len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) triple->maximum)); |
728 | 0 | (void) hb_uselocale (((void) freelocale (clocale), oldlocale)); |
729 | |
|
730 | 0 | assert (len < ARRAY_LENGTH (s)); |
731 | 0 | len = hb_min (len, size - 1); |
732 | 0 | hb_memcpy (buf, s, len); |
733 | 0 | buf[len] = '\0'; |
734 | 0 | } |
735 | | #endif |
736 | | |
737 | | #ifdef HB_EXPERIMENTAL_API |
738 | | static void |
739 | | _append_arg (hb_vector_t<char> &sb, const char *arg) |
740 | | { |
741 | | if (sb.in_error ()) return; |
742 | | if (sb.length) |
743 | | sb.push (' '); |
744 | | unsigned len = strlen (arg); |
745 | | sb.extend (hb_bytes_t (arg, len)); |
746 | | } |
747 | | static void |
748 | | _format_number_set (const hb_set_t *set, hb_vector_t<char> &out, unsigned base = 10) |
749 | | { |
750 | | assert (base == 10 || base == 16); |
751 | | if (unlikely (base != 10 && base != 16)) return; |
752 | | |
753 | | hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID; |
754 | | bool first_range = true; |
755 | | while (hb_set_next_range (set, &first, &last)) |
756 | | { |
757 | | if (!first_range) |
758 | | out.push (','); |
759 | | first_range = false; |
760 | | |
761 | | char buf[64]; |
762 | | int len; |
763 | | if (first == last) |
764 | | { |
765 | | if (base == 16) |
766 | | len = snprintf (buf, sizeof (buf), "%X", first); |
767 | | else |
768 | | len = snprintf (buf, sizeof (buf), "%u", first); |
769 | | } |
770 | | else |
771 | | { |
772 | | if (base == 16) |
773 | | len = snprintf (buf, sizeof (buf), "%X-%X", first, last); |
774 | | else |
775 | | len = snprintf (buf, sizeof (buf), "%u-%u", first, last); |
776 | | } |
777 | | if (unlikely (len < 0 || (size_t) len >= sizeof (buf))) return; |
778 | | out.extend (hb_bytes_t (buf, len)); |
779 | | } |
780 | | } |
781 | | |
782 | | static void |
783 | | _format_tag (hb_tag_t tag, hb_vector_t<char> &out) |
784 | | { |
785 | | char buf[4]; |
786 | | hb_tag_to_string (tag, buf); |
787 | | |
788 | | unsigned len = 4; |
789 | | while (len > 0 && buf[len - 1] == ' ') |
790 | | len--; |
791 | | |
792 | | for (unsigned i = 0; i < len; i++) |
793 | | { |
794 | | char c = buf[i]; |
795 | | if (!((c >= 'a' && c <= 'z') || |
796 | | (c >= 'A' && c <= 'Z') || |
797 | | (c >= '0' && c <= '9') || |
798 | | c == '-' || c == '_')) |
799 | | { |
800 | | c = '_'; |
801 | | } |
802 | | out.push (c); |
803 | | } |
804 | | } |
805 | | |
806 | | static void |
807 | | _format_tag_set (const hb_set_t *set, hb_vector_t<char> &out) |
808 | | { |
809 | | bool first_tag = true; |
810 | | for (hb_codepoint_t tag : *set) |
811 | | { |
812 | | if (!first_tag) |
813 | | out.push (','); |
814 | | first_tag = false; |
815 | | |
816 | | _format_tag (tag, out); |
817 | | } |
818 | | } |
819 | | |
820 | | static bool |
821 | | _is_set_default (const hb_set_t *set, const hb_set_t *default_set) |
822 | | { |
823 | | return hb_set_is_inverted (set) == hb_set_is_inverted (default_set) && |
824 | | hb_set_is_equal (set, default_set); |
825 | | } |
826 | | |
827 | | template <typename Formatter> |
828 | | static void |
829 | | _format_set_arg (const hb_set_t *set, |
830 | | const char *opt_name, |
831 | | Formatter &&formatter, |
832 | | hb_vector_t<char> &sb) |
833 | | { |
834 | | if (hb_set_is_inverted (set)) |
835 | | { |
836 | | hb_set_t *excluded = hb_set_copy (set); |
837 | | hb_set_invert (excluded); |
838 | | |
839 | | hb_vector_t<char> opt; |
840 | | opt.extend (hb_bytes_t ("--", 2)); |
841 | | opt.extend (hb_bytes_t (opt_name, strlen (opt_name))); |
842 | | opt.extend (hb_bytes_t ("=*", 2)); |
843 | | opt.push ('\0'); |
844 | | if (opt.arrayZ) _append_arg (sb, opt.arrayZ); |
845 | | |
846 | | if (!hb_set_is_empty (excluded)) |
847 | | { |
848 | | hb_vector_t<char> formatted; |
849 | | formatter (excluded, formatted); |
850 | | if (formatted.length) |
851 | | { |
852 | | hb_vector_t<char> opt2; |
853 | | opt2.extend (hb_bytes_t ("--", 2)); |
854 | | opt2.extend (hb_bytes_t (opt_name, strlen (opt_name))); |
855 | | opt2.extend (hb_bytes_t ("-=", 2)); |
856 | | opt2.extend (formatted.as_array ()); |
857 | | opt2.push ('\0'); |
858 | | if (opt2.arrayZ) _append_arg (sb, opt2.arrayZ); |
859 | | } |
860 | | } |
861 | | hb_set_destroy (excluded); |
862 | | } |
863 | | else if (hb_set_is_empty (set)) |
864 | | { |
865 | | hb_vector_t<char> opt; |
866 | | opt.extend (hb_bytes_t ("--", 2)); |
867 | | opt.extend (hb_bytes_t (opt_name, strlen (opt_name))); |
868 | | opt.extend (hb_bytes_t ("-=*", 3)); |
869 | | opt.push ('\0'); |
870 | | if (opt.arrayZ) _append_arg (sb, opt.arrayZ); |
871 | | } |
872 | | else |
873 | | { |
874 | | hb_vector_t<char> formatted; |
875 | | formatter (set, formatted); |
876 | | if (formatted.length) |
877 | | { |
878 | | hb_vector_t<char> opt; |
879 | | opt.extend (hb_bytes_t ("--", 2)); |
880 | | opt.extend (hb_bytes_t (opt_name, strlen (opt_name))); |
881 | | opt.extend (hb_bytes_t ("=", 1)); |
882 | | opt.extend (formatted.as_array ()); |
883 | | opt.push ('\0'); |
884 | | if (opt.arrayZ) _append_arg (sb, opt.arrayZ); |
885 | | } |
886 | | } |
887 | | } |
888 | | |
889 | | static void |
890 | | _format_number_set_arg (const hb_set_t *set, |
891 | | const char *opt_name, |
892 | | hb_vector_t<char> &sb, |
893 | | unsigned base = 10) |
894 | | { |
895 | | _format_set_arg (set, opt_name, [base] (const hb_set_t *s, hb_vector_t<char> &out) { |
896 | | _format_number_set (s, out, base); |
897 | | }, sb); |
898 | | } |
899 | | |
900 | | static void |
901 | | _format_tag_set_arg (const hb_set_t *set, |
902 | | const char *opt_name, |
903 | | hb_vector_t<char> &sb) |
904 | | { |
905 | | _format_set_arg (set, opt_name, _format_tag_set, sb); |
906 | | } |
907 | | |
908 | | static bool |
909 | | _format_glyph_map_arg (const hb_map_t &glyph_map, |
910 | | hb_vector_t<char> &sb) |
911 | | { |
912 | | if (glyph_map.is_empty ()) |
913 | | return true; |
914 | | |
915 | | hb_set_t keys; |
916 | | hb_map_keys (&glyph_map, &keys); |
917 | | hb_vector_t<char> pairs; |
918 | | bool first = true; |
919 | | for (hb_codepoint_t key : keys) |
920 | | { |
921 | | if (!first) |
922 | | pairs.push (','); |
923 | | first = false; |
924 | | hb_codepoint_t val = hb_map_get (&glyph_map, key); |
925 | | char buf[64]; |
926 | | int len = snprintf (buf, sizeof (buf), "%u:%u", key, val); |
927 | | if (unlikely (len < 0 || (size_t) len >= sizeof (buf))) return false; |
928 | | pairs.extend (hb_bytes_t (buf, len)); |
929 | | } |
930 | | if (pairs.length) |
931 | | { |
932 | | hb_vector_t<char> opt; |
933 | | opt.extend (hb_bytes_t ("--gid-map=", 10)); |
934 | | opt.extend (pairs.as_array ()); |
935 | | opt.push ('\0'); |
936 | | if (opt.arrayZ) _append_arg (sb, opt.arrayZ); |
937 | | } |
938 | | return true; |
939 | | } |
940 | | |
941 | | static bool |
942 | | _format_axes_location_arg (const hb_hashmap_t<hb_tag_t, Triple> &axes_location, |
943 | | hb_vector_t<char> &sb) |
944 | | { |
945 | | if (axes_location.is_empty ()) |
946 | | return true; |
947 | | |
948 | | hb_vector_t<hb_tag_t> axis_tags; |
949 | | for (auto tag : axes_location.keys ()) |
950 | | axis_tags.push (tag); |
951 | | axis_tags.qsort ([] (const hb_tag_t &a, const hb_tag_t &b) { return a < b ? -1 : a > b ? 1 : 0; }); |
952 | | |
953 | | hb_vector_t<char> specs; |
954 | | bool first = true; |
955 | | for (hb_tag_t tag : axis_tags) |
956 | | { |
957 | | Triple triple = axes_location.get (tag); |
958 | | if (!first) |
959 | | specs.push (','); |
960 | | first = false; |
961 | | |
962 | | hb_vector_t<char> tag_buf; |
963 | | _format_tag (tag, tag_buf); |
964 | | |
965 | | char buf[128]; |
966 | | int len; |
967 | | if (triple.minimum == triple.middle && triple.middle == triple.maximum) |
968 | | { |
969 | | len = snprintf (buf, sizeof (buf), "%.*s=%g", (int) tag_buf.length, tag_buf.arrayZ, (double) triple.middle); |
970 | | } |
971 | | else if (std::isnan (triple.minimum) && std::isnan (triple.middle) && std::isnan (triple.maximum)) |
972 | | { |
973 | | len = snprintf (buf, sizeof (buf), "%.*s=drop", (int) tag_buf.length, tag_buf.arrayZ); |
974 | | } |
975 | | else |
976 | | { |
977 | | len = snprintf (buf, sizeof (buf), "%.*s=%g:%g:%g", (int) tag_buf.length, tag_buf.arrayZ, |
978 | | (double) triple.minimum, (double) triple.middle, (double) triple.maximum); |
979 | | } |
980 | | if (unlikely (len < 0 || (size_t) len >= sizeof (buf))) return false; |
981 | | specs.extend (hb_bytes_t (buf, len)); |
982 | | } |
983 | | if (specs.length) |
984 | | { |
985 | | hb_vector_t<char> opt; |
986 | | opt.extend (hb_bytes_t ("--variations=", 13)); |
987 | | opt.extend (specs.as_array ()); |
988 | | opt.push ('\0'); |
989 | | if (opt.arrayZ) _append_arg (sb, opt.arrayZ); |
990 | | } |
991 | | return true; |
992 | | } |
993 | | |
994 | | /** |
995 | | * hb_subset_input_to_string_or_fail: |
996 | | * @input: a #hb_subset_input_t object. |
997 | | * |
998 | | * Produces a command line string representation of the given subset input |
999 | | * suitable for use with the `hb-subset` command line tool. |
1000 | | * |
1001 | | * Return value: (transfer full): A new #hb_blob_t containing the command line |
1002 | | * string, or `NULL` if failed. Destroy with hb_blob_destroy(). |
1003 | | * |
1004 | | * XSince: EXPERIMENTAL |
1005 | | **/ |
1006 | | hb_blob_t * |
1007 | | hb_subset_input_to_string_or_fail (hb_subset_input_t *input) |
1008 | | { |
1009 | | if (unlikely (!input || input->in_error ())) |
1010 | | return nullptr; |
1011 | | |
1012 | | hb_vector_t<char> sb; |
1013 | | |
1014 | | struct flag_option_t { |
1015 | | hb_subset_flags_t flag; |
1016 | | char option[32]; |
1017 | | }; |
1018 | | static const flag_option_t flag_options[] = { |
1019 | | { HB_SUBSET_FLAGS_NO_HINTING, "no-hinting" }, |
1020 | | { HB_SUBSET_FLAGS_RETAIN_GIDS, "retain-gids" }, |
1021 | | { HB_SUBSET_FLAGS_DESUBROUTINIZE, "desubroutinize" }, |
1022 | | { HB_SUBSET_FLAGS_NAME_LEGACY, "name-legacy" }, |
1023 | | { HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG, "set-overlaps-flag" }, |
1024 | | { HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED, "passthrough-tables" }, |
1025 | | { HB_SUBSET_FLAGS_NOTDEF_OUTLINE, "notdef-outline" }, |
1026 | | { HB_SUBSET_FLAGS_GLYPH_NAMES, "glyph-names" }, |
1027 | | { HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES, "no-prune-unicode-ranges" }, |
1028 | | { HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE, "no-layout-closure" }, |
1029 | | { HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS, "optimize" }, |
1030 | | { HB_SUBSET_FLAGS_NO_BIDI_CLOSURE, "no-bidi-closure" }, |
1031 | | #ifdef HB_EXPERIMENTAL_API |
1032 | | { HB_SUBSET_FLAGS_IFTB_REQUIREMENTS, "iftb-requirements" }, |
1033 | | { HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS, "retain-num-glyphs" }, |
1034 | | #endif |
1035 | | { HB_SUBSET_FLAGS_DOWNGRADE_CFF2, "downgrade-cff2" }, |
1036 | | }; |
1037 | | |
1038 | | #ifdef HB_EXPERIMENTAL_API |
1039 | | static_assert (sizeof (flag_options) / sizeof (flag_options[0]) == 15, |
1040 | | "Check all flags in hb_subset_flags_t are handled here."); |
1041 | | #else |
1042 | | static_assert (sizeof (flag_options) / sizeof (flag_options[0]) == 13, |
1043 | | "Check all flags in hb_subset_flags_t are handled here."); |
1044 | | #endif |
1045 | | |
1046 | | for (const auto &fo : flag_options) |
1047 | | { |
1048 | | if (input->flags & fo.flag) |
1049 | | { |
1050 | | char buf[36]; |
1051 | | snprintf (buf, sizeof (buf), "--%s", fo.option); |
1052 | | _append_arg (sb, buf); |
1053 | | } |
1054 | | } |
1055 | | |
1056 | | hb_subset_input_t *default_input = hb_subset_input_create_or_fail (); |
1057 | | if (unlikely (!default_input)) |
1058 | | return nullptr; |
1059 | | |
1060 | | // Serialize all sets if they are not equal to their default setting: |
1061 | | #define PROCESS_NUMBER_SET(field, opt_name, ...) \ |
1062 | | if (!_is_set_default (input->sets.field, default_input->sets.field)) \ |
1063 | | _format_number_set_arg (input->sets.field, opt_name, sb, ##__VA_ARGS__) |
1064 | | |
1065 | | #define PROCESS_TAG_SET(field, opt_name) \ |
1066 | | if (!_is_set_default (input->sets.field, default_input->sets.field)) \ |
1067 | | _format_tag_set_arg (input->sets.field, opt_name, sb) |
1068 | | |
1069 | | PROCESS_NUMBER_SET (unicodes, "unicodes", 16); |
1070 | | PROCESS_NUMBER_SET (glyphs, "gids"); |
1071 | | PROCESS_NUMBER_SET (name_ids, "name-IDs"); |
1072 | | PROCESS_NUMBER_SET (name_languages, "name-languages"); |
1073 | | PROCESS_TAG_SET (layout_features, "layout-features"); |
1074 | | PROCESS_TAG_SET (layout_scripts, "layout-scripts"); |
1075 | | PROCESS_TAG_SET (drop_tables, "drop-tables"); |
1076 | | PROCESS_TAG_SET (no_subset_tables, "passthrough-tables"); |
1077 | | |
1078 | | #undef PROCESS_NUMBER_SET |
1079 | | #undef PROCESS_TAG_SET |
1080 | | |
1081 | | hb_subset_input_destroy (default_input); |
1082 | | |
1083 | | static_assert (sizeof (input->sets) / sizeof (hb_set_t*) == 8, |
1084 | | "Check all sets in hb_subset_input_t::sets_t are handled here."); |
1085 | | |
1086 | | if (unlikely (!_format_glyph_map_arg (input->glyph_map, sb))) |
1087 | | return nullptr; |
1088 | | |
1089 | | if (unlikely (!_format_axes_location_arg (input->axes_location, sb))) |
1090 | | return nullptr; |
1091 | | |
1092 | | sb.push ('\0'); |
1093 | | if (unlikely (sb.in_error ())) |
1094 | | return nullptr; |
1095 | | |
1096 | | unsigned len = 0; |
1097 | | char *buf = sb.steal (&len); |
1098 | | if (unlikely (!buf)) |
1099 | | return nullptr; |
1100 | | |
1101 | | return hb_blob_create_or_fail (buf, len, HB_MEMORY_MODE_WRITABLE, buf, hb_free); |
1102 | | } |
1103 | | #endif |
1104 | | |
1105 | | /** |
1106 | | * hb_subset_preprocess: |
1107 | | * @source: a #hb_face_t object. |
1108 | | * |
1109 | | * Preprocesses the face and attaches data that will be needed by the |
1110 | | * subsetter. Future subsetting operations can then use the precomputed data |
1111 | | * to speed up the subsetting operation. |
1112 | | * |
1113 | | * See [subset-preprocessing](https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md) |
1114 | | * for more information. |
1115 | | * |
1116 | | * Note: the preprocessed face may contain sub-blobs that reference the memory |
1117 | | * backing the source #hb_face_t. Therefore in the case that this memory is not |
1118 | | * owned by the source face you will need to ensure that memory lives |
1119 | | * as long as the returned #hb_face_t. |
1120 | | * |
1121 | | * Returns: a new #hb_face_t. |
1122 | | * |
1123 | | * Since: 6.0.0 |
1124 | | **/ |
1125 | | |
1126 | | HB_EXTERN hb_face_t * |
1127 | | hb_subset_preprocess (hb_face_t *source) |
1128 | 0 | { |
1129 | 0 | hb_subset_input_t* input = hb_subset_input_create_or_fail (); |
1130 | 0 | if (!input) |
1131 | 0 | return hb_face_reference (source); |
1132 | | |
1133 | 0 | hb_subset_input_keep_everything (input); |
1134 | |
|
1135 | 0 | input->attach_accelerator_data = true; |
1136 | | |
1137 | | // Always use long loca in the preprocessed version. This allows |
1138 | | // us to store the glyph bytes unpadded which allows the future subset |
1139 | | // operation to run faster by skipping the trim padding step. |
1140 | 0 | input->force_long_loca = true; |
1141 | |
|
1142 | 0 | hb_face_t* new_source = hb_subset_or_fail (source, input); |
1143 | 0 | hb_subset_input_destroy (input); |
1144 | |
|
1145 | 0 | if (!new_source) { |
1146 | 0 | DEBUG_MSG (SUBSET, nullptr, "Preprocessing failed due to subset failure."); |
1147 | 0 | return hb_face_reference (source); |
1148 | 0 | } |
1149 | | |
1150 | 0 | return new_source; |
1151 | 0 | } |
1152 | | |
1153 | | /** |
1154 | | * hb_subset_input_old_to_new_glyph_mapping: |
1155 | | * @input: a #hb_subset_input_t object. |
1156 | | * |
1157 | | * Returns a map which can be used to provide an explicit mapping from old to new glyph |
1158 | | * id's in the produced subset. The caller should populate the map as desired. |
1159 | | * If this map is left empty then glyph ids will be automatically mapped to new |
1160 | | * values by the subsetter. If populated, the mapping must be unique. That |
1161 | | * is no two original glyph ids can be mapped to the same new id. |
1162 | | * Additionally, if a mapping is provided then the retain gids option cannot |
1163 | | * be enabled. |
1164 | | * |
1165 | | * Any glyphs that are retained in the subset which are not specified |
1166 | | * in this mapping will be assigned glyph ids after the highest glyph |
1167 | | * id in the mapping. |
1168 | | * |
1169 | | * Note: this will accept and apply non-monotonic mappings, however this |
1170 | | * may result in unsorted Coverage tables. Such fonts may not work for all |
1171 | | * use cases (for example ots will reject unsorted coverage tables). So it's |
1172 | | * recommended, if possible, to supply a monotonic mapping. |
1173 | | * |
1174 | | * Return value: (transfer none): pointer to the #hb_map_t of the custom glyphs ID map. |
1175 | | * |
1176 | | * Since: 7.3.0 |
1177 | | **/ |
1178 | | HB_EXTERN hb_map_t* |
1179 | | hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input) |
1180 | 15.5k | { |
1181 | 15.5k | return &input->glyph_map; |
1182 | 15.5k | } |
1183 | | |
1184 | | #ifdef HB_EXPERIMENTAL_API |
1185 | | /** |
1186 | | * hb_subset_input_override_name_table: |
1187 | | * @input: a #hb_subset_input_t object. |
1188 | | * @name_id: name_id of a nameRecord |
1189 | | * @platform_id: platform ID of a nameRecord |
1190 | | * @encoding_id: encoding ID of a nameRecord |
1191 | | * @language_id: language ID of a nameRecord |
1192 | | * @name_str: pointer to name string new value or null to indicate should remove |
1193 | | * @str_len: the size of @name_str, or -1 if it is `NULL`-terminated |
1194 | | * |
1195 | | * Override the name string of the NameRecord identified by name_id, |
1196 | | * platform_id, encoding_id and language_id. If a record with that name_id |
1197 | | * doesn't exist, create it and insert to the name table. |
1198 | | * |
1199 | | * Note: for mac platform, we only support name_str with all ascii characters, |
1200 | | * name_str with non-ascii characters will be ignored. |
1201 | | * |
1202 | | * XSince: EXPERIMENTAL |
1203 | | **/ |
1204 | | HB_EXTERN hb_bool_t |
1205 | | hb_subset_input_override_name_table (hb_subset_input_t *input, |
1206 | | hb_ot_name_id_t name_id, |
1207 | | unsigned platform_id, |
1208 | | unsigned encoding_id, |
1209 | | unsigned language_id, |
1210 | | const char *name_str, |
1211 | | int str_len /* -1 means nul-terminated */) |
1212 | | { |
1213 | | if (!name_str) |
1214 | | { |
1215 | | str_len = 0; |
1216 | | } |
1217 | | else if (str_len == -1) |
1218 | | { |
1219 | | str_len = strlen (name_str); |
1220 | | } |
1221 | | |
1222 | | hb_bytes_t name_bytes (nullptr, 0); |
1223 | | if (str_len) |
1224 | | { |
1225 | | if (platform_id == 1) |
1226 | | { |
1227 | | const uint8_t *src = reinterpret_cast<const uint8_t*> (name_str); |
1228 | | const uint8_t *src_end = src + str_len; |
1229 | | |
1230 | | hb_codepoint_t unicode; |
1231 | | const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; |
1232 | | while (src < src_end) |
1233 | | { |
1234 | | src = hb_utf8_t::next (src, src_end, &unicode, replacement); |
1235 | | if (unicode >= 0x0080u) |
1236 | | { |
1237 | | // Non-ascii character detected, ignored... |
1238 | | return false; |
1239 | | } |
1240 | | } |
1241 | | } |
1242 | | char *override_name = (char *) hb_malloc (str_len); |
1243 | | if (unlikely (!override_name)) return false; |
1244 | | |
1245 | | hb_memcpy (override_name, name_str, str_len); |
1246 | | name_bytes = hb_bytes_t (override_name, str_len); |
1247 | | } |
1248 | | input->name_table_overrides.set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes); |
1249 | | return true; |
1250 | | } |
1251 | | #endif |