blob: 867c172a119885e4a52a9ef8f23efe4b66004643 [file] [log] [blame]
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -04001/*
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
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070029#include "hb.hh"
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040030
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070031#include "hb-face.hh"
32#include "hb-blob.hh"
33#include "hb-open-file.hh"
Behdad Esfahboda84309a2018-08-26 09:33:01 -070034#include "hb-ot-face.hh"
Behdad Esfahbod3a0b3a22018-08-26 15:11:24 -070035#include "hb-ot-cmap-table.hh"
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040036
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040037
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043038/**
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -070039 * SECTION:hb-face
Behdad Esfahbodcf5fa572018-10-27 04:50:38 -070040 * @title: hb-face
Behdad Esfahbod5dd86aa2018-10-27 04:28:40 -070041 * @short_description: Font face objects
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -070042 * @include: hb.h
43 *
Nathan Willis3e72feb2019-04-22 19:21:27 +010044 * 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.
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -070048 * 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/**
Behdad Esfahbod55bae682018-09-24 10:43:06 -040054 * hb_face_count:
55 * @blob: a blob.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043056 *
Nathan Willis3e72feb2019-04-22 19:21:27 +010057 * Fetches the number of faces in a blob.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043058 *
Behdad Esfahbod55bae682018-09-24 10:43:06 -040059 * Return value: Number of faces in @blob
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043060 *
Behdad Esfahboddf01f3e2018-06-05 15:17:39 -070061 * Since: 1.7.7
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043062 **/
63unsigned int
64hb_face_count (hb_blob_t *blob)
65{
66 if (unlikely (!blob))
67 return 0;
68
Behdad Esfahbod1e9e3442018-07-17 19:17:59 +020069 /* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -070070 /* Make API signature const after. */
Behdad Esfahboded7b2e52018-08-01 23:59:09 -070071 hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
Ebrahim Byagowi8220ef82018-06-05 22:50:53 +043072 const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
Behdad Esfahbod1e9e3442018-07-17 19:17:59 +020073 unsigned int ret = ot.get_face_count ();
74 hb_blob_destroy (sanitized);
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043075
Behdad Esfahbod1e9e3442018-07-17 19:17:59 +020076 return ret;
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043077}
78
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040079/*
80 * hb_face_t
81 */
82
Behdad Esfahbod35066722018-08-06 06:17:48 -070083DEFINE_NULL_INSTANCE (hb_face_t) =
84{
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040085 HB_OBJECT_HEADER_STATIC,
86
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +020087 nullptr, /* reference_table_func */
88 nullptr, /* user_data */
89 nullptr, /* destroy */
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040090
91 0, /* index */
Behdad Esfahbod140797d2020-06-29 03:51:09 -070092 1000, /* upem */
93 0, /* num_glyphs */
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040094
Behdad Esfahbode88d47b2018-11-11 16:25:43 -050095 /* Zero for the rest is fine. */
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040096};
97
98
Behdad Esfahbod288f2892013-09-06 15:40:22 -040099/**
100 * hb_face_create_for_tables:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100101 * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function
102 * @user_data: A pointer to the user data
Khaled Hosny99364902020-12-31 00:19:29 +0200103 * @destroy: (nullable): A callback to call when @data is not needed anymore
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400104 *
Khaled Hosnycc7b3a12020-09-26 10:22:39 +0200105 * 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.
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200109 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100110 * Creates a new face object from the specified @user_data and @reference_table_func,
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200111 * with the @destroy callback.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400112 *
n8willis41b46a32020-04-26 16:01:31 +0100113 * Return value: (transfer full): The new face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400114 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430115 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400116 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400117hb_face_t *
118hb_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
Behdad Esfahbodfc44dea2018-11-13 11:54:33 -0500134 face->num_glyphs.set_relaxed (-1);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400135
Behdad Esfahbodce5da0f2018-11-16 02:29:13 -0500136 face->data.init0 (face);
Behdad Esfahbod914b5952018-11-05 22:39:50 -0500137 face->table.init0 (face);
138
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400139 return face;
140}
141
142
143typedef struct hb_face_for_data_closure_t {
144 hb_blob_t *blob;
145 unsigned int index;
146} hb_face_for_data_closure_t;
147
148static hb_face_for_data_closure_t *
149_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
150{
151 hb_face_for_data_closure_t *closure;
152
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600153 closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t));
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400154 if (unlikely (!closure))
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200155 return nullptr;
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400156
157 closure->blob = blob;
158 closure->index = index;
159
160 return closure;
161}
162
163static void
Behdad Esfahbode1b6d922017-10-11 15:51:31 +0200164_hb_face_for_data_closure_destroy (void *data)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400165{
Behdad Esfahbode1b6d922017-10-11 15:51:31 +0200166 hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
167
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400168 hb_blob_destroy (closure->blob);
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600169 hb_free (closure);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400170}
171
172static hb_blob_t *
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
Behdad Esfahbodeba1c162018-05-08 02:47:42 -0700180 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
Behdad Esfahbod9479ffe2018-09-11 16:41:26 +0200181 unsigned int base_offset;
182 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400183
184 const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
185
Behdad Esfahbod9479ffe2018-09-11 16:41:26 +0200186 hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400187
188 return blob;
189}
190
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400191/**
Behdad Esfahbod085d4292013-09-12 17:14:33 -0400192 * hb_face_create: (Xconstructor)
Nathan Willis3e72feb2019-04-22 19:21:27 +0100193 * @blob: #hb_blob_t to work upon
194 * @index: The index of the face within @blob
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400195 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100196 * Constructs a new face object from the specified blob and
n8willis726e3202020-04-26 15:56:57 +0100197 * 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.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430200 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100201 * Return value: (transfer full): The new face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400202 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430203 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400204 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400205hb_face_t *
206hb_face_create (hb_blob_t *blob,
207 unsigned int index)
208{
209 hb_face_t *face;
210
Behdad Esfahbodeb0bf3a2014-08-06 15:36:41 -0400211 if (unlikely (!blob))
212 blob = hb_blob_get_empty ();
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400213
Sebastian Rasmussen12a9d572020-06-24 03:25:43 +0800214 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);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400217
218 if (unlikely (!closure))
Sebastian Rasmussen12a9d572020-06-24 03:25:43 +0800219 {
220 hb_blob_destroy (blob);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400221 return hb_face_get_empty ();
Sebastian Rasmussen12a9d572020-06-24 03:25:43 +0800222 }
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400223
224 face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
225 closure,
Behdad Esfahbode1b6d922017-10-11 15:51:31 +0200226 _hb_face_for_data_closure_destroy);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400227
Behdad Esfahbodd3d36912017-02-03 15:42:03 -0800228 face->index = index;
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400229
230 return face;
231}
232
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400233/**
234 * hb_face_get_empty:
235 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100236 * Fetches the singleton empty face object.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430237 *
Khaled Hosny3d7a3612020-12-30 23:58:37 +0200238 * Return value: (transfer full): The empty face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400239 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430240 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400241 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400242hb_face_t *
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330243hb_face_get_empty ()
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400244{
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430245 return const_cast<hb_face_t *> (&Null (hb_face_t));
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400246}
247
248
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400249/**
250 * hb_face_reference: (skip)
Nathan Willis3e72feb2019-04-22 19:21:27 +0100251 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400252 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100253 * Increases the reference count on a face object.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400254 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100255 * Return value: The @face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400256 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430257 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400258 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400259hb_face_t *
260hb_face_reference (hb_face_t *face)
261{
262 return hb_object_reference (face);
263}
264
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400265/**
266 * hb_face_destroy: (skip)
Nathan Willis3e72feb2019-04-22 19:21:27 +0100267 * @face: A face object
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200268 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100269 * Decreases the reference count on a face object. When the
270 * reference count reaches zero, the face is destroyed,
271 * freeing all memory.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400272 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430273 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400274 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400275void
276hb_face_destroy (hb_face_t *face)
277{
278 if (!hb_object_destroy (face)) return;
279
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500280 for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400281 {
282 hb_face_t::plan_node_t *next = node->next;
283 hb_shape_plan_destroy (node->shape_plan);
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600284 hb_free (node);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400285 node = next;
286 }
287
Behdad Esfahbodce5da0f2018-11-16 02:29:13 -0500288 face->data.fini ();
Behdad Esfahbod914b5952018-11-05 22:39:50 -0500289 face->table.fini ();
290
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400291 if (face->destroy)
292 face->destroy (face->user_data);
293
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600294 hb_free (face);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400295}
296
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400297/**
298 * hb_face_set_user_data: (skip)
Nathan Willis3e72feb2019-04-22 19:21:27 +0100299 * @face: A face object
300 * @key: The user-data key to set
301 * @data: A pointer to the user data
Khaled Hosny99364902020-12-31 00:19:29 +0200302 * @destroy: (nullable): A callback to call when @data is not needed anymore
Nathan Willis3e72feb2019-04-22 19:21:27 +0100303 * @replace: Whether to replace an existing data with the same key
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400304 *
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200305 * Attaches a user-data key/data pair to the given face object.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400306 *
Khaled Hosnyf88e8452020-12-24 21:28:37 +0200307 * Return value: %true if success, %false otherwise
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400308 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430309 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400310 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400311hb_bool_t
312hb_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
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400321/**
322 * hb_face_get_user_data: (skip)
Nathan Willis3e72feb2019-04-22 19:21:27 +0100323 * @face: A face object
324 * @key: The user-data key to query
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400325 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100326 * Fetches the user data associated with the specified key,
327 * attached to the specified face object.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430328 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100329 * Return value: (transfer none): A pointer to the user data
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400330 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430331 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400332 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400333void *
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700334hb_face_get_user_data (const hb_face_t *face,
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400335 hb_user_data_key_t *key)
336{
337 return hb_object_get_user_data (face, key);
338}
339
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400340/**
341 * hb_face_make_immutable:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100342 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400343 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100344 * Makes the given face object immutable.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400345 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430346 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400347 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400348void
349hb_face_make_immutable (hb_face_t *face)
350{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400351 if (hb_object_is_immutable (face))
Behdad Esfahbod90a0f9f2018-09-26 15:03:07 -0400352 return;
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400353
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400354 hb_object_make_immutable (face);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400355}
356
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400357/**
358 * hb_face_is_immutable:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100359 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400360 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100361 * Tests whether the given face object is immutable.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400362 *
Khaled Hosnya8e72ee2020-12-30 23:08:40 +0200363 * Return value: %true is @face is immutable, %false otherwise
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400364 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430365 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400366 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400367hb_bool_t
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700368hb_face_is_immutable (const hb_face_t *face)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400369{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400370 return hb_object_is_immutable (face);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400371}
372
373
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400374/**
375 * hb_face_reference_table:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100376 * @face: A face object
377 * @tag: The #hb_tag_t of the table to query
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400378 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100379 * Fetches a reference to the specified table within
380 * the specified face.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430381 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100382 * Return value: (transfer full): A pointer to the @tag table within @face
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400383 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430384 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400385 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400386hb_blob_t *
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700387hb_face_reference_table (const hb_face_t *face,
388 hb_tag_t tag)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400389{
Ebrahim Byagowif441a7c2019-09-01 02:18:09 +0430390 if (unlikely (tag == HB_TAG_NONE))
391 return hb_blob_get_empty ();
392
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400393 return face->reference_table (tag);
394}
395
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400396/**
397 * hb_face_reference_blob:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100398 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400399 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100400 * Fetches a pointer to the binary blob that contains the
Khaled Hosnycc7b3a12020-09-26 10:22:39 +0200401 * specified face. Returns an empty blob if referencing face data is not
402 * possible.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430403 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100404 * Return value: (transfer full): A pointer to the blob for @face
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400405 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200406 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400407 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400408hb_blob_t *
409hb_face_reference_blob (hb_face_t *face)
410{
411 return face->reference_table (HB_TAG_NONE);
412}
413
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400414/**
415 * hb_face_set_index:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100416 * @face: A face object
417 * @index: The index to assign
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400418 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100419 * Assigns the specified face-index to @face. Fails if the
420 * face is immutable.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430421 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100422 * <note>Note: face indices within a collection are zero-based.</note>
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400423 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200424 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400425 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400426void
427hb_face_set_index (hb_face_t *face,
428 unsigned int index)
429{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400430 if (hb_object_is_immutable (face))
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400431 return;
432
433 face->index = index;
434}
435
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400436/**
437 * hb_face_get_index:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100438 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400439 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100440 * Fetches the face-index corresponding to the given face.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400441 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100442 * <note>Note: face indices within a collection are zero-based.</note>
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430443 *
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200444 * Return value: The index of @face.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400445 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200446 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400447 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400448unsigned int
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700449hb_face_get_index (const hb_face_t *face)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400450{
451 return face->index;
452}
453
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400454/**
455 * hb_face_set_upem:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100456 * @face: A face object
457 * @upem: The units-per-em value to assign
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400458 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100459 * Sets the units-per-em (upem) for a face object to the specified value.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400460 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200461 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400462 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400463void
464hb_face_set_upem (hb_face_t *face,
465 unsigned int upem)
466{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400467 if (hb_object_is_immutable (face))
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400468 return;
469
Behdad Esfahbodfc44dea2018-11-13 11:54:33 -0500470 face->upem.set_relaxed (upem);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400471}
472
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400473/**
474 * hb_face_get_upem:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100475 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400476 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100477 * Fetches the units-per-em (upem) value of the specified face object.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400478 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100479 * Return value: The upem value of @face
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400480 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430481 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400482 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400483unsigned int
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700484hb_face_get_upem (const hb_face_t *face)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400485{
486 return face->get_upem ();
487}
488
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400489/**
490 * hb_face_set_glyph_count:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100491 * @face: A face object
492 * @glyph_count: The glyph-count value to assign
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400493 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100494 * Sets the glyph count for a face object to the specified value.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400495 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200496 * Since: 0.9.7
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400497 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400498void
499hb_face_set_glyph_count (hb_face_t *face,
500 unsigned int glyph_count)
501{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400502 if (hb_object_is_immutable (face))
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400503 return;
504
Behdad Esfahbodfc44dea2018-11-13 11:54:33 -0500505 face->num_glyphs.set_relaxed (glyph_count);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400506}
507
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400508/**
509 * hb_face_get_glyph_count:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100510 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400511 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100512 * Fetches the glyph-count value of the specified face object.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400513 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100514 * Return value: The glyph-count value of @face
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400515 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200516 * Since: 0.9.7
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400517 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400518unsigned int
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700519hb_face_get_glyph_count (const hb_face_t *face)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400520{
521 return face->get_num_glyphs ();
522}
523
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200524/**
525 * hb_face_get_table_tags:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100526 * @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
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200531 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100532 * Fetches a list of all table tags for a face, if possible. The list returned will
533 * begin at the offset provided
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200534 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100535 * Return value: Total number of tables, or zero if it is not possible to list
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200536 *
537 * Since: 1.6.0
538 **/
539unsigned int
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700540hb_face_get_table_tags (const hb_face_t *face,
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200541 unsigned int start_offset,
542 unsigned int *table_count, /* IN/OUT */
543 hb_tag_t *table_tags /* OUT */)
544{
prrace498e4372018-06-09 16:04:28 -0700545 if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200546 {
547 if (table_count)
548 *table_count = 0;
549 return 0;
550 }
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400551
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200552 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
553
Behdad Esfahbodeba1c162018-05-08 02:47:42 -0700554 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200555 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}
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700559
560
561/*
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700562 * Character set.
563 */
564
Behdad Esfahboda84309a2018-08-26 09:33:01 -0700565
Behdad Esfahbod27de7c42019-06-19 20:07:02 -0700566#ifndef HB_NO_FACE_COLLECT_UNICODES
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700567/**
568 * hb_face_collect_unicodes:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100569 * @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.
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700574 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200575 * Since: 1.9.0
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700576 */
577void
578hb_face_collect_unicodes (hb_face_t *face,
579 hb_set_t *out)
580{
Michiharu Ariza5ab50ee2020-02-29 01:32:29 -0800581 face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700582}
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700583/**
584 * hb_face_collect_variation_selectors:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100585 * @face: A face object
586 * @out: The set to add Variation Selector characters to
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700587 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100588 * Collects all Unicode "Variation Selector" characters covered by @face and adds
589 * them to the #hb_set_t set @out.
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700590 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200591 * Since: 1.9.0
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700592 */
593void
594hb_face_collect_variation_selectors (hb_face_t *face,
595 hb_set_t *out)
596{
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -0500597 face->table.cmap->collect_variation_selectors (out);
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700598}
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700599/**
600 * hb_face_collect_variation_unicodes:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100601 * @face: A face object
602 * @variation_selector: The Variation Selector to query
603 * @out: The set to add Unicode characters to
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700604 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100605 * Collects all Unicode characters for @variation_selector covered by @face and adds
606 * them to the #hb_set_t set @out.
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700607 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200608 * Since: 1.9.0
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700609 */
610void
611hb_face_collect_variation_unicodes (hb_face_t *face,
612 hb_codepoint_t variation_selector,
613 hb_set_t *out)
614{
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -0500615 face->table.cmap->collect_variation_unicodes (variation_selector, out);
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700616}
Behdad Esfahbod27de7c42019-06-19 20:07:02 -0700617#endif
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700618
619
620/*
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700621 * face-builder: A face that has add_table().
622 */
623
624struct hb_face_builder_data_t
625{
626 struct table_entry_t
627 {
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330628 int cmp (hb_tag_t t) const
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700629 {
Behdad Esfahbod96cf0882018-11-24 01:07:15 -0500630 if (t < tag) return -1;
631 if (t > tag) return -1;
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700632 return 0;
633 }
634
635 hb_tag_t tag;
636 hb_blob_t *blob;
637 };
638
Behdad Esfahbodfa333e32018-12-27 17:56:22 -0500639 hb_vector_t<table_entry_t> tables;
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700640};
641
642static hb_face_builder_data_t *
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330643_hb_face_builder_data_create ()
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700644{
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600645 hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t));
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700646 if (unlikely (!data))
647 return nullptr;
648
649 data->tables.init ();
650
651 return data;
652}
653
654static void
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
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500659 for (unsigned int i = 0; i < data->tables.length; i++)
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700660 hb_blob_destroy (data->tables[i].blob);
661
662 data->tables.fini ();
663
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600664 hb_free (data);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700665}
666
667static hb_blob_t *
668_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
669{
670
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500671 unsigned int table_count = data->tables.length;
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700672 unsigned int face_length = table_count * 16 + 12;
673
674 for (unsigned int i = 0; i < table_count; i++)
Behdad Esfahbod341206e2018-10-05 18:39:48 +0200675 face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700676
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600677 char *buf = (char *) hb_malloc (face_length);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700678 if (unlikely (!buf))
679 return nullptr;
680
681 hb_serialize_context_t c (buf, face_length);
Behdad Esfahbodf9417af2018-12-18 13:23:32 -0500682 c.propagate_error (data->tables);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700683 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
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500688 bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700689
690 c.end_serialize ();
691
692 if (unlikely (!ret))
693 {
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600694 hb_free (buf);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700695 return nullptr;
696 }
697
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600698 return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700699}
700
701static hb_blob_t *
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700702_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700703{
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 *
HinTakbd1be872018-10-03 07:11:22 +0800724 * Return value: (transfer full): New face.
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700725 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200726 * Since: 1.9.0
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700727 **/
728hb_face_t *
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330729hb_face_builder_create ()
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700730{
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:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100741 * @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
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700744 *
745 * Add table for @tag with data provided by @blob to the face. @face must
746 * be created using hb_face_builder_create().
747 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200748 * Since: 1.9.0
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700749 **/
750hb_bool_t
751hb_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;
Garret Riegerdae32b42020-07-28 18:31:46 -0700757
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700758 hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
Behdad Esfahbodd7e2a512021-02-11 10:55:03 -0700759 if (unlikely (data->tables.in_error()))
Garret Riegerdae32b42020-07-28 18:31:46 -0700760 return false;
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700761
762 entry->tag = tag;
763 entry->blob = hb_blob_reference (blob);
764
765 return true;
766}