/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 | 6.57k | { |
35 | 6.57k | for (auto& set : sets_iter ()) |
36 | 52.5k | set = hb::shared_ptr<hb_set_t> (hb_set_create ()); |
37 | | |
38 | 6.57k | if (in_error ()) |
39 | 0 | return; |
40 | | |
41 | 6.57k | flags = HB_SUBSET_FLAGS_DEFAULT; |
42 | | |
43 | 6.57k | hb_set_add_range (sets.name_ids, 0, 6); |
44 | 6.57k | hb_set_add (sets.name_languages, 0x0409); |
45 | | |
46 | 6.57k | hb_tag_t default_drop_tables[] = { |
47 | | // Layout disabled by default |
48 | 6.57k | HB_TAG ('m', 'o', 'r', 'x'), |
49 | 6.57k | HB_TAG ('m', 'o', 'r', 't'), |
50 | 6.57k | HB_TAG ('k', 'e', 'r', 'x'), |
51 | 6.57k | HB_TAG ('k', 'e', 'r', 'n'), |
52 | | |
53 | | // Copied from fontTools: |
54 | 6.57k | HB_TAG ('J', 'S', 'T', 'F'), |
55 | 6.57k | HB_TAG ('D', 'S', 'I', 'G'), |
56 | 6.57k | HB_TAG ('E', 'B', 'D', 'T'), |
57 | 6.57k | HB_TAG ('E', 'B', 'L', 'C'), |
58 | 6.57k | HB_TAG ('E', 'B', 'S', 'C'), |
59 | 6.57k | HB_TAG ('S', 'V', 'G', ' '), |
60 | 6.57k | HB_TAG ('P', 'C', 'L', 'T'), |
61 | 6.57k | HB_TAG ('L', 'T', 'S', 'H'), |
62 | | // Graphite tables |
63 | 6.57k | HB_TAG ('F', 'e', 'a', 't'), |
64 | 6.57k | HB_TAG ('G', 'l', 'a', 't'), |
65 | 6.57k | HB_TAG ('G', 'l', 'o', 'c'), |
66 | 6.57k | HB_TAG ('S', 'i', 'l', 'f'), |
67 | 6.57k | HB_TAG ('S', 'i', 'l', 'l'), |
68 | 6.57k | }; |
69 | 6.57k | sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables)); |
70 | | |
71 | 6.57k | hb_tag_t default_no_subset_tables[] = { |
72 | 6.57k | HB_TAG ('g', 'a', 's', 'p'), |
73 | 6.57k | HB_TAG ('f', 'p', 'g', 'm'), |
74 | 6.57k | HB_TAG ('p', 'r', 'e', 'p'), |
75 | 6.57k | HB_TAG ('V', 'D', 'M', 'X'), |
76 | 6.57k | HB_TAG ('D', 'S', 'I', 'G'), |
77 | 6.57k | }; |
78 | 6.57k | sets.no_subset_tables->add_array (default_no_subset_tables, |
79 | 6.57k | ARRAY_LENGTH (default_no_subset_tables)); |
80 | | |
81 | | //copied from _layout_features_groups in fonttools |
82 | 6.57k | hb_tag_t default_layout_features[] = { |
83 | | // default shaper |
84 | | // common |
85 | 6.57k | HB_TAG ('r', 'v', 'r', 'n'), |
86 | 6.57k | HB_TAG ('c', 'c', 'm', 'p'), |
87 | 6.57k | HB_TAG ('l', 'i', 'g', 'a'), |
88 | 6.57k | HB_TAG ('l', 'o', 'c', 'l'), |
89 | 6.57k | HB_TAG ('m', 'a', 'r', 'k'), |
90 | 6.57k | HB_TAG ('m', 'k', 'm', 'k'), |
91 | 6.57k | HB_TAG ('r', 'l', 'i', 'g'), |
92 | | |
93 | | //fractions |
94 | 6.57k | HB_TAG ('f', 'r', 'a', 'c'), |
95 | 6.57k | HB_TAG ('n', 'u', 'm', 'r'), |
96 | 6.57k | HB_TAG ('d', 'n', 'o', 'm'), |
97 | | |
98 | | //horizontal |
99 | 6.57k | HB_TAG ('c', 'a', 'l', 't'), |
100 | 6.57k | HB_TAG ('c', 'l', 'i', 'g'), |
101 | 6.57k | HB_TAG ('c', 'u', 'r', 's'), |
102 | 6.57k | HB_TAG ('k', 'e', 'r', 'n'), |
103 | 6.57k | HB_TAG ('r', 'c', 'l', 't'), |
104 | | |
105 | | //vertical |
106 | 6.57k | HB_TAG ('v', 'a', 'l', 't'), |
107 | 6.57k | HB_TAG ('v', 'e', 'r', 't'), |
108 | 6.57k | HB_TAG ('v', 'k', 'r', 'n'), |
109 | 6.57k | HB_TAG ('v', 'p', 'a', 'l'), |
110 | 6.57k | HB_TAG ('v', 'r', 't', '2'), |
111 | | |
112 | | //ltr |
113 | 6.57k | HB_TAG ('l', 't', 'r', 'a'), |
114 | 6.57k | HB_TAG ('l', 't', 'r', 'm'), |
115 | | |
116 | | //rtl |
117 | 6.57k | HB_TAG ('r', 't', 'l', 'a'), |
118 | 6.57k | HB_TAG ('r', 't', 'l', 'm'), |
119 | | |
120 | | //random |
121 | 6.57k | HB_TAG ('r', 'a', 'n', 'd'), |
122 | | |
123 | | //justify |
124 | 6.57k | HB_TAG ('j', 'a', 'l', 't'), // HarfBuzz doesn't use; others might |
125 | | |
126 | | //East Asian spacing |
127 | 6.57k | HB_TAG ('c', 'h', 'w', 's'), |
128 | 6.57k | HB_TAG ('v', 'c', 'h', 'w'), |
129 | 6.57k | HB_TAG ('h', 'a', 'l', 't'), |
130 | 6.57k | HB_TAG ('v', 'h', 'a', 'l'), |
131 | | |
132 | | //private |
133 | 6.57k | HB_TAG ('H', 'a', 'r', 'f'), |
134 | 6.57k | HB_TAG ('H', 'A', 'R', 'F'), |
135 | 6.57k | HB_TAG ('B', 'u', 'z', 'z'), |
136 | 6.57k | HB_TAG ('B', 'U', 'Z', 'Z'), |
137 | | |
138 | | //shapers |
139 | | |
140 | | //arabic |
141 | 6.57k | HB_TAG ('i', 'n', 'i', 't'), |
142 | 6.57k | HB_TAG ('m', 'e', 'd', 'i'), |
143 | 6.57k | HB_TAG ('f', 'i', 'n', 'a'), |
144 | 6.57k | HB_TAG ('i', 's', 'o', 'l'), |
145 | 6.57k | HB_TAG ('m', 'e', 'd', '2'), |
146 | 6.57k | HB_TAG ('f', 'i', 'n', '2'), |
147 | 6.57k | HB_TAG ('f', 'i', 'n', '3'), |
148 | 6.57k | HB_TAG ('c', 's', 'w', 'h'), |
149 | 6.57k | HB_TAG ('m', 's', 'e', 't'), |
150 | 6.57k | HB_TAG ('s', 't', 'c', 'h'), |
151 | | |
152 | | //hangul |
153 | 6.57k | HB_TAG ('l', 'j', 'm', 'o'), |
154 | 6.57k | HB_TAG ('v', 'j', 'm', 'o'), |
155 | 6.57k | HB_TAG ('t', 'j', 'm', 'o'), |
156 | | |
157 | | //tibetan |
158 | 6.57k | HB_TAG ('a', 'b', 'v', 's'), |
159 | 6.57k | HB_TAG ('b', 'l', 'w', 's'), |
160 | 6.57k | HB_TAG ('a', 'b', 'v', 'm'), |
161 | 6.57k | HB_TAG ('b', 'l', 'w', 'm'), |
162 | | |
163 | | //indic |
164 | 6.57k | HB_TAG ('n', 'u', 'k', 't'), |
165 | 6.57k | HB_TAG ('a', 'k', 'h', 'n'), |
166 | 6.57k | HB_TAG ('r', 'p', 'h', 'f'), |
167 | 6.57k | HB_TAG ('r', 'k', 'r', 'f'), |
168 | 6.57k | HB_TAG ('p', 'r', 'e', 'f'), |
169 | 6.57k | HB_TAG ('b', 'l', 'w', 'f'), |
170 | 6.57k | HB_TAG ('h', 'a', 'l', 'f'), |
171 | 6.57k | HB_TAG ('a', 'b', 'v', 'f'), |
172 | 6.57k | HB_TAG ('p', 's', 't', 'f'), |
173 | 6.57k | HB_TAG ('c', 'f', 'a', 'r'), |
174 | 6.57k | HB_TAG ('v', 'a', 't', 'u'), |
175 | 6.57k | HB_TAG ('c', 'j', 'c', 't'), |
176 | 6.57k | HB_TAG ('i', 'n', 'i', 't'), |
177 | 6.57k | HB_TAG ('p', 'r', 'e', 's'), |
178 | 6.57k | HB_TAG ('a', 'b', 'v', 's'), |
179 | 6.57k | HB_TAG ('b', 'l', 'w', 's'), |
180 | 6.57k | HB_TAG ('p', 's', 't', 's'), |
181 | 6.57k | HB_TAG ('h', 'a', 'l', 'n'), |
182 | 6.57k | HB_TAG ('d', 'i', 's', 't'), |
183 | 6.57k | HB_TAG ('a', 'b', 'v', 'm'), |
184 | 6.57k | HB_TAG ('b', 'l', 'w', 'm'), |
185 | 6.57k | }; |
186 | | |
187 | 6.57k | sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features)); |
188 | | |
189 | 6.57k | sets.layout_scripts->invert (); // Default to all scripts. |
190 | 6.57k | } |
191 | | |
192 | | /** |
193 | | * hb_subset_input_create_or_fail: |
194 | | * |
195 | | * Creates a new subset input object. |
196 | | * |
197 | | * Return value: (transfer full): New subset input, or `NULL` if failed. Destroy |
198 | | * with hb_subset_input_destroy(). |
199 | | * |
200 | | * Since: 1.8.0 |
201 | | **/ |
202 | | hb_subset_input_t * |
203 | | hb_subset_input_create_or_fail (void) |
204 | 6.57k | { |
205 | 6.57k | hb_subset_input_t *input = hb_object_create<hb_subset_input_t>(); |
206 | | |
207 | 6.57k | if (unlikely (!input)) |
208 | 0 | return nullptr; |
209 | | |
210 | 6.57k | if (input->in_error ()) |
211 | 0 | { |
212 | 0 | hb_subset_input_destroy (input); |
213 | 0 | return nullptr; |
214 | 0 | } |
215 | | |
216 | 6.57k | return input; |
217 | 6.57k | } |
218 | | |
219 | | /** |
220 | | * hb_subset_input_reference: (skip) |
221 | | * @input: a #hb_subset_input_t object. |
222 | | * |
223 | | * Increases the reference count on @input. |
224 | | * |
225 | | * Return value: @input. |
226 | | * |
227 | | * Since: 1.8.0 |
228 | | **/ |
229 | | hb_subset_input_t * |
230 | | hb_subset_input_reference (hb_subset_input_t *input) |
231 | 0 | { |
232 | 0 | return hb_object_reference (input); |
233 | 0 | } |
234 | | |
235 | | /** |
236 | | * hb_subset_input_destroy: |
237 | | * @input: a #hb_subset_input_t object. |
238 | | * |
239 | | * Decreases the reference count on @input, and if it reaches zero, destroys |
240 | | * @input, freeing all memory. |
241 | | * |
242 | | * Since: 1.8.0 |
243 | | **/ |
244 | | void |
245 | | hb_subset_input_destroy (hb_subset_input_t *input) |
246 | 6.57k | { |
247 | 6.57k | if (!hb_object_destroy (input)) return; |
248 | | |
249 | 6.57k | hb_free (input); |
250 | 6.57k | } |
251 | | |
252 | | /** |
253 | | * hb_subset_input_unicode_set: |
254 | | * @input: a #hb_subset_input_t object. |
255 | | * |
256 | | * Gets the set of Unicode code points to retain, the caller should modify the |
257 | | * set as needed. |
258 | | * |
259 | | * Return value: (transfer none): pointer to the #hb_set_t of Unicode code |
260 | | * points. |
261 | | * |
262 | | * Since: 1.8.0 |
263 | | **/ |
264 | | HB_EXTERN hb_set_t * |
265 | | hb_subset_input_unicode_set (hb_subset_input_t *input) |
266 | 0 | { |
267 | 0 | return input->sets.unicodes; |
268 | 0 | } |
269 | | |
270 | | /** |
271 | | * hb_subset_input_glyph_set: |
272 | | * @input: a #hb_subset_input_t object. |
273 | | * |
274 | | * Gets the set of glyph IDs to retain, the caller should modify the set as |
275 | | * needed. |
276 | | * |
277 | | * Return value: (transfer none): pointer to the #hb_set_t of glyph IDs. |
278 | | * |
279 | | * Since: 1.8.0 |
280 | | **/ |
281 | | HB_EXTERN hb_set_t * |
282 | | hb_subset_input_glyph_set (hb_subset_input_t *input) |
283 | 6.57k | { |
284 | 6.57k | return input->sets.glyphs; |
285 | 6.57k | } |
286 | | |
287 | | /** |
288 | | * hb_subset_input_set: |
289 | | * @input: a #hb_subset_input_t object. |
290 | | * @set_type: a #hb_subset_sets_t set type. |
291 | | * |
292 | | * Gets the set of the specified type. |
293 | | * |
294 | | * Return value: (transfer none): pointer to the #hb_set_t of the specified type. |
295 | | * |
296 | | * Since: 2.9.1 |
297 | | **/ |
298 | | HB_EXTERN hb_set_t * |
299 | | hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type) |
300 | 6.57k | { |
301 | 6.57k | return input->sets_iter () [set_type]; |
302 | 6.57k | } |
303 | | |
304 | | /** |
305 | | * hb_subset_input_get_flags: |
306 | | * @input: a #hb_subset_input_t object. |
307 | | * |
308 | | * Gets all of the subsetting flags in the input object. |
309 | | * |
310 | | * Return value: the subsetting flags bit field. |
311 | | * |
312 | | * Since: 2.9.0 |
313 | | **/ |
314 | | HB_EXTERN hb_subset_flags_t |
315 | | hb_subset_input_get_flags (hb_subset_input_t *input) |
316 | 0 | { |
317 | 0 | return (hb_subset_flags_t) input->flags; |
318 | 0 | } |
319 | | |
320 | | /** |
321 | | * hb_subset_input_set_flags: |
322 | | * @input: a #hb_subset_input_t object. |
323 | | * @value: bit field of flags |
324 | | * |
325 | | * Sets all of the flags in the input object to the values specified by the bit |
326 | | * field. |
327 | | * |
328 | | * Since: 2.9.0 |
329 | | **/ |
330 | | HB_EXTERN void |
331 | | hb_subset_input_set_flags (hb_subset_input_t *input, |
332 | | unsigned value) |
333 | 6.57k | { |
334 | 6.57k | input->flags = (hb_subset_flags_t) value; |
335 | 6.57k | } |
336 | | |
337 | | /** |
338 | | * hb_subset_input_set_user_data: (skip) |
339 | | * @input: a #hb_subset_input_t object. |
340 | | * @key: The user-data key to set |
341 | | * @data: A pointer to the user data |
342 | | * @destroy: (nullable): A callback to call when @data is not needed anymore |
343 | | * @replace: Whether to replace an existing data with the same key |
344 | | * |
345 | | * Attaches a user-data key/data pair to the given subset input object. |
346 | | * |
347 | | * Return value: `true` if success, `false` otherwise |
348 | | * |
349 | | * Since: 2.9.0 |
350 | | **/ |
351 | | hb_bool_t |
352 | | hb_subset_input_set_user_data (hb_subset_input_t *input, |
353 | | hb_user_data_key_t *key, |
354 | | void * data, |
355 | | hb_destroy_func_t destroy, |
356 | | hb_bool_t replace) |
357 | 0 | { |
358 | 0 | return hb_object_set_user_data (input, key, data, destroy, replace); |
359 | 0 | } |
360 | | |
361 | | /** |
362 | | * hb_subset_input_get_user_data: (skip) |
363 | | * @input: a #hb_subset_input_t object. |
364 | | * @key: The user-data key to query |
365 | | * |
366 | | * Fetches the user data associated with the specified key, |
367 | | * attached to the specified subset input object. |
368 | | * |
369 | | * Return value: (transfer none): A pointer to the user data |
370 | | * |
371 | | * Since: 2.9.0 |
372 | | **/ |
373 | | void * |
374 | | hb_subset_input_get_user_data (const hb_subset_input_t *input, |
375 | | hb_user_data_key_t *key) |
376 | 0 | { |
377 | 0 | return hb_object_get_user_data (input, key); |
378 | 0 | } |
379 | | |
380 | | /** |
381 | | * hb_subset_input_keep_everything: |
382 | | * @input: a #hb_subset_input_t object |
383 | | * |
384 | | * Configure input object to keep everything in the font face. |
385 | | * That is, all Unicodes, glyphs, names, layout items, |
386 | | * glyph names, etc. |
387 | | * |
388 | | * The input can be tailored afterwards by the caller. |
389 | | * |
390 | | * Since: 7.0.0 |
391 | | */ |
392 | | void |
393 | | hb_subset_input_keep_everything (hb_subset_input_t *input) |
394 | 0 | { |
395 | 0 | const hb_subset_sets_t indices[] = {HB_SUBSET_SETS_UNICODE, |
396 | 0 | HB_SUBSET_SETS_GLYPH_INDEX, |
397 | 0 | HB_SUBSET_SETS_NAME_ID, |
398 | 0 | HB_SUBSET_SETS_NAME_LANG_ID, |
399 | 0 | HB_SUBSET_SETS_LAYOUT_FEATURE_TAG, |
400 | 0 | HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG}; |
401 | |
|
402 | 0 | for (auto idx : hb_iter (indices)) |
403 | 0 | { |
404 | 0 | hb_set_t *set = hb_subset_input_set (input, idx); |
405 | 0 | hb_set_clear (set); |
406 | 0 | hb_set_invert (set); |
407 | 0 | } |
408 | | |
409 | | // Don't drop any tables |
410 | 0 | hb_set_clear (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG)); |
411 | |
|
412 | 0 | hb_subset_input_set_flags (input, |
413 | 0 | HB_SUBSET_FLAGS_NOTDEF_OUTLINE | |
414 | 0 | HB_SUBSET_FLAGS_GLYPH_NAMES | |
415 | 0 | HB_SUBSET_FLAGS_NAME_LEGACY | |
416 | 0 | HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES | |
417 | 0 | HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED); |
418 | 0 | } |
419 | | |
420 | | #ifndef HB_NO_VAR |
421 | | /** |
422 | | * hb_subset_input_pin_all_axes_to_default: (skip) |
423 | | * @input: a #hb_subset_input_t object. |
424 | | * @face: a #hb_face_t object. |
425 | | * |
426 | | * Pin all axes to default locations in the given subset input object. |
427 | | * |
428 | | * All axes in a font must be pinned. Additionally, `CFF2` table, if present, |
429 | | * 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 | | * All axes in a font must be pinned. Additionally, `CFF2` table, if present, |
470 | | * will be de-subroutinized. |
471 | | * |
472 | | * Return value: `true` if success, `false` otherwise |
473 | | * |
474 | | * Since: 6.0.0 |
475 | | **/ |
476 | | HB_EXTERN hb_bool_t |
477 | | hb_subset_input_pin_axis_to_default (hb_subset_input_t *input, |
478 | | hb_face_t *face, |
479 | | hb_tag_t axis_tag) |
480 | 0 | { |
481 | 0 | hb_ot_var_axis_info_t axis_info; |
482 | 0 | if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) |
483 | 0 | return false; |
484 | | |
485 | 0 | double default_val = (double) axis_info.default_value; |
486 | 0 | return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)); |
487 | 0 | } |
488 | | |
489 | | /** |
490 | | * hb_subset_input_pin_axis_location: (skip) |
491 | | * @input: a #hb_subset_input_t object. |
492 | | * @face: a #hb_face_t object. |
493 | | * @axis_tag: Tag of the axis to be pinned |
494 | | * @axis_value: Location on the axis to be pinned at |
495 | | * |
496 | | * Pin an axis to a fixed location in the given subset input object. |
497 | | * |
498 | | * All axes in a font must be pinned. Additionally, `CFF2` table, if present, |
499 | | * will be de-subroutinized. |
500 | | * |
501 | | * Return value: `true` if success, `false` otherwise |
502 | | * |
503 | | * Since: 6.0.0 |
504 | | **/ |
505 | | HB_EXTERN hb_bool_t |
506 | | hb_subset_input_pin_axis_location (hb_subset_input_t *input, |
507 | | hb_face_t *face, |
508 | | hb_tag_t axis_tag, |
509 | | float axis_value) |
510 | 0 | { |
511 | 0 | hb_ot_var_axis_info_t axis_info; |
512 | 0 | if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) |
513 | 0 | return false; |
514 | | |
515 | 0 | double val = hb_clamp((double) axis_value, (double) axis_info.min_value, (double) axis_info.max_value); |
516 | 0 | return input->axes_location.set (axis_tag, Triple (val, val, val)); |
517 | 0 | } |
518 | | |
519 | | /** |
520 | | * hb_subset_input_set_axis_range: (skip) |
521 | | * @input: a #hb_subset_input_t object. |
522 | | * @face: a #hb_face_t object. |
523 | | * @axis_tag: Tag of the axis |
524 | | * @axis_min_value: Minimum value of the axis variation range to set, if NaN the existing min will be used. |
525 | | * @axis_max_value: Maximum value of the axis variation range to set if NaN the existing max will be used. |
526 | | * @axis_def_value: Default value of the axis variation range to set, if NaN the existing default will be used. |
527 | | * |
528 | | * Restricting the range of variation on an axis in the given subset input object. |
529 | | * New min/default/max values will be clamped if they're not within the fvar axis range. |
530 | | * |
531 | | * If the fvar axis default value is not within the new range, the new default |
532 | | * value will be changed to the new min or max value, whichever is closer to the fvar |
533 | | * axis default. |
534 | | * |
535 | | * Note: input min value can not be bigger than input max value. If the input |
536 | | * default value is not within the new min/max range, it'll be clamped. |
537 | | * |
538 | | * Return value: `true` if success, `false` otherwise |
539 | | * |
540 | | * Since: 8.5.0 |
541 | | **/ |
542 | | HB_EXTERN hb_bool_t |
543 | | hb_subset_input_set_axis_range (hb_subset_input_t *input, |
544 | | hb_face_t *face, |
545 | | hb_tag_t axis_tag, |
546 | | float axis_min_value, |
547 | | float axis_max_value, |
548 | | float axis_def_value) |
549 | 0 | { |
550 | 0 | hb_ot_var_axis_info_t axis_info; |
551 | 0 | if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) |
552 | 0 | return false; |
553 | | |
554 | 0 | float min = !std::isnan(axis_min_value) ? axis_min_value : axis_info.min_value; |
555 | 0 | float max = !std::isnan(axis_max_value) ? axis_max_value : axis_info.max_value; |
556 | 0 | float def = !std::isnan(axis_def_value) ? axis_def_value : axis_info.default_value; |
557 | |
|
558 | 0 | if (min > max) |
559 | 0 | return false; |
560 | | |
561 | 0 | float new_min_val = hb_clamp(min, axis_info.min_value, axis_info.max_value); |
562 | 0 | float new_max_val = hb_clamp(max, axis_info.min_value, axis_info.max_value); |
563 | 0 | float new_default_val = hb_clamp(def, new_min_val, new_max_val); |
564 | 0 | return input->axes_location.set (axis_tag, Triple ((double) new_min_val, (double) new_default_val, (double) new_max_val)); |
565 | 0 | } |
566 | | |
567 | | /** |
568 | | * hb_subset_input_get_axis_range: (skip) |
569 | | * @input: a #hb_subset_input_t object. |
570 | | * @axis_tag: Tag of the axis |
571 | | * @axis_min_value: Set to the previously configured minimum value of the axis variation range. |
572 | | * @axis_max_value: Set to the previously configured maximum value of the axis variation range. |
573 | | * @axis_def_value: Set to the previously configured default value of the axis variation range. |
574 | | * |
575 | | * Gets the axis range assigned by previous calls to hb_subset_input_set_axis_range. |
576 | | * |
577 | | * Return value: `true` if a range has been set for this axis tag, `false` otherwise. |
578 | | * |
579 | | * Since: 8.5.0 |
580 | | **/ |
581 | | HB_EXTERN hb_bool_t |
582 | | hb_subset_input_get_axis_range (hb_subset_input_t *input, |
583 | | hb_tag_t axis_tag, |
584 | | float *axis_min_value, |
585 | | float *axis_max_value, |
586 | | float *axis_def_value) |
587 | | |
588 | 0 | { |
589 | 0 | Triple* triple; |
590 | 0 | if (!input->axes_location.has(axis_tag, &triple)) { |
591 | 0 | return false; |
592 | 0 | } |
593 | | |
594 | 0 | *axis_min_value = triple->minimum; |
595 | 0 | *axis_def_value = triple->middle; |
596 | 0 | *axis_max_value = triple->maximum; |
597 | 0 | return true; |
598 | 0 | } |
599 | | |
600 | | /** |
601 | | * hb_subset_axis_range_from_string: |
602 | | * @str: a string to parse |
603 | | * @len: length of @str, or -1 if str is NULL terminated |
604 | | * @axis_min_value: (out): the axis min value to initialize with the parsed value |
605 | | * @axis_max_value: (out): the axis max value to initialize with the parsed value |
606 | | * @axis_def_value: (out): the axis default value to initialize with the parse |
607 | | * value |
608 | | * |
609 | | * Parses a string into a subset axis range(min, def, max). |
610 | | * Axis positions string is in the format of min:def:max or min:max |
611 | | * When parsing axis positions, empty values as meaning the existing value for that part |
612 | | * E.g: :300:500 |
613 | | * Specifies min = existing, def = 300, max = 500 |
614 | | * In the output axis_range, if a value should be set to it's default value, |
615 | | * then it will be set to NaN |
616 | | * |
617 | | * Return value: |
618 | | * `true` if @str is successfully parsed, `false` otherwise |
619 | | * |
620 | | * Since: 10.2.0 |
621 | | */ |
622 | | HB_EXTERN hb_bool_t |
623 | | hb_subset_axis_range_from_string (const char *str, int len, |
624 | | float *axis_min_value, |
625 | | float *axis_max_value, |
626 | | float *axis_def_value) |
627 | 0 | { |
628 | 0 | if (len < 0) |
629 | 0 | len = strlen (str); |
630 | |
|
631 | 0 | const char *end = str + len; |
632 | 0 | const char* part = strpbrk (str, ":"); |
633 | 0 | if (!part) |
634 | 0 | { |
635 | | // Single value. |
636 | 0 | if (strcmp (str, "drop") == 0) |
637 | 0 | { |
638 | 0 | *axis_min_value = NAN; |
639 | 0 | *axis_def_value = NAN; |
640 | 0 | *axis_max_value = NAN; |
641 | 0 | return true; |
642 | 0 | } |
643 | | |
644 | 0 | double v; |
645 | 0 | if (!hb_parse_double (&str, end, &v)) return false; |
646 | | |
647 | 0 | *axis_min_value = v; |
648 | 0 | *axis_def_value = v; |
649 | 0 | *axis_max_value = v; |
650 | 0 | return true; |
651 | 0 | } |
652 | | |
653 | 0 | float values[3]; |
654 | 0 | int count = 0; |
655 | 0 | for (int i = 0; i < 3; i++) { |
656 | 0 | count++; |
657 | 0 | if (!*str || part == str) |
658 | 0 | { |
659 | 0 | values[i] = NAN; |
660 | |
|
661 | 0 | if (part == NULL) break; |
662 | 0 | str = part + 1; |
663 | 0 | part = strpbrk (str, ":"); |
664 | 0 | continue; |
665 | 0 | } |
666 | | |
667 | 0 | double v; |
668 | 0 | if (!hb_parse_double (&str, part, &v)) return false; |
669 | 0 | values[i] = v; |
670 | |
|
671 | 0 | if (part == NULL) break; |
672 | 0 | str = part + 1; |
673 | 0 | part = strpbrk (str, ":"); |
674 | 0 | } |
675 | | |
676 | 0 | if (count == 2) |
677 | 0 | { |
678 | 0 | *axis_min_value = values[0]; |
679 | 0 | *axis_def_value = NAN; |
680 | 0 | *axis_max_value = values[1]; |
681 | 0 | return true; |
682 | 0 | } |
683 | 0 | else if (count == 3) |
684 | 0 | { |
685 | 0 | *axis_min_value = values[0]; |
686 | 0 | *axis_def_value = values[1]; |
687 | 0 | *axis_max_value = values[2]; |
688 | 0 | return true; |
689 | 0 | } |
690 | 0 | return false; |
691 | 0 | } |
692 | | |
693 | | /** |
694 | | * hb_subset_axis_range_to_string: |
695 | | * @input: a #hb_subset_input_t object. |
696 | | * @axis_tag: an axis to convert |
697 | | * @buf: (array length=size) (out caller-allocates): output string |
698 | | * @size: the allocated size of @buf |
699 | | * |
700 | | * Converts an axis range into a `NULL`-terminated string in the format |
701 | | * understood by hb_subset_axis_range_from_string(). The client in responsible for |
702 | | * allocating big enough size for @buf, 128 bytes is more than enough. |
703 | | * |
704 | | * Since: 10.2.0 |
705 | | */ |
706 | | HB_EXTERN void |
707 | | hb_subset_axis_range_to_string (hb_subset_input_t *input, |
708 | | hb_tag_t axis_tag, |
709 | | char *buf, unsigned size) |
710 | 0 | { |
711 | 0 | if (unlikely (!size)) return; |
712 | 0 | Triple* triple; |
713 | 0 | if (!input->axes_location.has(axis_tag, &triple)) { |
714 | 0 | return; |
715 | 0 | } |
716 | | |
717 | 0 | char s[128]; |
718 | 0 | unsigned len = 0; |
719 | |
|
720 | 0 | hb_locale_t clocale HB_UNUSED; |
721 | 0 | hb_locale_t oldlocale HB_UNUSED; |
722 | 0 | oldlocale = hb_uselocale (clocale = newlocale (LC_ALL_MASK, "C", NULL)); |
723 | 0 | len += hb_max (0, snprintf (s, ARRAY_LENGTH (s) - len, "%g", (double) triple->minimum)); |
724 | 0 | s[len++] = ':'; |
725 | |
|
726 | 0 | len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) triple->middle)); |
727 | 0 | s[len++] = ':'; |
728 | |
|
729 | 0 | len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) triple->maximum)); |
730 | 0 | (void) hb_uselocale (((void) freelocale (clocale), oldlocale)); |
731 | |
|
732 | 0 | assert (len < ARRAY_LENGTH (s)); |
733 | 0 | len = hb_min (len, size - 1); |
734 | 0 | hb_memcpy (buf, s, len); |
735 | 0 | buf[len] = '\0'; |
736 | 0 | } |
737 | | #endif |
738 | | |
739 | | /** |
740 | | * hb_subset_preprocess: |
741 | | * @source: a #hb_face_t object. |
742 | | * |
743 | | * Preprocesses the face and attaches data that will be needed by the |
744 | | * subsetter. Future subsetting operations can then use the precomputed data |
745 | | * to speed up the subsetting operation. |
746 | | * |
747 | | * See [subset-preprocessing](https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md) |
748 | | * for more information. |
749 | | * |
750 | | * Note: the preprocessed face may contain sub-blobs that reference the memory |
751 | | * backing the source #hb_face_t. Therefore in the case that this memory is not |
752 | | * owned by the source face you will need to ensure that memory lives |
753 | | * as long as the returned #hb_face_t. |
754 | | * |
755 | | * Returns: a new #hb_face_t. |
756 | | * |
757 | | * Since: 6.0.0 |
758 | | **/ |
759 | | |
760 | | HB_EXTERN hb_face_t * |
761 | | hb_subset_preprocess (hb_face_t *source) |
762 | 0 | { |
763 | 0 | hb_subset_input_t* input = hb_subset_input_create_or_fail (); |
764 | 0 | if (!input) |
765 | 0 | return hb_face_reference (source); |
766 | | |
767 | 0 | hb_subset_input_keep_everything (input); |
768 | |
|
769 | 0 | input->attach_accelerator_data = true; |
770 | | |
771 | | // Always use long loca in the preprocessed version. This allows |
772 | | // us to store the glyph bytes unpadded which allows the future subset |
773 | | // operation to run faster by skipping the trim padding step. |
774 | 0 | input->force_long_loca = true; |
775 | |
|
776 | 0 | hb_face_t* new_source = hb_subset_or_fail (source, input); |
777 | 0 | hb_subset_input_destroy (input); |
778 | |
|
779 | 0 | if (!new_source) { |
780 | 0 | DEBUG_MSG (SUBSET, nullptr, "Preprocessing failed due to subset failure."); |
781 | 0 | return hb_face_reference (source); |
782 | 0 | } |
783 | | |
784 | 0 | return new_source; |
785 | 0 | } |
786 | | |
787 | | /** |
788 | | * hb_subset_input_old_to_new_glyph_mapping: |
789 | | * @input: a #hb_subset_input_t object. |
790 | | * |
791 | | * Returns a map which can be used to provide an explicit mapping from old to new glyph |
792 | | * id's in the produced subset. The caller should populate the map as desired. |
793 | | * If this map is left empty then glyph ids will be automatically mapped to new |
794 | | * values by the subsetter. If populated, the mapping must be unique. That |
795 | | * is no two original glyph ids can be mapped to the same new id. |
796 | | * Additionally, if a mapping is provided then the retain gids option cannot |
797 | | * be enabled. |
798 | | * |
799 | | * Any glyphs that are retained in the subset which are not specified |
800 | | * in this mapping will be assigned glyph ids after the highest glyph |
801 | | * id in the mapping. |
802 | | * |
803 | | * Note: this will accept and apply non-monotonic mappings, however this |
804 | | * may result in unsorted Coverage tables. Such fonts may not work for all |
805 | | * use cases (for example ots will reject unsorted coverage tables). So it's |
806 | | * recommended, if possible, to supply a monotonic mapping. |
807 | | * |
808 | | * Return value: (transfer none): pointer to the #hb_map_t of the custom glyphs ID map. |
809 | | * |
810 | | * Since: 7.3.0 |
811 | | **/ |
812 | | HB_EXTERN hb_map_t* |
813 | | hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input) |
814 | 6.57k | { |
815 | 6.57k | return &input->glyph_map; |
816 | 6.57k | } |
817 | | |
818 | | #ifdef HB_EXPERIMENTAL_API |
819 | | /** |
820 | | * hb_subset_input_override_name_table: |
821 | | * @input: a #hb_subset_input_t object. |
822 | | * @name_id: name_id of a nameRecord |
823 | | * @platform_id: platform ID of a nameRecord |
824 | | * @encoding_id: encoding ID of a nameRecord |
825 | | * @language_id: language ID of a nameRecord |
826 | | * @name_str: pointer to name string new value or null to indicate should remove |
827 | | * @str_len: the size of @name_str, or -1 if it is `NULL`-terminated |
828 | | * |
829 | | * Override the name string of the NameRecord identified by name_id, |
830 | | * platform_id, encoding_id and language_id. If a record with that name_id |
831 | | * doesn't exist, create it and insert to the name table. |
832 | | * |
833 | | * Note: for mac platform, we only support name_str with all ascii characters, |
834 | | * name_str with non-ascii characters will be ignored. |
835 | | * |
836 | | * XSince: EXPERIMENTAL |
837 | | **/ |
838 | | HB_EXTERN hb_bool_t |
839 | | hb_subset_input_override_name_table (hb_subset_input_t *input, |
840 | | hb_ot_name_id_t name_id, |
841 | | unsigned platform_id, |
842 | | unsigned encoding_id, |
843 | | unsigned language_id, |
844 | | const char *name_str, |
845 | | int str_len /* -1 means nul-terminated */) |
846 | | { |
847 | | if (!name_str) |
848 | | { |
849 | | str_len = 0; |
850 | | } |
851 | | else if (str_len == -1) |
852 | | { |
853 | | str_len = strlen (name_str); |
854 | | } |
855 | | |
856 | | hb_bytes_t name_bytes (nullptr, 0); |
857 | | if (str_len) |
858 | | { |
859 | | if (platform_id == 1) |
860 | | { |
861 | | const uint8_t *src = reinterpret_cast<const uint8_t*> (name_str); |
862 | | const uint8_t *src_end = src + str_len; |
863 | | |
864 | | hb_codepoint_t unicode; |
865 | | const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; |
866 | | while (src < src_end) |
867 | | { |
868 | | src = hb_utf8_t::next (src, src_end, &unicode, replacement); |
869 | | if (unicode >= 0x0080u) |
870 | | { |
871 | | // Non-ascii character detected, ignored... |
872 | | return false; |
873 | | } |
874 | | } |
875 | | } |
876 | | char *override_name = (char *) hb_malloc (str_len); |
877 | | if (unlikely (!override_name)) return false; |
878 | | |
879 | | hb_memcpy (override_name, name_str, str_len); |
880 | | name_bytes = hb_bytes_t (override_name, str_len); |
881 | | } |
882 | | input->name_table_overrides.set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes); |
883 | | return true; |
884 | | } |
885 | | #endif |