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