xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-face.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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 
38 /**
39  * SECTION:hb-face
40  * @title: hb-face
41  * @short_description: Font face objects
42  * @include: hb.h
43  *
44  * A font face is an object that represents a single face from within a
45  * font family.
46  *
47  * More precisely, a font face represents a single face in a binary font file.
48  * Font faces are typically built from a binary blob and a face index.
49  * Font faces are used to create fonts.
50  *
51  * A font face can be created from a binary blob using hb_face_create().
52  * The face index is used to select a face from a binary blob that contains
53  * multiple faces.  For example, a binary blob that contains both a regular
54  * and a bold face can be used to create two font faces, one for each face
55  * index.
56  **/
57 
58 
59 /**
60  * hb_face_count:
61  * @blob: a blob.
62  *
63  * Fetches the number of faces in a blob.
64  *
65  * Return value: Number of faces in @blob
66  *
67  * Since: 1.7.7
68  **/
69 unsigned int
hb_face_count(hb_blob_t * blob)70 hb_face_count (hb_blob_t *blob)
71 {
72   if (unlikely (!blob))
73     return 0;
74 
75   /* TODO We shouldn't be sanitizing blob.  Port to run sanitizer and return if not sane. */
76   /* Make API signature const after. */
77   hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
78   const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
79   unsigned int ret = ot.get_face_count ();
80   hb_blob_destroy (sanitized);
81 
82   return ret;
83 }
84 
85 /*
86  * hb_face_t
87  */
88 
89 DEFINE_NULL_INSTANCE (hb_face_t) =
90 {
91   HB_OBJECT_HEADER_STATIC,
92 
93   0,    /* index */
94   1000, /* upem */
95   0,    /* num_glyphs */
96 
97   /* Zero for the rest is fine. */
98 };
99 
100 
101 /**
102  * hb_face_create_for_tables:
103  * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function
104  * @user_data: A pointer to the user data
105  * @destroy: (nullable): A callback to call when @data is not needed anymore
106  *
107  * Variant of hb_face_create(), built for those cases where it is more
108  * convenient to provide data for individual tables instead of the whole font
109  * data. With the caveat that hb_face_get_table_tags() would not work
110  * with faces created this way. You can address that by calling the
111  * hb_face_set_get_table_tags_func() function and setting the appropriate callback.
112  *
113  * Creates a new face object from the specified @user_data and @reference_table_func,
114  * with the @destroy callback.
115  *
116  * Return value: (transfer full): The new face object
117  *
118  * Since: 0.9.2
119  **/
120 hb_face_t *
hb_face_create_for_tables(hb_reference_table_func_t reference_table_func,void * user_data,hb_destroy_func_t destroy)121 hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
122 			   void                      *user_data,
123 			   hb_destroy_func_t          destroy)
124 {
125   hb_face_t *face;
126 
127   if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {
128     if (destroy)
129       destroy (user_data);
130     return hb_face_get_empty ();
131   }
132 
133   face->reference_table_func = reference_table_func;
134   face->user_data = user_data;
135   face->destroy = destroy;
136 
137   face->num_glyphs = -1;
138 
139   face->data.init0 (face);
140   face->table.init0 (face);
141 
142   return face;
143 }
144 
145 
146 typedef struct hb_face_for_data_closure_t {
147   hb_blob_t *blob;
148   uint16_t  index;
149 } hb_face_for_data_closure_t;
150 
151 static hb_face_for_data_closure_t *
_hb_face_for_data_closure_create(hb_blob_t * blob,unsigned int index)152 _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
153 {
154   hb_face_for_data_closure_t *closure;
155 
156   closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t));
157   if (unlikely (!closure))
158     return nullptr;
159 
160   closure->blob = blob;
161   closure->index = (uint16_t) (index & 0xFFFFu);
162 
163   return closure;
164 }
165 
166 static void
_hb_face_for_data_closure_destroy(void * data)167 _hb_face_for_data_closure_destroy (void *data)
168 {
169   hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
170 
171   hb_blob_destroy (closure->blob);
172   hb_free (closure);
173 }
174 
175 static hb_blob_t *
_hb_face_for_data_reference_table(hb_face_t * face HB_UNUSED,hb_tag_t tag,void * user_data)176 _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
177 {
178   hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
179 
180   if (tag == HB_TAG_NONE)
181     return hb_blob_reference (data->blob);
182 
183   const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
184   unsigned int base_offset;
185   const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset);
186 
187   const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
188 
189   hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length);
190 
191   return blob;
192 }
193 
194 static unsigned
_hb_face_for_data_get_table_tags(const hb_face_t * face HB_UNUSED,unsigned int start_offset,unsigned int * table_count,hb_tag_t * table_tags,void * user_data)195 _hb_face_for_data_get_table_tags (const hb_face_t *face HB_UNUSED,
196 				  unsigned int start_offset,
197 				  unsigned int *table_count,
198 				  hb_tag_t *table_tags,
199 				  void *user_data)
200 {
201   hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
202 
203   const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
204   const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
205 
206   return ot_face.get_table_tags (start_offset, table_count, table_tags);
207 }
208 
209 
210 /**
211  * hb_face_create:
212  * @blob: #hb_blob_t to work upon
213  * @index: The index of the face within @blob
214  *
215  * Constructs a new face object from the specified blob and
216  * a face index into that blob.
217  *
218  * The face index is used for blobs of file formats such as TTC and
219  * DFont that can contain more than one face.  Face indices within
220  * such collections are zero-based.
221  *
222  * <note>Note: If the blob font format is not a collection, @index
223  * is ignored.  Otherwise, only the lower 16-bits of @index are used.
224  * The unmodified @index can be accessed via hb_face_get_index().</note>
225  *
226  * <note>Note: The high 16-bits of @index, if non-zero, are used by
227  * hb_font_create() to load named-instances in variable fonts.  See
228  * hb_font_create() for details.</note>
229  *
230  * Return value: (transfer full): The new face object
231  *
232  * Since: 0.9.2
233  **/
234 hb_face_t *
hb_face_create(hb_blob_t * blob,unsigned int index)235 hb_face_create (hb_blob_t    *blob,
236 		unsigned int  index)
237 {
238   hb_face_t *face;
239 
240   if (unlikely (!blob))
241     blob = hb_blob_get_empty ();
242 
243   blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
244 
245   hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index);
246 
247   if (unlikely (!closure))
248   {
249     hb_blob_destroy (blob);
250     return hb_face_get_empty ();
251   }
252 
253   face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
254 				    closure,
255 				    _hb_face_for_data_closure_destroy);
256   hb_face_set_get_table_tags_func (face,
257 				   _hb_face_for_data_get_table_tags,
258 				   closure,
259 				   nullptr);
260 
261   face->index = index;
262 
263   return face;
264 }
265 
266 /**
267  * hb_face_create_or_fail:
268  * @blob: #hb_blob_t to work upon
269  * @index: The index of the face within @blob
270  *
271  * Like hb_face_create(), but returns `NULL` if the blob data
272  * contains no usable font face at the specified index.
273  *
274  * Return value: (transfer full): The new face object, or `NULL` if
275  * no face is found at the specified index.
276  *
277  * Since: 10.1.0
278  **/
279 hb_face_t *
hb_face_create_or_fail(hb_blob_t * blob,unsigned int index)280 hb_face_create_or_fail (hb_blob_t    *blob,
281 			unsigned int  index)
282 {
283   unsigned num_faces = hb_face_count (blob);
284   if (index >= num_faces)
285     return nullptr;
286 
287   hb_face_t *face = hb_face_create (blob, index);
288   if (hb_object_is_immutable (face))
289     return nullptr;
290 
291   return face;
292 }
293 
294 /**
295  * hb_face_create_from_file_or_fail:
296  * @file_name: A font filename
297  * @index: The index of the face within the file
298  *
299  * A thin wrapper around hb_blob_create_from_file_or_fail()
300  * followed by hb_face_create_or_fail().
301  *
302  * Return value: (transfer full): The new face object, or `NULL` if
303  * no face is found at the specified index or the file cannot be read.
304  *
305  * Since: 10.1.0
306  **/
307 HB_EXTERN hb_face_t *
hb_face_create_from_file_or_fail(const char * file_name,unsigned int index)308 hb_face_create_from_file_or_fail (const char   *file_name,
309 				  unsigned int  index)
310 {
311   hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name);
312   if (unlikely (!blob))
313     return nullptr;
314 
315   hb_face_t *face = hb_face_create_or_fail (blob, index);
316   hb_blob_destroy (blob);
317 
318   return face;
319 }
320 
321 /**
322  * hb_face_get_empty:
323  *
324  * Fetches the singleton empty face object.
325  *
326  * Return value: (transfer full): The empty face object
327  *
328  * Since: 0.9.2
329  **/
330 hb_face_t *
hb_face_get_empty()331 hb_face_get_empty ()
332 {
333   return const_cast<hb_face_t *> (&Null (hb_face_t));
334 }
335 
336 
337 /**
338  * hb_face_reference: (skip)
339  * @face: A face object
340  *
341  * Increases the reference count on a face object.
342  *
343  * Return value: The @face object
344  *
345  * Since: 0.9.2
346  **/
347 hb_face_t *
hb_face_reference(hb_face_t * face)348 hb_face_reference (hb_face_t *face)
349 {
350   return hb_object_reference (face);
351 }
352 
353 /**
354  * hb_face_destroy: (skip)
355  * @face: A face object
356  *
357  * Decreases the reference count on a face object. When the
358  * reference count reaches zero, the face is destroyed,
359  * freeing all memory.
360  *
361  * Since: 0.9.2
362  **/
363 void
hb_face_destroy(hb_face_t * face)364 hb_face_destroy (hb_face_t *face)
365 {
366   if (!hb_object_destroy (face)) return;
367 
368 #ifndef HB_NO_SHAPER
369   for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
370   {
371     hb_face_t::plan_node_t *next = node->next;
372     hb_shape_plan_destroy (node->shape_plan);
373     hb_free (node);
374     node = next;
375   }
376 #endif
377 
378   face->data.fini ();
379   face->table.fini ();
380 
381   if (face->get_table_tags_destroy)
382     face->get_table_tags_destroy (face->get_table_tags_user_data);
383 
384   if (face->destroy)
385     face->destroy (face->user_data);
386 
387   hb_free (face);
388 }
389 
390 /**
391  * hb_face_set_user_data: (skip)
392  * @face: A face object
393  * @key: The user-data key to set
394  * @data: A pointer to the user data
395  * @destroy: (nullable): A callback to call when @data is not needed anymore
396  * @replace: Whether to replace an existing data with the same key
397  *
398  * Attaches a user-data key/data pair to the given face object.
399  *
400  * Return value: `true` if success, `false` otherwise
401  *
402  * Since: 0.9.2
403  **/
404 hb_bool_t
hb_face_set_user_data(hb_face_t * face,hb_user_data_key_t * key,void * data,hb_destroy_func_t destroy,hb_bool_t replace)405 hb_face_set_user_data (hb_face_t          *face,
406 		       hb_user_data_key_t *key,
407 		       void *              data,
408 		       hb_destroy_func_t   destroy,
409 		       hb_bool_t           replace)
410 {
411   return hb_object_set_user_data (face, key, data, destroy, replace);
412 }
413 
414 /**
415  * hb_face_get_user_data: (skip)
416  * @face: A face object
417  * @key: The user-data key to query
418  *
419  * Fetches the user data associated with the specified key,
420  * attached to the specified face object.
421  *
422  * Return value: (transfer none): A pointer to the user data
423  *
424  * Since: 0.9.2
425  **/
426 void *
hb_face_get_user_data(const hb_face_t * face,hb_user_data_key_t * key)427 hb_face_get_user_data (const hb_face_t    *face,
428 		       hb_user_data_key_t *key)
429 {
430   return hb_object_get_user_data (face, key);
431 }
432 
433 /**
434  * hb_face_make_immutable:
435  * @face: A face object
436  *
437  * Makes the given face object immutable.
438  *
439  * Since: 0.9.2
440  **/
441 void
hb_face_make_immutable(hb_face_t * face)442 hb_face_make_immutable (hb_face_t *face)
443 {
444   if (hb_object_is_immutable (face))
445     return;
446 
447   hb_object_make_immutable (face);
448 }
449 
450 /**
451  * hb_face_is_immutable:
452  * @face: A face object
453  *
454  * Tests whether the given face object is immutable.
455  *
456  * Return value: `true` is @face is immutable, `false` otherwise
457  *
458  * Since: 0.9.2
459  **/
460 hb_bool_t
hb_face_is_immutable(const hb_face_t * face)461 hb_face_is_immutable (const hb_face_t *face)
462 {
463   return hb_object_is_immutable (face);
464 }
465 
466 
467 /**
468  * hb_face_reference_table:
469  * @face: A face object
470  * @tag: The #hb_tag_t of the table to query
471  *
472  * Fetches a reference to the specified table within
473  * the specified face.
474  *
475  * Return value: (transfer full): A pointer to the @tag table within @face
476  *
477  * Since: 0.9.2
478  **/
479 hb_blob_t *
hb_face_reference_table(const hb_face_t * face,hb_tag_t tag)480 hb_face_reference_table (const hb_face_t *face,
481 			 hb_tag_t tag)
482 {
483   if (unlikely (tag == HB_TAG_NONE))
484     return hb_blob_get_empty ();
485 
486   return face->reference_table (tag);
487 }
488 
489 /**
490  * hb_face_reference_blob:
491  * @face: A face object
492  *
493  * Fetches a pointer to the binary blob that contains the
494  * specified face. Returns an empty blob if referencing face data is not
495  * possible.
496  *
497  * Return value: (transfer full): A pointer to the blob for @face
498  *
499  * Since: 0.9.2
500  **/
501 hb_blob_t *
hb_face_reference_blob(hb_face_t * face)502 hb_face_reference_blob (hb_face_t *face)
503 {
504   return face->reference_table (HB_TAG_NONE);
505 }
506 
507 /**
508  * hb_face_set_index:
509  * @face: A face object
510  * @index: The index to assign
511  *
512  * Assigns the specified face-index to @face. Fails if the
513  * face is immutable.
514  *
515  * <note>Note: changing the index has no effect on the face itself
516  * This only changes the value returned by hb_face_get_index().</note>
517  *
518  * Since: 0.9.2
519  **/
520 void
hb_face_set_index(hb_face_t * face,unsigned int index)521 hb_face_set_index (hb_face_t    *face,
522 		   unsigned int  index)
523 {
524   if (hb_object_is_immutable (face))
525     return;
526 
527   face->index = index;
528 }
529 
530 /**
531  * hb_face_get_index:
532  * @face: A face object
533  *
534  * Fetches the face-index corresponding to the given face.
535  *
536  * <note>Note: face indices within a collection are zero-based.</note>
537  *
538  * Return value: The index of @face.
539  *
540  * Since: 0.9.2
541  **/
542 unsigned int
hb_face_get_index(const hb_face_t * face)543 hb_face_get_index (const hb_face_t *face)
544 {
545   return face->index;
546 }
547 
548 /**
549  * hb_face_set_upem:
550  * @face: A face object
551  * @upem: The units-per-em value to assign
552  *
553  * Sets the units-per-em (upem) for a face object to the specified value.
554  *
555  * This API is used in rare circumstances.
556  *
557  * Since: 0.9.2
558  **/
559 void
hb_face_set_upem(hb_face_t * face,unsigned int upem)560 hb_face_set_upem (hb_face_t    *face,
561 		  unsigned int  upem)
562 {
563   if (hb_object_is_immutable (face))
564     return;
565 
566   face->upem = upem;
567 }
568 
569 /**
570  * hb_face_get_upem:
571  * @face: A face object
572  *
573  * Fetches the units-per-em (UPEM) value of the specified face object.
574  *
575  * Typical UPEM values for fonts are 1000, or 2048, but any value
576  * in between 16 and 16,384 is allowed for OpenType fonts.
577  *
578  * Return value: The upem value of @face
579  *
580  * Since: 0.9.2
581  **/
582 unsigned int
hb_face_get_upem(const hb_face_t * face)583 hb_face_get_upem (const hb_face_t *face)
584 {
585   return face->get_upem ();
586 }
587 
588 /**
589  * hb_face_set_glyph_count:
590  * @face: A face object
591  * @glyph_count: The glyph-count value to assign
592  *
593  * Sets the glyph count for a face object to the specified value.
594  *
595  * This API is used in rare circumstances.
596  *
597  * Since: 0.9.7
598  **/
599 void
hb_face_set_glyph_count(hb_face_t * face,unsigned int glyph_count)600 hb_face_set_glyph_count (hb_face_t    *face,
601 			 unsigned int  glyph_count)
602 {
603   if (hb_object_is_immutable (face))
604     return;
605 
606   face->num_glyphs = glyph_count;
607 }
608 
609 /**
610  * hb_face_get_glyph_count:
611  * @face: A face object
612  *
613  * Fetches the glyph-count value of the specified face object.
614  *
615  * Return value: The glyph-count value of @face
616  *
617  * Since: 0.9.7
618  **/
619 unsigned int
hb_face_get_glyph_count(const hb_face_t * face)620 hb_face_get_glyph_count (const hb_face_t *face)
621 {
622   return face->get_num_glyphs ();
623 }
624 
625 /**
626  * hb_face_set_get_table_tags_func:
627  * @face: A face object
628  * @func: (closure user_data) (destroy destroy) (scope notified): The table-tag-fetching function
629  * @user_data: A pointer to the user data, to be destroyed by @destroy when not needed anymore
630  * @destroy: (nullable): A callback to call when @func is not needed anymore
631  *
632  * Sets the table-tag-fetching function for the specified face object.
633  *
634  * Since: 10.0.0
635  */
636 HB_EXTERN void
hb_face_set_get_table_tags_func(hb_face_t * face,hb_get_table_tags_func_t func,void * user_data,hb_destroy_func_t destroy)637 hb_face_set_get_table_tags_func (hb_face_t *face,
638 				 hb_get_table_tags_func_t func,
639 				 void                    *user_data,
640 				 hb_destroy_func_t        destroy)
641 {
642   if (hb_object_is_immutable (face))
643   {
644     if (destroy)
645       destroy (user_data);
646   }
647 
648   if (face->get_table_tags_destroy)
649     face->get_table_tags_destroy (face->get_table_tags_user_data);
650 
651   face->get_table_tags_func = func;
652   face->get_table_tags_user_data = user_data;
653   face->get_table_tags_destroy = destroy;
654 }
655 
656 /**
657  * hb_face_get_table_tags:
658  * @face: A face object
659  * @start_offset: The index of first table tag to retrieve
660  * @table_count: (inout): Input = the maximum number of table tags to return;
661  *                Output = the actual number of table tags returned (may be zero)
662  * @table_tags: (out) (array length=table_count): The array of table tags found
663  *
664  * Fetches a list of all table tags for a face, if possible. The list returned will
665  * begin at the offset provided
666  *
667  * Return value: Total number of tables, or zero if it is not possible to list
668  *
669  * Since: 1.6.0
670  **/
671 unsigned int
hb_face_get_table_tags(const hb_face_t * face,unsigned int start_offset,unsigned int * table_count,hb_tag_t * table_tags)672 hb_face_get_table_tags (const hb_face_t *face,
673 			unsigned int  start_offset,
674 			unsigned int *table_count, /* IN/OUT */
675 			hb_tag_t     *table_tags /* OUT */)
676 {
677   if (!face->get_table_tags_func)
678   {
679     if (table_count)
680       *table_count = 0;
681     return 0;
682   }
683 
684   return face->get_table_tags_func (face, start_offset, table_count, table_tags, face->get_table_tags_user_data);
685 }
686 
687 
688 /*
689  * Character set.
690  */
691 
692 
693 #ifndef HB_NO_FACE_COLLECT_UNICODES
694 /**
695  * hb_face_collect_unicodes:
696  * @face: A face object
697  * @out: (out): The set to add Unicode characters to
698  *
699  * Collects all of the Unicode characters covered by @face and adds
700  * them to the #hb_set_t set @out.
701  *
702  * Since: 1.9.0
703  */
704 void
hb_face_collect_unicodes(hb_face_t * face,hb_set_t * out)705 hb_face_collect_unicodes (hb_face_t *face,
706 			  hb_set_t  *out)
707 {
708   face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
709 }
710 /**
711  * hb_face_collect_nominal_glyph_mapping:
712  * @face: A face object
713  * @mapping: (out): The map to add Unicode-to-glyph mapping to
714  * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL`
715  *
716  * Collects the mapping from Unicode characters to nominal glyphs of the @face,
717  * and optionally all of the Unicode characters covered by @face.
718  *
719  * Since: 7.0.0
720  */
721 void
hb_face_collect_nominal_glyph_mapping(hb_face_t * face,hb_map_t * mapping,hb_set_t * unicodes)722 hb_face_collect_nominal_glyph_mapping (hb_face_t *face,
723 				       hb_map_t  *mapping,
724 				       hb_set_t  *unicodes)
725 {
726   hb_set_t stack_unicodes;
727   if (!unicodes)
728     unicodes = &stack_unicodes;
729   face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ());
730 }
731 /**
732  * hb_face_collect_variation_selectors:
733  * @face: A face object
734  * @out: (out): The set to add Variation Selector characters to
735  *
736  * Collects all Unicode "Variation Selector" characters covered by @face and adds
737  * them to the #hb_set_t set @out.
738  *
739  * Since: 1.9.0
740  */
741 void
hb_face_collect_variation_selectors(hb_face_t * face,hb_set_t * out)742 hb_face_collect_variation_selectors (hb_face_t *face,
743 				     hb_set_t  *out)
744 {
745   face->table.cmap->collect_variation_selectors (out);
746 }
747 /**
748  * hb_face_collect_variation_unicodes:
749  * @face: A face object
750  * @variation_selector: The Variation Selector to query
751  * @out: (out): The set to add Unicode characters to
752  *
753  * Collects all Unicode characters for @variation_selector covered by @face and adds
754  * them to the #hb_set_t set @out.
755  *
756  * Since: 1.9.0
757  */
758 void
hb_face_collect_variation_unicodes(hb_face_t * face,hb_codepoint_t variation_selector,hb_set_t * out)759 hb_face_collect_variation_unicodes (hb_face_t *face,
760 				    hb_codepoint_t variation_selector,
761 				    hb_set_t  *out)
762 {
763   face->table.cmap->collect_variation_unicodes (variation_selector, out);
764 }
765 #endif
766