Coverage Report

Created: 2025-07-07 10:01

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