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