tor-browser

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

hb-face.cc (25917B)


      1 /*
      2 * Copyright © 2009  Red Hat, Inc.
      3 * Copyright © 2012  Google, Inc.
      4 *
      5 *  This is part of HarfBuzz, a text shaping library.
      6 *
      7 * Permission is hereby granted, without written agreement and without
      8 * license or royalty fees, to use, copy, modify, and distribute this
      9 * software and its documentation for any purpose, provided that the
     10 * above copyright notice and the following two paragraphs appear in
     11 * all copies of this software.
     12 *
     13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     17 * DAMAGE.
     18 *
     19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     21 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     24 *
     25 * Red Hat Author(s): Behdad Esfahbod
     26 * Google Author(s): Behdad Esfahbod
     27 */
     28 
     29 #include "hb.hh"
     30 
     31 #include "hb-face.hh"
     32 #include "hb-blob.hh"
     33 #include "hb-open-file.hh"
     34 #include "hb-ot-face.hh"
     35 #include "hb-ot-cmap-table.hh"
     36 
     37 #ifdef HAVE_FREETYPE
     38 #include "hb-ft.h"
     39 #endif
     40 #ifdef HAVE_CORETEXT
     41 #include "hb-coretext.h"
     42 #endif
     43 #ifdef HAVE_DIRECTWRITE
     44 #include "hb-directwrite.h"
     45 #endif
     46 
     47 
     48 /**
     49 * SECTION:hb-face
     50 * @title: hb-face
     51 * @short_description: Font face objects
     52 * @include: hb.h
     53 *
     54 * A font face is an object that represents a single face from within a
     55 * font family.
     56 *
     57 * More precisely, a font face represents a single face in a binary font file.
     58 * Font faces are typically built from a binary blob and a face index.
     59 * Font faces are used to create fonts.
     60 *
     61 * A font face can be created from a binary blob using hb_face_create().
     62 * The face index is used to select a face from a binary blob that contains
     63 * multiple faces.  For example, a binary blob that contains both a regular
     64 * and a bold face can be used to create two font faces, one for each face
     65 * index.
     66 **/
     67 
     68 
     69 /**
     70 * hb_face_count:
     71 * @blob: a blob.
     72 *
     73 * Fetches the number of faces in a blob.
     74 *
     75 * Return value: Number of faces in @blob
     76 *
     77 * Since: 1.7.7
     78 **/
     79 unsigned int
     80 hb_face_count (hb_blob_t *blob)
     81 {
     82  if (unlikely (!blob))
     83    return 0;
     84 
     85  hb_sanitize_context_t c (blob);
     86 
     87  auto *ot = blob->as<OT::OpenTypeFontFile> ();
     88  if (unlikely (!ot->sanitize (&c)))
     89    return 0;
     90 
     91  return ot->get_face_count ();
     92 }
     93 
     94 /*
     95 * hb_face_t
     96 */
     97 
     98 DEFINE_NULL_INSTANCE (hb_face_t) =
     99 {
    100  HB_OBJECT_HEADER_STATIC,
    101 
    102  0,    /* index */
    103  1000, /* upem */
    104  0,    /* num_glyphs */
    105 
    106  /* Zero for the rest is fine. */
    107 };
    108 
    109 
    110 /**
    111 * hb_face_create_for_tables:
    112 * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function
    113 * @user_data: A pointer to the user data
    114 * @destroy: (nullable): A callback to call when @data is not needed anymore
    115 *
    116 * Variant of hb_face_create(), built for those cases where it is more
    117 * convenient to provide data for individual tables instead of the whole font
    118 * data. With the caveat that hb_face_get_table_tags() would not work
    119 * with faces created this way. You can address that by calling the
    120 * hb_face_set_get_table_tags_func() function and setting the appropriate callback.
    121 *
    122 * Creates a new face object from the specified @user_data and @reference_table_func,
    123 * with the @destroy callback.
    124 *
    125 * Return value: (transfer full): The new face object
    126 *
    127 * Since: 0.9.2
    128 **/
    129 hb_face_t *
    130 hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
    131 		   void                      *user_data,
    132 		   hb_destroy_func_t          destroy)
    133 {
    134  hb_face_t *face;
    135 
    136  if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {
    137    if (destroy)
    138      destroy (user_data);
    139    return hb_face_get_empty ();
    140  }
    141 
    142  face->reference_table_func = reference_table_func;
    143  face->user_data = user_data;
    144  face->destroy = destroy;
    145 
    146  face->num_glyphs = -1;
    147 
    148  face->data.init0 (face);
    149  face->table.init0 (face);
    150 
    151  return face;
    152 }
    153 
    154 
    155 typedef struct hb_face_for_data_closure_t {
    156  hb_blob_t *blob;
    157  uint16_t  index;
    158 } hb_face_for_data_closure_t;
    159 
    160 static hb_face_for_data_closure_t *
    161 _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
    162 {
    163  hb_face_for_data_closure_t *closure;
    164 
    165  closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t));
    166  if (unlikely (!closure))
    167    return nullptr;
    168 
    169  closure->blob = blob;
    170  closure->index = (uint16_t) (index & 0xFFFFu);
    171 
    172  return closure;
    173 }
    174 
    175 static void
    176 _hb_face_for_data_closure_destroy (void *data)
    177 {
    178  hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
    179 
    180  hb_blob_destroy (closure->blob);
    181  hb_free (closure);
    182 }
    183 
    184 static hb_blob_t *
    185 _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
    186 {
    187  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
    188 
    189  if (tag == HB_TAG_NONE)
    190    return hb_blob_reference (data->blob);
    191 
    192  const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
    193  unsigned int base_offset;
    194  const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset);
    195 
    196  const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
    197 
    198  hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length);
    199 
    200  return blob;
    201 }
    202 
    203 static unsigned
    204 _hb_face_for_data_get_table_tags (const hb_face_t *face HB_UNUSED,
    205 			  unsigned int start_offset,
    206 			  unsigned int *table_count,
    207 			  hb_tag_t *table_tags,
    208 			  void *user_data)
    209 {
    210  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
    211 
    212  const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
    213  const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
    214 
    215  return ot_face.get_table_tags (start_offset, table_count, table_tags);
    216 }
    217 
    218 
    219 /**
    220 * hb_face_create:
    221 * @blob: #hb_blob_t to work upon
    222 * @index: The index of the face within @blob
    223 *
    224 * Constructs a new face object from the specified blob and
    225 * a face index into that blob.
    226 *
    227 * The face index is used for blobs of file formats such as TTC and
    228 * DFont that can contain more than one face.  Face indices within
    229 * such collections are zero-based.
    230 *
    231 * <note>Note: If the blob font format is not a collection, @index
    232 * is ignored.  Otherwise, only the lower 16-bits of @index are used.
    233 * The unmodified @index can be accessed via hb_face_get_index().</note>
    234 *
    235 * <note>Note: The high 16-bits of @index, if non-zero, are used by
    236 * hb_font_create() to load named-instances in variable fonts.  See
    237 * hb_font_create() for details.</note>
    238 *
    239 * Return value: (transfer full): The new face object
    240 *
    241 * Since: 0.9.2
    242 **/
    243 hb_face_t *
    244 hb_face_create (hb_blob_t    *blob,
    245 	unsigned int  index)
    246 {
    247  hb_face_t *face;
    248 
    249  if (unlikely (!blob))
    250    blob = hb_blob_get_empty ();
    251 
    252  blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
    253 
    254  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index);
    255 
    256  if (unlikely (!closure))
    257  {
    258    hb_blob_destroy (blob);
    259    return hb_face_get_empty ();
    260  }
    261 
    262  face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
    263 			    closure,
    264 			    _hb_face_for_data_closure_destroy);
    265  hb_face_set_get_table_tags_func (face,
    266 			   _hb_face_for_data_get_table_tags,
    267 			   closure,
    268 			   nullptr);
    269 
    270  face->index = index;
    271 
    272  return face;
    273 }
    274 
    275 /**
    276 * hb_face_create_or_fail:
    277 * @blob: #hb_blob_t to work upon
    278 * @index: The index of the face within @blob
    279 *
    280 * Like hb_face_create(), but returns `NULL` if the blob data
    281 * contains no usable font face at the specified index.
    282 *
    283 * Return value: (transfer full): The new face object, or `NULL` if
    284 * no face is found at the specified index.
    285 *
    286 * Since: 10.1.0
    287 **/
    288 hb_face_t *
    289 hb_face_create_or_fail (hb_blob_t    *blob,
    290 		unsigned int  index)
    291 {
    292  unsigned num_faces = hb_face_count (blob);
    293  if (index >= num_faces)
    294    return nullptr;
    295 
    296  hb_face_t *face = hb_face_create (blob, index);
    297  if (hb_object_is_immutable (face))
    298    return nullptr;
    299 
    300  return face;
    301 }
    302 
    303 #ifndef HB_NO_OPEN
    304 /**
    305 * hb_face_create_from_file_or_fail:
    306 * @file_name: A font filename
    307 * @index: The index of the face within the file
    308 *
    309 * A thin wrapper around hb_blob_create_from_file_or_fail()
    310 * followed by hb_face_create_or_fail().
    311 *
    312 * Return value: (transfer full): The new face object, or `NULL` if
    313 * no face is found at the specified index or the file cannot be read.
    314 *
    315 * Since: 10.1.0
    316 **/
    317 HB_EXTERN hb_face_t *
    318 hb_face_create_from_file_or_fail (const char   *file_name,
    319 			  unsigned int  index)
    320 {
    321  hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name);
    322  if (unlikely (!blob))
    323    return nullptr;
    324 
    325  hb_face_t *face = hb_face_create_or_fail (blob, index);
    326  hb_blob_destroy (blob);
    327 
    328  return face;
    329 }
    330 
    331 static const struct supported_face_loaders_t {
    332 char name[16];
    333 hb_face_t * (*from_file) (const char *font_file, unsigned face_index);
    334 hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index);
    335 } supported_face_loaders[] =
    336 {
    337  {"ot",
    338 #ifndef HB_NO_OPEN
    339   hb_face_create_from_file_or_fail,
    340 #else
    341   nullptr,
    342 #endif
    343   hb_face_create_or_fail
    344  },
    345 #ifdef HAVE_FREETYPE
    346  {"ft",
    347   hb_ft_face_create_from_file_or_fail,
    348   hb_ft_face_create_from_blob_or_fail
    349  },
    350 #endif
    351 #ifdef HAVE_CORETEXT
    352  {"coretext",
    353   hb_coretext_face_create_from_file_or_fail,
    354   hb_coretext_face_create_from_blob_or_fail
    355  },
    356 #endif
    357 #ifdef HAVE_DIRECTWRITE
    358  {"directwrite",
    359   hb_directwrite_face_create_from_file_or_fail,
    360   hb_directwrite_face_create_from_blob_or_fail
    361  },
    362 #endif
    363 };
    364 
    365 static const char *get_default_loader_name ()
    366 {
    367  static hb_atomic_t<const char *> static_loader_name;
    368  const char *loader_name = static_loader_name.get_acquire ();
    369  if (!loader_name)
    370  {
    371    loader_name = getenv ("HB_FACE_LOADER");
    372    if (!loader_name)
    373      loader_name = "";
    374    if (!static_loader_name.cmpexch (nullptr, loader_name))
    375      loader_name = static_loader_name.get_acquire ();
    376  }
    377  return loader_name;
    378 }
    379 
    380 /**
    381 * hb_face_create_from_file_or_fail_using:
    382 * @file_name: A font filename
    383 * @index: The index of the face within the file
    384 * @loader_name: (nullable): The name of the loader to use, or `NULL`
    385 *
    386 * A thin wrapper around the face loader functions registered with HarfBuzz.
    387 * If @loader_name is `NULL` or the empty string, the first available loader
    388 * is used.
    389 *
    390 * For example, the FreeType ("ft") loader might be able to load
    391 * WOFF and WOFF2 files if FreeType is built with those features,
    392 * whereas the OpenType ("ot") loader will not.
    393 *
    394 * Return value: (transfer full): The new face object, or `NULL` if
    395 * the file cannot be read or the loader fails to load the face.
    396 *
    397 * Since: 11.0.0
    398 **/
    399 hb_face_t *
    400 hb_face_create_from_file_or_fail_using (const char   *file_name,
    401 				unsigned int  index,
    402 				const char   *loader_name)
    403 {
    404  // Duplicated in hb_face_create_or_fail_using
    405  bool retry = false;
    406  if (!loader_name || !*loader_name)
    407  {
    408    loader_name = get_default_loader_name ();
    409    retry = true;
    410  }
    411  if (loader_name && !*loader_name) loader_name = nullptr;
    412 
    413 retry:
    414  for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
    415  {
    416    if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name)))
    417      return supported_face_loaders[i].from_file (file_name, index);
    418  }
    419 
    420  if (retry)
    421  {
    422    retry = false;
    423    loader_name = nullptr;
    424    goto retry;
    425  }
    426 
    427  return nullptr;
    428 }
    429 
    430 /**
    431 * hb_face_create_or_fail_using:
    432 * @blob: #hb_blob_t to work upon
    433 * @index: The index of the face within @blob
    434 * @loader_name: (nullable): The name of the loader to use, or `NULL`
    435 *
    436 * A thin wrapper around the face loader functions registered with HarfBuzz.
    437 * If @loader_name is `NULL` or the empty string, the first available loader
    438 * is used.
    439 *
    440 * For example, the FreeType ("ft") loader might be able to load
    441 * WOFF and WOFF2 files if FreeType is built with those features,
    442 * whereas the OpenType ("ot") loader will not.
    443 *
    444 * Return value: (transfer full): The new face object, or `NULL` if
    445 * the loader fails to load the face.
    446 *
    447 * Since: 11.0.0
    448 **/
    449 hb_face_t *
    450 hb_face_create_or_fail_using (hb_blob_t    *blob,
    451 		      unsigned int  index,
    452 		      const char   *loader_name)
    453 {
    454  // Duplicated in hb_face_create_from_file_or_fail_using
    455  bool retry = false;
    456  if (!loader_name || !*loader_name)
    457  {
    458    loader_name = get_default_loader_name ();
    459    retry = true;
    460  }
    461  if (loader_name && !*loader_name) loader_name = nullptr;
    462 
    463 retry:
    464  for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
    465  {
    466    if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name)))
    467      return supported_face_loaders[i].from_blob (blob, index);
    468  }
    469 
    470  if (retry)
    471  {
    472    retry = false;
    473    loader_name = nullptr;
    474    goto retry;
    475  }
    476 
    477  return nullptr;
    478 }
    479 
    480 static inline void free_static_face_loader_list ();
    481 
    482 static const char * const nil_face_loader_list[] = {nullptr};
    483 
    484 static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t<const char *,
    485 							  hb_face_loader_list_lazy_loader_t>
    486 {
    487  static const char ** create ()
    488  {
    489    const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *));
    490    if (unlikely (!face_loader_list))
    491      return nullptr;
    492 
    493    unsigned i;
    494    for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
    495      face_loader_list[i] = supported_face_loaders[i].name;
    496    face_loader_list[i] = nullptr;
    497 
    498    hb_atexit (free_static_face_loader_list);
    499 
    500    return face_loader_list;
    501  }
    502  static void destroy (const char **l)
    503  { hb_free (l); }
    504  static const char * const * get_null ()
    505  { return nil_face_loader_list; }
    506 } static_face_loader_list;
    507 
    508 static inline
    509 void free_static_face_loader_list ()
    510 {
    511  static_face_loader_list.free_instance ();
    512 }
    513 
    514 /**
    515 * hb_face_list_loaders:
    516 *
    517 * Retrieves the list of face loaders supported by HarfBuzz.
    518 *
    519 * Return value: (transfer none) (array zero-terminated=1): a
    520 *    `NULL`-terminated array of supported face loaders
    521 *    constant strings. The returned array is owned by HarfBuzz
    522 *    and should not be modified or freed.
    523 *
    524 * Since: 11.0.0
    525 **/
    526 const char **
    527 hb_face_list_loaders ()
    528 {
    529  return static_face_loader_list.get_unconst ();
    530 }
    531 #endif
    532 
    533 
    534 /**
    535 * hb_face_get_empty:
    536 *
    537 * Fetches the singleton empty face object.
    538 *
    539 * Return value: (transfer full): The empty face object
    540 *
    541 * Since: 0.9.2
    542 **/
    543 hb_face_t *
    544 hb_face_get_empty ()
    545 {
    546  return const_cast<hb_face_t *> (&Null (hb_face_t));
    547 }
    548 
    549 
    550 /**
    551 * hb_face_reference: (skip)
    552 * @face: A face object
    553 *
    554 * Increases the reference count on a face object.
    555 *
    556 * Return value: The @face object
    557 *
    558 * Since: 0.9.2
    559 **/
    560 hb_face_t *
    561 hb_face_reference (hb_face_t *face)
    562 {
    563  return hb_object_reference (face);
    564 }
    565 
    566 /**
    567 * hb_face_destroy: (skip)
    568 * @face: A face object
    569 *
    570 * Decreases the reference count on a face object. When the
    571 * reference count reaches zero, the face is destroyed,
    572 * freeing all memory.
    573 *
    574 * Since: 0.9.2
    575 **/
    576 void
    577 hb_face_destroy (hb_face_t *face)
    578 {
    579  if (!hb_object_destroy (face)) return;
    580 
    581 #ifndef HB_NO_SHAPER
    582  for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
    583  {
    584    hb_face_t::plan_node_t *next = node->next;
    585    hb_shape_plan_destroy (node->shape_plan);
    586    hb_free (node);
    587    node = next;
    588  }
    589 #endif
    590 
    591  face->data.fini ();
    592  face->table.fini ();
    593 
    594  if (face->get_table_tags_destroy)
    595    face->get_table_tags_destroy (face->get_table_tags_user_data);
    596 
    597  if (face->destroy)
    598    face->destroy (face->user_data);
    599 
    600  hb_free (face);
    601 }
    602 
    603 /**
    604 * hb_face_set_user_data: (skip)
    605 * @face: A face object
    606 * @key: The user-data key to set
    607 * @data: A pointer to the user data
    608 * @destroy: (nullable): A callback to call when @data is not needed anymore
    609 * @replace: Whether to replace an existing data with the same key
    610 *
    611 * Attaches a user-data key/data pair to the given face object.
    612 *
    613 * Return value: `true` if success, `false` otherwise
    614 *
    615 * Since: 0.9.2
    616 **/
    617 hb_bool_t
    618 hb_face_set_user_data (hb_face_t          *face,
    619 	       hb_user_data_key_t *key,
    620 	       void *              data,
    621 	       hb_destroy_func_t   destroy,
    622 	       hb_bool_t           replace)
    623 {
    624  return hb_object_set_user_data (face, key, data, destroy, replace);
    625 }
    626 
    627 /**
    628 * hb_face_get_user_data: (skip)
    629 * @face: A face object
    630 * @key: The user-data key to query
    631 *
    632 * Fetches the user data associated with the specified key,
    633 * attached to the specified face object.
    634 *
    635 * Return value: (transfer none): A pointer to the user data
    636 *
    637 * Since: 0.9.2
    638 **/
    639 void *
    640 hb_face_get_user_data (const hb_face_t    *face,
    641 	       hb_user_data_key_t *key)
    642 {
    643  return hb_object_get_user_data (face, key);
    644 }
    645 
    646 /**
    647 * hb_face_make_immutable:
    648 * @face: A face object
    649 *
    650 * Makes the given face object immutable.
    651 *
    652 * Since: 0.9.2
    653 **/
    654 void
    655 hb_face_make_immutable (hb_face_t *face)
    656 {
    657  if (hb_object_is_immutable (face))
    658    return;
    659 
    660  hb_object_make_immutable (face);
    661 }
    662 
    663 /**
    664 * hb_face_is_immutable:
    665 * @face: A face object
    666 *
    667 * Tests whether the given face object is immutable.
    668 *
    669 * Return value: `true` is @face is immutable, `false` otherwise
    670 *
    671 * Since: 0.9.2
    672 **/
    673 hb_bool_t
    674 hb_face_is_immutable (hb_face_t *face)
    675 {
    676  return hb_object_is_immutable (face);
    677 }
    678 
    679 
    680 /**
    681 * hb_face_reference_table:
    682 * @face: A face object
    683 * @tag: The #hb_tag_t of the table to query
    684 *
    685 * Fetches a reference to the specified table within
    686 * the specified face. Returns an empty blob if referencing table data is not
    687 * possible.
    688 *
    689 * Return value: (transfer full): A pointer to the @tag table within @face
    690 *
    691 * Since: 0.9.2
    692 **/
    693 hb_blob_t *
    694 hb_face_reference_table (const hb_face_t *face,
    695 		 hb_tag_t tag)
    696 {
    697  if (unlikely (tag == HB_TAG_NONE))
    698    return hb_blob_get_empty ();
    699 
    700  return face->reference_table (tag);
    701 }
    702 
    703 /**
    704 * hb_face_reference_blob:
    705 * @face: A face object
    706 *
    707 * Fetches a pointer to the binary blob that contains the specified face.
    708 * If referencing the face data is not possible, this function creates a blob
    709 * out of individual table blobs if hb_face_get_table_tags() works with this
    710 * face, otherwise it returns an empty blob.
    711 *
    712 * Return value: (transfer full): A pointer to the blob for @face
    713 *
    714 * Since: 0.9.2
    715 **/
    716 hb_blob_t *
    717 hb_face_reference_blob (hb_face_t *face)
    718 {
    719  hb_blob_t *blob = face->reference_table (HB_TAG_NONE);
    720 
    721  if (blob == hb_blob_get_empty ())
    722  {
    723    // If referencing the face blob is not possible (e.g. not implemented by the
    724    // font functions), use face builder to create a blob out of individual
    725    // table blobs.
    726    unsigned total_count = hb_face_get_table_tags (face, 0, nullptr, nullptr);
    727    if (total_count)
    728    {
    729      hb_tag_t tags[64];
    730      unsigned count = ARRAY_LENGTH (tags);
    731      hb_face_t* builder = hb_face_builder_create ();
    732 
    733      for (unsigned offset = 0; offset < total_count; offset += count)
    734      {
    735        hb_face_get_table_tags (face, offset, &count, tags);
    736 if (unlikely (!count))
    737   break; // Allocation error
    738        for (unsigned i = 0; i < count; i++)
    739        {
    740   if (unlikely (!tags[i]))
    741     continue;
    742   hb_blob_t *table = hb_face_reference_table (face, tags[i]);
    743   hb_face_builder_add_table (builder, tags[i], table);
    744   hb_blob_destroy (table);
    745        }
    746      }
    747 
    748      blob = hb_face_reference_blob (builder);
    749      hb_face_destroy (builder);
    750    }
    751  }
    752 
    753  return blob;
    754 }
    755 
    756 /**
    757 * hb_face_set_index:
    758 * @face: A face object
    759 * @index: The index to assign
    760 *
    761 * Assigns the specified face-index to @face. Fails if the
    762 * face is immutable.
    763 *
    764 * <note>Note: changing the index has no effect on the face itself
    765 * This only changes the value returned by hb_face_get_index().</note>
    766 *
    767 * Since: 0.9.2
    768 **/
    769 void
    770 hb_face_set_index (hb_face_t    *face,
    771 	   unsigned int  index)
    772 {
    773  if (hb_object_is_immutable (face))
    774    return;
    775 
    776  face->index = index;
    777 }
    778 
    779 /**
    780 * hb_face_get_index:
    781 * @face: A face object
    782 *
    783 * Fetches the face-index corresponding to the given face.
    784 *
    785 * <note>Note: face indices within a collection are zero-based.</note>
    786 *
    787 * Return value: The index of @face.
    788 *
    789 * Since: 0.9.2
    790 **/
    791 unsigned int
    792 hb_face_get_index (const hb_face_t *face)
    793 {
    794  return face->index;
    795 }
    796 
    797 /**
    798 * hb_face_set_upem:
    799 * @face: A face object
    800 * @upem: The units-per-em value to assign
    801 *
    802 * Sets the units-per-em (upem) for a face object to the specified value.
    803 *
    804 * This API is used in rare circumstances.
    805 *
    806 * Since: 0.9.2
    807 **/
    808 void
    809 hb_face_set_upem (hb_face_t    *face,
    810 	  unsigned int  upem)
    811 {
    812  if (hb_object_is_immutable (face))
    813    return;
    814 
    815  face->upem = upem;
    816 }
    817 
    818 /**
    819 * hb_face_get_upem:
    820 * @face: A face object
    821 *
    822 * Fetches the units-per-em (UPEM) value of the specified face object.
    823 *
    824 * Typical UPEM values for fonts are 1000, or 2048, but any value
    825 * in between 16 and 16,384 is allowed for OpenType fonts.
    826 *
    827 * Return value: The upem value of @face
    828 *
    829 * Since: 0.9.2
    830 **/
    831 unsigned int
    832 hb_face_get_upem (const hb_face_t *face)
    833 {
    834  return face->get_upem ();
    835 }
    836 
    837 /**
    838 * hb_face_set_glyph_count:
    839 * @face: A face object
    840 * @glyph_count: The glyph-count value to assign
    841 *
    842 * Sets the glyph count for a face object to the specified value.
    843 *
    844 * This API is used in rare circumstances.
    845 *
    846 * Since: 0.9.7
    847 **/
    848 void
    849 hb_face_set_glyph_count (hb_face_t    *face,
    850 		 unsigned int  glyph_count)
    851 {
    852  if (hb_object_is_immutable (face))
    853    return;
    854 
    855  face->num_glyphs = glyph_count;
    856 }
    857 
    858 /**
    859 * hb_face_get_glyph_count:
    860 * @face: A face object
    861 *
    862 * Fetches the glyph-count value of the specified face object.
    863 *
    864 * Return value: The glyph-count value of @face
    865 *
    866 * Since: 0.9.7
    867 **/
    868 unsigned int
    869 hb_face_get_glyph_count (const hb_face_t *face)
    870 {
    871  return face->get_num_glyphs ();
    872 }
    873 
    874 /**
    875 * hb_face_set_get_table_tags_func:
    876 * @face: A face object
    877 * @func: (closure user_data) (destroy destroy) (scope notified): The table-tag-fetching function
    878 * @user_data: A pointer to the user data, to be destroyed by @destroy when not needed anymore
    879 * @destroy: (nullable): A callback to call when @func is not needed anymore
    880 *
    881 * Sets the table-tag-fetching function for the specified face object.
    882 *
    883 * Since: 10.0.0
    884 */
    885 HB_EXTERN void
    886 hb_face_set_get_table_tags_func (hb_face_t *face,
    887 			 hb_get_table_tags_func_t func,
    888 			 void                    *user_data,
    889 			 hb_destroy_func_t        destroy)
    890 {
    891  if (hb_object_is_immutable (face))
    892  {
    893    if (destroy)
    894      destroy (user_data);
    895    return;
    896  }
    897 
    898  if (face->get_table_tags_destroy)
    899    face->get_table_tags_destroy (face->get_table_tags_user_data);
    900 
    901  face->get_table_tags_func = func;
    902  face->get_table_tags_user_data = user_data;
    903  face->get_table_tags_destroy = destroy;
    904 }
    905 
    906 /**
    907 * hb_face_get_table_tags:
    908 * @face: A face object
    909 * @start_offset: The index of first table tag to retrieve
    910 * @table_count: (inout): Input = the maximum number of table tags to return;
    911 *                Output = the actual number of table tags returned (may be zero)
    912 * @table_tags: (out) (array length=table_count): The array of table tags found
    913 *
    914 * Fetches a list of all table tags for a face, if possible. The list returned will
    915 * begin at the offset provided
    916 *
    917 * Return value: Total number of tables, or zero if it is not possible to list
    918 *
    919 * Since: 1.6.0
    920 **/
    921 unsigned int
    922 hb_face_get_table_tags (const hb_face_t *face,
    923 		unsigned int  start_offset,
    924 		unsigned int *table_count, /* IN/OUT */
    925 		hb_tag_t     *table_tags /* OUT */)
    926 {
    927  if (!face->get_table_tags_func)
    928  {
    929    if (table_count)
    930      *table_count = 0;
    931    return 0;
    932  }
    933 
    934  return face->get_table_tags_func (face, start_offset, table_count, table_tags, face->get_table_tags_user_data);
    935 }
    936 
    937 
    938 /*
    939 * Character set.
    940 */
    941 
    942 
    943 #ifndef HB_NO_FACE_COLLECT_UNICODES
    944 /**
    945 * hb_face_collect_unicodes:
    946 * @face: A face object
    947 * @out: (out): The set to add Unicode characters to
    948 *
    949 * Collects all of the Unicode characters covered by @face and adds
    950 * them to the #hb_set_t set @out.
    951 *
    952 * Since: 1.9.0
    953 */
    954 void
    955 hb_face_collect_unicodes (hb_face_t *face,
    956 		  hb_set_t  *out)
    957 {
    958  face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
    959 }
    960 /**
    961 * hb_face_collect_nominal_glyph_mapping:
    962 * @face: A face object
    963 * @mapping: (out): The map to add Unicode-to-glyph mapping to
    964 * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL`
    965 *
    966 * Collects the mapping from Unicode characters to nominal glyphs of the @face,
    967 * and optionally all of the Unicode characters covered by @face.
    968 *
    969 * Since: 7.0.0
    970 */
    971 void
    972 hb_face_collect_nominal_glyph_mapping (hb_face_t *face,
    973 			       hb_map_t  *mapping,
    974 			       hb_set_t  *unicodes)
    975 {
    976  hb_set_t stack_unicodes;
    977  if (!unicodes)
    978    unicodes = &stack_unicodes;
    979  face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ());
    980 }
    981 /**
    982 * hb_face_collect_variation_selectors:
    983 * @face: A face object
    984 * @out: (out): The set to add Variation Selector characters to
    985 *
    986 * Collects all Unicode "Variation Selector" characters covered by @face and adds
    987 * them to the #hb_set_t set @out.
    988 *
    989 * Since: 1.9.0
    990 */
    991 void
    992 hb_face_collect_variation_selectors (hb_face_t *face,
    993 			     hb_set_t  *out)
    994 {
    995  face->table.cmap->collect_variation_selectors (out);
    996 }
    997 /**
    998 * hb_face_collect_variation_unicodes:
    999 * @face: A face object
   1000 * @variation_selector: The Variation Selector to query
   1001 * @out: (out): The set to add Unicode characters to
   1002 *
   1003 * Collects all Unicode characters for @variation_selector covered by @face and adds
   1004 * them to the #hb_set_t set @out.
   1005 *
   1006 * Since: 1.9.0
   1007 */
   1008 void
   1009 hb_face_collect_variation_unicodes (hb_face_t *face,
   1010 			    hb_codepoint_t variation_selector,
   1011 			    hb_set_t  *out)
   1012 {
   1013  face->table.cmap->collect_variation_unicodes (variation_selector, out);
   1014 }
   1015 #endif