tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-subset-input.cc (26384B)


      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 {
     35  for (auto& set : sets_iter ())
     36    set = hb::shared_ptr<hb_set_t> (hb_set_create ());
     37 
     38  if (in_error ())
     39    return;
     40 
     41  flags = HB_SUBSET_FLAGS_DEFAULT;
     42 
     43  hb_set_add_range (sets.name_ids, 0, 6);
     44  hb_set_add (sets.name_languages, 0x0409);
     45 
     46  hb_tag_t default_drop_tables[] = {
     47    // Layout disabled by default
     48    HB_TAG ('m', 'o', 'r', 'x'),
     49    HB_TAG ('m', 'o', 'r', 't'),
     50    HB_TAG ('k', 'e', 'r', 'x'),
     51    HB_TAG ('k', 'e', 'r', 'n'),
     52 
     53    // Copied from fontTools:
     54    HB_TAG ('J', 'S', 'T', 'F'),
     55    HB_TAG ('D', 'S', 'I', 'G'),
     56    HB_TAG ('E', 'B', 'D', 'T'),
     57    HB_TAG ('E', 'B', 'L', 'C'),
     58    HB_TAG ('E', 'B', 'S', 'C'),
     59    HB_TAG ('S', 'V', 'G', ' '),
     60    HB_TAG ('P', 'C', 'L', 'T'),
     61    HB_TAG ('L', 'T', 'S', 'H'),
     62    // Graphite tables
     63    HB_TAG ('F', 'e', 'a', 't'),
     64    HB_TAG ('G', 'l', 'a', 't'),
     65    HB_TAG ('G', 'l', 'o', 'c'),
     66    HB_TAG ('S', 'i', 'l', 'f'),
     67    HB_TAG ('S', 'i', 'l', 'l'),
     68  };
     69  sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
     70 
     71  hb_tag_t default_no_subset_tables[] = {
     72    HB_TAG ('g', 'a', 's', 'p'),
     73    HB_TAG ('f', 'p', 'g', 'm'),
     74    HB_TAG ('p', 'r', 'e', 'p'),
     75    HB_TAG ('V', 'D', 'M', 'X'),
     76    HB_TAG ('D', 'S', 'I', 'G'),
     77  };
     78  sets.no_subset_tables->add_array (default_no_subset_tables,
     79 				 ARRAY_LENGTH (default_no_subset_tables));
     80 
     81  //copied from _layout_features_groups in fonttools
     82  hb_tag_t default_layout_features[] = {
     83    // default shaper
     84    // common
     85    HB_TAG ('r', 'v', 'r', 'n'),
     86    HB_TAG ('c', 'c', 'm', 'p'),
     87    HB_TAG ('l', 'i', 'g', 'a'),
     88    HB_TAG ('l', 'o', 'c', 'l'),
     89    HB_TAG ('m', 'a', 'r', 'k'),
     90    HB_TAG ('m', 'k', 'm', 'k'),
     91    HB_TAG ('r', 'l', 'i', 'g'),
     92 
     93    //fractions
     94    HB_TAG ('f', 'r', 'a', 'c'),
     95    HB_TAG ('n', 'u', 'm', 'r'),
     96    HB_TAG ('d', 'n', 'o', 'm'),
     97 
     98    //horizontal
     99    HB_TAG ('c', 'a', 'l', 't'),
    100    HB_TAG ('c', 'l', 'i', 'g'),
    101    HB_TAG ('c', 'u', 'r', 's'),
    102    HB_TAG ('k', 'e', 'r', 'n'),
    103    HB_TAG ('r', 'c', 'l', 't'),
    104 
    105    //vertical
    106    HB_TAG ('v', 'a', 'l', 't'),
    107    HB_TAG ('v', 'e', 'r', 't'),
    108    HB_TAG ('v', 'k', 'r', 'n'),
    109    HB_TAG ('v', 'p', 'a', 'l'),
    110    HB_TAG ('v', 'r', 't', '2'),
    111 
    112    //ltr
    113    HB_TAG ('l', 't', 'r', 'a'),
    114    HB_TAG ('l', 't', 'r', 'm'),
    115 
    116    //rtl
    117    HB_TAG ('r', 't', 'l', 'a'),
    118    HB_TAG ('r', 't', 'l', 'm'),
    119 
    120    //random
    121    HB_TAG ('r', 'a', 'n', 'd'),
    122 
    123    //justify
    124    HB_TAG ('j', 'a', 'l', 't'), // HarfBuzz doesn't use; others might
    125 
    126    //East Asian spacing
    127    HB_TAG ('c', 'h', 'w', 's'),
    128    HB_TAG ('v', 'c', 'h', 'w'),
    129    HB_TAG ('h', 'a', 'l', 't'),
    130    HB_TAG ('v', 'h', 'a', 'l'),
    131 
    132    //private
    133    HB_TAG ('H', 'a', 'r', 'f'),
    134    HB_TAG ('H', 'A', 'R', 'F'),
    135    HB_TAG ('B', 'u', 'z', 'z'),
    136    HB_TAG ('B', 'U', 'Z', 'Z'),
    137 
    138    //shapers
    139 
    140    //arabic
    141    HB_TAG ('i', 'n', 'i', 't'),
    142    HB_TAG ('m', 'e', 'd', 'i'),
    143    HB_TAG ('f', 'i', 'n', 'a'),
    144    HB_TAG ('i', 's', 'o', 'l'),
    145    HB_TAG ('m', 'e', 'd', '2'),
    146    HB_TAG ('f', 'i', 'n', '2'),
    147    HB_TAG ('f', 'i', 'n', '3'),
    148    HB_TAG ('c', 's', 'w', 'h'),
    149    HB_TAG ('m', 's', 'e', 't'),
    150    HB_TAG ('s', 't', 'c', 'h'),
    151 
    152    //hangul
    153    HB_TAG ('l', 'j', 'm', 'o'),
    154    HB_TAG ('v', 'j', 'm', 'o'),
    155    HB_TAG ('t', 'j', 'm', 'o'),
    156 
    157    //tibetan
    158    HB_TAG ('a', 'b', 'v', 's'),
    159    HB_TAG ('b', 'l', 'w', 's'),
    160    HB_TAG ('a', 'b', 'v', 'm'),
    161    HB_TAG ('b', 'l', 'w', 'm'),
    162 
    163    //indic
    164    HB_TAG ('n', 'u', 'k', 't'),
    165    HB_TAG ('a', 'k', 'h', 'n'),
    166    HB_TAG ('r', 'p', 'h', 'f'),
    167    HB_TAG ('r', 'k', 'r', 'f'),
    168    HB_TAG ('p', 'r', 'e', 'f'),
    169    HB_TAG ('b', 'l', 'w', 'f'),
    170    HB_TAG ('h', 'a', 'l', 'f'),
    171    HB_TAG ('a', 'b', 'v', 'f'),
    172    HB_TAG ('p', 's', 't', 'f'),
    173    HB_TAG ('c', 'f', 'a', 'r'),
    174    HB_TAG ('v', 'a', 't', 'u'),
    175    HB_TAG ('c', 'j', 'c', 't'),
    176    HB_TAG ('i', 'n', 'i', 't'),
    177    HB_TAG ('p', 'r', 'e', 's'),
    178    HB_TAG ('a', 'b', 'v', 's'),
    179    HB_TAG ('b', 'l', 'w', 's'),
    180    HB_TAG ('p', 's', 't', 's'),
    181    HB_TAG ('h', 'a', 'l', 'n'),
    182    HB_TAG ('d', 'i', 's', 't'),
    183    HB_TAG ('a', 'b', 'v', 'm'),
    184    HB_TAG ('b', 'l', 'w', 'm'),
    185  };
    186 
    187  sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
    188 
    189  sets.layout_scripts->invert (); // Default to all scripts.
    190 }
    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 {
    205  hb_subset_input_t *input = hb_object_create<hb_subset_input_t>();
    206 
    207  if (unlikely (!input))
    208    return nullptr;
    209 
    210  if (input->in_error ())
    211  {
    212    hb_subset_input_destroy (input);
    213    return nullptr;
    214  }
    215 
    216  return input;
    217 }
    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 {
    232  return hb_object_reference (input);
    233 }
    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 {
    247  if (!hb_object_destroy (input)) return;
    248 
    249  hb_free (input);
    250 }
    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 {
    267  return input->sets.unicodes;
    268 }
    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 {
    284  return input->sets.glyphs;
    285 }
    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 {
    301  return input->sets_iter () [set_type];
    302 }
    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 {
    317  return (hb_subset_flags_t) input->flags;
    318 }
    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 {
    334  input->flags = (hb_subset_flags_t) value;
    335 }
    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 {
    358  return hb_object_set_user_data (input, key, data, destroy, replace);
    359 }
    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 {
    377  return hb_object_get_user_data (input, key);
    378 }
    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 {
    395  const hb_subset_sets_t indices[] = {HB_SUBSET_SETS_UNICODE,
    396 			      HB_SUBSET_SETS_GLYPH_INDEX,
    397 			      HB_SUBSET_SETS_NAME_ID,
    398 			      HB_SUBSET_SETS_NAME_LANG_ID,
    399 			      HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
    400 			      HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG};
    401 
    402  for (auto idx : hb_iter (indices))
    403  {
    404    hb_set_t *set = hb_subset_input_set (input, idx);
    405    hb_set_clear (set);
    406    hb_set_invert (set);
    407  }
    408 
    409  // Don't drop any tables
    410  hb_set_clear (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG));
    411 
    412  hb_subset_input_set_flags (input,
    413 		     HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
    414 		     HB_SUBSET_FLAGS_GLYPH_NAMES |
    415 		     HB_SUBSET_FLAGS_NAME_LEGACY |
    416 		     HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES |
    417                             HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED);
    418 }
    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 {
    439  unsigned axis_count = hb_ot_var_get_axis_count (face);
    440  if (!axis_count) return false;
    441 
    442  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  if (unlikely (!axis_infos)) return false;
    444 
    445  (void) hb_ot_var_get_axis_infos (face, 0, &axis_count, axis_infos);
    446 
    447  for (unsigned i = 0; i < axis_count; i++)
    448  {
    449    hb_tag_t axis_tag = axis_infos[i].tag;
    450    double default_val = (double) axis_infos[i].default_value;
    451    if (!input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)))
    452    {
    453      hb_free (axis_infos);
    454      return false;
    455    }
    456  }
    457  hb_free (axis_infos);
    458  return true;
    459 }
    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 {
    481  hb_ot_var_axis_info_t axis_info;
    482  if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
    483    return false;
    484 
    485  double default_val = (double) axis_info.default_value;
    486  return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val));
    487 }
    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 {
    511  hb_ot_var_axis_info_t axis_info;
    512  if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
    513    return false;
    514 
    515  double val = hb_clamp((double) axis_value, (double) axis_info.min_value, (double) axis_info.max_value);
    516  return input->axes_location.set (axis_tag, Triple (val, val, val));
    517 }
    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 {
    550  hb_ot_var_axis_info_t axis_info;
    551  if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
    552    return false;
    553 
    554  float min = !std::isnan(axis_min_value) ? axis_min_value : axis_info.min_value;
    555  float max = !std::isnan(axis_max_value) ? axis_max_value : axis_info.max_value;
    556  float def = !std::isnan(axis_def_value) ? axis_def_value : axis_info.default_value;
    557 
    558  if (min > max)
    559    return false;
    560 
    561  float new_min_val = hb_clamp(min, axis_info.min_value, axis_info.max_value);
    562  float new_max_val = hb_clamp(max, axis_info.min_value, axis_info.max_value);
    563  float new_default_val = hb_clamp(def, new_min_val, new_max_val);
    564  return input->axes_location.set (axis_tag, Triple ((double) new_min_val, (double) new_default_val, (double) new_max_val));
    565 }
    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 {
    589  Triple* triple;
    590  if (!input->axes_location.has(axis_tag, &triple)) {
    591    return false;
    592  }
    593 
    594  *axis_min_value = triple->minimum;
    595  *axis_def_value = triple->middle;
    596  *axis_max_value = triple->maximum;
    597  return true;
    598 }
    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 {
    628  if (len < 0)
    629    len = strlen (str);
    630 
    631  const char *end = str + len;
    632  const char* part = strpbrk (str, ":");
    633  if (!part)
    634  {
    635    // Single value.
    636    if (strcmp (str, "drop") == 0)
    637    {
    638      *axis_min_value = NAN;
    639      *axis_def_value = NAN;
    640      *axis_max_value = NAN;
    641      return true;
    642    }
    643 
    644    double v;
    645    if (!hb_parse_double (&str, end, &v)) return false;
    646 
    647    *axis_min_value = v;
    648    *axis_def_value = v;
    649    *axis_max_value = v;
    650    return true;
    651  }
    652 
    653  float values[3];
    654  int count = 0;
    655  for (int i = 0; i < 3; i++) {
    656    count++;
    657    if (!*str || part == str)
    658    {
    659      values[i] = NAN;
    660 
    661      if (part == NULL) break;
    662      str = part + 1;
    663      part = strpbrk (str, ":");
    664      continue;
    665    }
    666 
    667    double v;
    668    if (!hb_parse_double (&str, part, &v)) return false;
    669    values[i] = v;
    670 
    671    if (part == NULL) break;
    672    str = part + 1;
    673    part = strpbrk (str, ":");
    674  }
    675 
    676  if (count == 2)
    677  {
    678    *axis_min_value = values[0];
    679    *axis_def_value = NAN;
    680    *axis_max_value = values[1];
    681    return true;
    682  }
    683  else if (count == 3)
    684  {
    685    *axis_min_value = values[0];
    686    *axis_def_value = values[1];
    687    *axis_max_value = values[2];
    688    return true;
    689  }
    690  return false;
    691 }
    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 {
    711  if (unlikely (!size)) return;
    712  Triple* triple;
    713  if (!input->axes_location.has(axis_tag, &triple)) {
    714    return;
    715  }
    716 
    717  char s[128];
    718  unsigned len = 0;
    719 
    720  hb_locale_t clocale HB_UNUSED;
    721  hb_locale_t oldlocale HB_UNUSED;
    722  oldlocale = hb_uselocale (clocale = newlocale (LC_ALL_MASK, "C", NULL));
    723  len += hb_max (0, snprintf (s, ARRAY_LENGTH (s) - len, "%g", (double) triple->minimum));
    724  s[len++] = ':';
    725 
    726  len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) triple->middle));
    727  s[len++] = ':';
    728 
    729  len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) triple->maximum));
    730  (void) hb_uselocale (((void) freelocale (clocale), oldlocale));
    731 
    732  assert (len < ARRAY_LENGTH (s));
    733  len = hb_min (len, size - 1);
    734  hb_memcpy (buf, s, len);
    735  buf[len] = '\0';
    736 }
    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 {
    763  hb_subset_input_t* input = hb_subset_input_create_or_fail ();
    764  if (!input)
    765    return hb_face_reference (source);
    766 
    767  hb_subset_input_keep_everything (input);
    768 
    769  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  input->force_long_loca = true;
    775 
    776  hb_face_t* new_source = hb_subset_or_fail (source, input);
    777  hb_subset_input_destroy (input);
    778 
    779  if (!new_source) {
    780    DEBUG_MSG (SUBSET, nullptr, "Preprocessing failed due to subset failure.");
    781    return hb_face_reference (source);
    782  }
    783 
    784  return new_source;
    785 }
    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 {
    815  return &input->glyph_map;
    816 }
    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