Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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