blob: 61adbdd503c871d46ecd6046fcadbc332515b163 [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"
Garret Riegerdea0fe52021-08-04 16:36:20 -070036#include "hb-map.hh"
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040037
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040038
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043039/**
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -070040 * SECTION:hb-face
Behdad Esfahbodcf5fa572018-10-27 04:50:38 -070041 * @title: hb-face
Behdad Esfahbod5dd86aa2018-10-27 04:28:40 -070042 * @short_description: Font face objects
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -070043 * @include: hb.h
44 *
Nathan Willis3e72feb2019-04-22 19:21:27 +010045 * 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.
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -070049 * 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/**
Behdad Esfahbod55bae682018-09-24 10:43:06 -040055 * hb_face_count:
56 * @blob: a blob.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043057 *
Nathan Willis3e72feb2019-04-22 19:21:27 +010058 * Fetches the number of faces in a blob.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043059 *
Behdad Esfahbod55bae682018-09-24 10:43:06 -040060 * Return value: Number of faces in @blob
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043061 *
Behdad Esfahboddf01f3e2018-06-05 15:17:39 -070062 * Since: 1.7.7
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043063 **/
64unsigned int
65hb_face_count (hb_blob_t *blob)
66{
67 if (unlikely (!blob))
68 return 0;
69
Behdad Esfahbod1e9e3442018-07-17 19:17:59 +020070 /* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -070071 /* Make API signature const after. */
Behdad Esfahboded7b2e52018-08-01 23:59:09 -070072 hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
Ebrahim Byagowi8220ef82018-06-05 22:50:53 +043073 const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
Behdad Esfahbod1e9e3442018-07-17 19:17:59 +020074 unsigned int ret = ot.get_face_count ();
75 hb_blob_destroy (sanitized);
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043076
Behdad Esfahbod1e9e3442018-07-17 19:17:59 +020077 return ret;
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +043078}
79
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040080/*
81 * hb_face_t
82 */
83
Behdad Esfahbod35066722018-08-06 06:17:48 -070084DEFINE_NULL_INSTANCE (hb_face_t) =
85{
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040086 HB_OBJECT_HEADER_STATIC,
87
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +020088 nullptr, /* reference_table_func */
89 nullptr, /* user_data */
90 nullptr, /* destroy */
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040091
92 0, /* index */
Behdad Esfahbod140797d2020-06-29 03:51:09 -070093 1000, /* upem */
94 0, /* num_glyphs */
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040095
Behdad Esfahbode88d47b2018-11-11 16:25:43 -050096 /* Zero for the rest is fine. */
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -040097};
98
99
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400100/**
101 * hb_face_create_for_tables:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100102 * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function
103 * @user_data: A pointer to the user data
Khaled Hosny99364902020-12-31 00:19:29 +0200104 * @destroy: (nullable): A callback to call when @data is not needed anymore
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400105 *
Khaled Hosnycc7b3a12020-09-26 10:22:39 +0200106 * 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.
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200110 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100111 * Creates a new face object from the specified @user_data and @reference_table_func,
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200112 * with the @destroy callback.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400113 *
n8willis41b46a32020-04-26 16:01:31 +0100114 * Return value: (transfer full): The new face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400115 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430116 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400117 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400118hb_face_t *
119hb_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
Behdad Esfahbodfc44dea2018-11-13 11:54:33 -0500135 face->num_glyphs.set_relaxed (-1);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400136
Behdad Esfahbodce5da0f2018-11-16 02:29:13 -0500137 face->data.init0 (face);
Behdad Esfahbod914b5952018-11-05 22:39:50 -0500138 face->table.init0 (face);
139
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400140 return face;
141}
142
143
144typedef struct hb_face_for_data_closure_t {
145 hb_blob_t *blob;
Behdad Esfahbodda7dba02022-01-01 11:20:20 -0700146 uint16_t index;
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400147} hb_face_for_data_closure_t;
148
149static hb_face_for_data_closure_t *
150_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
151{
152 hb_face_for_data_closure_t *closure;
153
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600154 closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t));
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400155 if (unlikely (!closure))
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200156 return nullptr;
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400157
158 closure->blob = blob;
Behdad Esfahbodda7dba02022-01-01 11:20:20 -0700159 closure->index = (uint16_t) (index & 0xFFFFu);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400160
161 return closure;
162}
163
164static void
Behdad Esfahbode1b6d922017-10-11 15:51:31 +0200165_hb_face_for_data_closure_destroy (void *data)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400166{
Behdad Esfahbode1b6d922017-10-11 15:51:31 +0200167 hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
168
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400169 hb_blob_destroy (closure->blob);
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600170 hb_free (closure);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400171}
172
173static hb_blob_t *
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
Behdad Esfahbodeba1c162018-05-08 02:47:42 -0700181 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
Behdad Esfahbod9479ffe2018-09-11 16:41:26 +0200182 unsigned int base_offset;
183 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400184
185 const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
186
Behdad Esfahbod9479ffe2018-09-11 16:41:26 +0200187 hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400188
189 return blob;
190}
191
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400192/**
Behdad Esfahbodf78a2502022-06-05 00:55:35 -0600193 * hb_face_create:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100194 * @blob: #hb_blob_t to work upon
195 * @index: The index of the face within @blob
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400196 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100197 * Constructs a new face object from the specified blob and
Behdad Esfahbodda7dba02022-01-01 11:20:20 -0700198 * 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>
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430207 *
Behdad Esfahbod2d42fc92022-01-02 07:45:10 -0700208 * <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 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100212 * Return value: (transfer full): The new face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400213 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430214 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400215 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400216hb_face_t *
217hb_face_create (hb_blob_t *blob,
218 unsigned int index)
219{
220 hb_face_t *face;
221
Behdad Esfahbodeb0bf3a2014-08-06 15:36:41 -0400222 if (unlikely (!blob))
223 blob = hb_blob_get_empty ();
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400224
Sebastian Rasmussen12a9d572020-06-24 03:25:43 +0800225 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);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400228
229 if (unlikely (!closure))
Sebastian Rasmussen12a9d572020-06-24 03:25:43 +0800230 {
231 hb_blob_destroy (blob);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400232 return hb_face_get_empty ();
Sebastian Rasmussen12a9d572020-06-24 03:25:43 +0800233 }
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400234
235 face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
236 closure,
Behdad Esfahbode1b6d922017-10-11 15:51:31 +0200237 _hb_face_for_data_closure_destroy);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400238
Behdad Esfahbodd3d36912017-02-03 15:42:03 -0800239 face->index = index;
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400240
241 return face;
242}
243
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400244/**
245 * hb_face_get_empty:
246 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100247 * Fetches the singleton empty face object.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430248 *
Khaled Hosny3d7a3612020-12-30 23:58:37 +0200249 * Return value: (transfer full): The empty face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400250 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430251 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400252 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400253hb_face_t *
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330254hb_face_get_empty ()
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400255{
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430256 return const_cast<hb_face_t *> (&Null (hb_face_t));
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400257}
258
259
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400260/**
261 * hb_face_reference: (skip)
Nathan Willis3e72feb2019-04-22 19:21:27 +0100262 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400263 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100264 * Increases the reference count on a face object.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400265 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100266 * Return value: The @face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400267 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430268 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400269 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400270hb_face_t *
271hb_face_reference (hb_face_t *face)
272{
273 return hb_object_reference (face);
274}
275
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400276/**
277 * hb_face_destroy: (skip)
Nathan Willis3e72feb2019-04-22 19:21:27 +0100278 * @face: A face object
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200279 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100280 * Decreases the reference count on a face object. When the
281 * reference count reaches zero, the face is destroyed,
282 * freeing all memory.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400283 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430284 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400285 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400286void
287hb_face_destroy (hb_face_t *face)
288{
289 if (!hb_object_destroy (face)) return;
290
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500291 for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400292 {
293 hb_face_t::plan_node_t *next = node->next;
294 hb_shape_plan_destroy (node->shape_plan);
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600295 hb_free (node);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400296 node = next;
297 }
298
Behdad Esfahbodce5da0f2018-11-16 02:29:13 -0500299 face->data.fini ();
Behdad Esfahbod914b5952018-11-05 22:39:50 -0500300 face->table.fini ();
301
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400302 if (face->destroy)
303 face->destroy (face->user_data);
304
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600305 hb_free (face);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400306}
307
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400308/**
309 * hb_face_set_user_data: (skip)
Nathan Willis3e72feb2019-04-22 19:21:27 +0100310 * @face: A face object
311 * @key: The user-data key to set
312 * @data: A pointer to the user data
Khaled Hosny99364902020-12-31 00:19:29 +0200313 * @destroy: (nullable): A callback to call when @data is not needed anymore
Nathan Willis3e72feb2019-04-22 19:21:27 +0100314 * @replace: Whether to replace an existing data with the same key
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400315 *
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200316 * Attaches a user-data key/data pair to the given face object.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400317 *
Khaled Hosny98e90cc2022-06-30 08:43:57 +0200318 * Return value: `true` if success, `false` otherwise
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400319 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430320 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400321 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400322hb_bool_t
323hb_face_set_user_data (hb_face_t *face,
324 hb_user_data_key_t *key,
325 void * data,
326 hb_destroy_func_t destroy,
327 hb_bool_t replace)
328{
329 return hb_object_set_user_data (face, key, data, destroy, replace);
330}
331
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400332/**
333 * hb_face_get_user_data: (skip)
Nathan Willis3e72feb2019-04-22 19:21:27 +0100334 * @face: A face object
335 * @key: The user-data key to query
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400336 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100337 * Fetches the user data associated with the specified key,
338 * attached to the specified face object.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430339 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100340 * Return value: (transfer none): A pointer to the user data
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400341 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430342 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400343 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400344void *
Behdad Esfahbod1945b402022-07-25 10:45:55 -0600345hb_face_get_user_data (const hb_face_t *face,
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400346 hb_user_data_key_t *key)
347{
348 return hb_object_get_user_data (face, key);
349}
350
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400351/**
352 * hb_face_make_immutable:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100353 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400354 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100355 * Makes the given face object immutable.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400356 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430357 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400358 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400359void
360hb_face_make_immutable (hb_face_t *face)
361{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400362 if (hb_object_is_immutable (face))
Behdad Esfahbod90a0f9f2018-09-26 15:03:07 -0400363 return;
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400364
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400365 hb_object_make_immutable (face);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400366}
367
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400368/**
369 * hb_face_is_immutable:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100370 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400371 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100372 * Tests whether the given face object is immutable.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400373 *
Khaled Hosny98e90cc2022-06-30 08:43:57 +0200374 * Return value: `true` is @face is immutable, `false` otherwise
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400375 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430376 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400377 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400378hb_bool_t
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700379hb_face_is_immutable (const hb_face_t *face)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400380{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400381 return hb_object_is_immutable (face);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400382}
383
384
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400385/**
386 * hb_face_reference_table:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100387 * @face: A face object
388 * @tag: The #hb_tag_t of the table to query
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400389 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100390 * Fetches a reference to the specified table within
391 * the specified face.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430392 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100393 * Return value: (transfer full): A pointer to the @tag table within @face
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400394 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430395 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400396 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400397hb_blob_t *
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700398hb_face_reference_table (const hb_face_t *face,
399 hb_tag_t tag)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400400{
Ebrahim Byagowif441a7c2019-09-01 02:18:09 +0430401 if (unlikely (tag == HB_TAG_NONE))
402 return hb_blob_get_empty ();
403
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400404 return face->reference_table (tag);
405}
406
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400407/**
408 * hb_face_reference_blob:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100409 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400410 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100411 * Fetches a pointer to the binary blob that contains the
Khaled Hosnycc7b3a12020-09-26 10:22:39 +0200412 * specified face. Returns an empty blob if referencing face data is not
413 * possible.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430414 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100415 * Return value: (transfer full): A pointer to the blob for @face
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400416 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200417 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400418 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400419hb_blob_t *
420hb_face_reference_blob (hb_face_t *face)
421{
422 return face->reference_table (HB_TAG_NONE);
423}
424
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400425/**
426 * hb_face_set_index:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100427 * @face: A face object
428 * @index: The index to assign
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400429 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100430 * Assigns the specified face-index to @face. Fails if the
431 * face is immutable.
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430432 *
Behdad Esfahbodda7dba02022-01-01 11:20:20 -0700433 * <note>Note: changing the index has no effect on the face itself
434 * This only changes the value returned by hb_face_get_index().</note>
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400435 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200436 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400437 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400438void
439hb_face_set_index (hb_face_t *face,
440 unsigned int index)
441{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400442 if (hb_object_is_immutable (face))
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400443 return;
444
445 face->index = index;
446}
447
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400448/**
449 * hb_face_get_index:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100450 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400451 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100452 * Fetches the face-index corresponding to the given face.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400453 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100454 * <note>Note: face indices within a collection are zero-based.</note>
Ebrahim Byagowi32da0c62018-06-05 18:56:26 +0430455 *
Khaled Hosny4811e8f2021-06-07 10:54:36 +0200456 * Return value: The index of @face.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400457 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200458 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400459 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400460unsigned int
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700461hb_face_get_index (const hb_face_t *face)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400462{
463 return face->index;
464}
465
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400466/**
467 * hb_face_set_upem:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100468 * @face: A face object
469 * @upem: The units-per-em value to assign
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400470 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100471 * Sets the units-per-em (upem) for a face object to the specified value.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400472 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200473 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400474 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400475void
476hb_face_set_upem (hb_face_t *face,
477 unsigned int upem)
478{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400479 if (hb_object_is_immutable (face))
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400480 return;
481
Behdad Esfahbodfc44dea2018-11-13 11:54:33 -0500482 face->upem.set_relaxed (upem);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400483}
484
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400485/**
486 * hb_face_get_upem:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100487 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400488 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100489 * Fetches the units-per-em (upem) value of the specified face object.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400490 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100491 * Return value: The upem value of @face
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400492 *
Behdad Esfahbod5d74ff02015-09-03 14:55:59 +0430493 * Since: 0.9.2
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400494 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400495unsigned int
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700496hb_face_get_upem (const hb_face_t *face)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400497{
498 return face->get_upem ();
499}
500
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400501/**
502 * hb_face_set_glyph_count:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100503 * @face: A face object
504 * @glyph_count: The glyph-count value to assign
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400505 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100506 * Sets the glyph count for a face object to the specified value.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400507 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200508 * Since: 0.9.7
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400509 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400510void
511hb_face_set_glyph_count (hb_face_t *face,
512 unsigned int glyph_count)
513{
Behdad Esfahbod5570c872018-11-03 14:51:38 -0400514 if (hb_object_is_immutable (face))
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400515 return;
516
Behdad Esfahbodfc44dea2018-11-13 11:54:33 -0500517 face->num_glyphs.set_relaxed (glyph_count);
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400518}
519
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400520/**
521 * hb_face_get_glyph_count:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100522 * @face: A face object
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400523 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100524 * Fetches the glyph-count value of the specified face object.
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400525 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100526 * Return value: The glyph-count value of @face
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400527 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200528 * Since: 0.9.7
Behdad Esfahbod288f2892013-09-06 15:40:22 -0400529 **/
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400530unsigned int
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700531hb_face_get_glyph_count (const hb_face_t *face)
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400532{
533 return face->get_num_glyphs ();
534}
535
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200536/**
537 * hb_face_get_table_tags:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100538 * @face: A face object
539 * @start_offset: The index of first table tag to retrieve
540 * @table_count: (inout): Input = the maximum number of table tags to return;
541 * Output = the actual number of table tags returned (may be zero)
542 * @table_tags: (out) (array length=table_count): The array of table tags found
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200543 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100544 * Fetches a list of all table tags for a face, if possible. The list returned will
545 * begin at the offset provided
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200546 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100547 * Return value: Total number of tables, or zero if it is not possible to list
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200548 *
549 * Since: 1.6.0
550 **/
551unsigned int
Behdad Esfahbod16ccfaf2018-08-01 22:50:06 -0700552hb_face_get_table_tags (const hb_face_t *face,
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200553 unsigned int start_offset,
554 unsigned int *table_count, /* IN/OUT */
555 hb_tag_t *table_tags /* OUT */)
556{
prrace498e4372018-06-09 16:04:28 -0700557 if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200558 {
559 if (table_count)
560 *table_count = 0;
561 return 0;
562 }
Behdad Esfahbod2e3a07a2013-08-26 18:49:07 -0400563
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200564 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
565
Behdad Esfahbodeba1c162018-05-08 02:47:42 -0700566 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
Behdad Esfahbod94b3caf2017-10-11 17:22:44 +0200567 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
568
569 return ot_face.get_table_tags (start_offset, table_count, table_tags);
570}
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700571
572
573/*
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700574 * Character set.
575 */
576
Behdad Esfahboda84309a2018-08-26 09:33:01 -0700577
Behdad Esfahbod27de7c42019-06-19 20:07:02 -0700578#ifndef HB_NO_FACE_COLLECT_UNICODES
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700579/**
580 * hb_face_collect_unicodes:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100581 * @face: A face object
582 * @out: The set to add Unicode characters to
583 *
584 * Collects all of the Unicode characters covered by @face and adds
585 * them to the #hb_set_t set @out.
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700586 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200587 * Since: 1.9.0
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700588 */
589void
590hb_face_collect_unicodes (hb_face_t *face,
591 hb_set_t *out)
592{
Michiharu Ariza5ab50ee2020-02-29 01:32:29 -0800593 face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700594}
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700595/**
596 * hb_face_collect_variation_selectors:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100597 * @face: A face object
598 * @out: The set to add Variation Selector characters to
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700599 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100600 * Collects all Unicode "Variation Selector" characters covered by @face and adds
601 * them to the #hb_set_t set @out.
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700602 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200603 * Since: 1.9.0
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700604 */
605void
606hb_face_collect_variation_selectors (hb_face_t *face,
607 hb_set_t *out)
608{
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -0500609 face->table.cmap->collect_variation_selectors (out);
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700610}
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700611/**
612 * hb_face_collect_variation_unicodes:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100613 * @face: A face object
614 * @variation_selector: The Variation Selector to query
615 * @out: The set to add Unicode characters to
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700616 *
Nathan Willis3e72feb2019-04-22 19:21:27 +0100617 * Collects all Unicode characters for @variation_selector covered by @face and adds
618 * them to the #hb_set_t set @out.
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700619 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200620 * Since: 1.9.0
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700621 */
622void
623hb_face_collect_variation_unicodes (hb_face_t *face,
624 hb_codepoint_t variation_selector,
625 hb_set_t *out)
626{
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -0500627 face->table.cmap->collect_variation_unicodes (variation_selector, out);
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700628}
Behdad Esfahbod27de7c42019-06-19 20:07:02 -0700629#endif
Behdad Esfahboddae39c52018-08-25 22:44:39 -0700630
631
632/*
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700633 * face-builder: A face that has add_table().
634 */
635
636struct hb_face_builder_data_t
637{
Behdad Esfahbod2cb8c922021-08-05 12:27:22 -0600638 hb_hashmap_t<hb_tag_t, hb_blob_t *> tables;
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700639};
640
Behdad Esfahbod74ad5dd2021-08-05 11:51:54 -0600641static int compare_entries (const void* pa, const void* pb)
Garret Riegerc2ee1fd2021-08-04 16:42:49 -0700642{
Behdad Esfahbod74ad5dd2021-08-05 11:51:54 -0600643 const auto& a = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pa;
644 const auto& b = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pb;
Garret Riegerc2ee1fd2021-08-04 16:42:49 -0700645
Behdad Esfahbod74ad5dd2021-08-05 11:51:54 -0600646 /* Order by blob size first (smallest to largest) and then table tag */
Garret Riegerc2ee1fd2021-08-04 16:42:49 -0700647
Behdad Esfahbod74ad5dd2021-08-05 11:51:54 -0600648 if (a.second->length != b.second->length)
649 return a.second->length < b.second->length ? -1 : +1;
650
651 return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
Garret Riegerc2ee1fd2021-08-04 16:42:49 -0700652}
653
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700654static hb_face_builder_data_t *
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330655_hb_face_builder_data_create ()
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700656{
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600657 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 -0700658 if (unlikely (!data))
659 return nullptr;
660
661 data->tables.init ();
662
663 return data;
664}
665
666static void
667_hb_face_builder_data_destroy (void *user_data)
668{
669 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
670
Garret Riegerdea0fe52021-08-04 16:36:20 -0700671 for (hb_blob_t* b : data->tables.values())
672 hb_blob_destroy (b);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700673
674 data->tables.fini ();
675
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600676 hb_free (data);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700677}
678
679static hb_blob_t *
680_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
681{
682
Garret Riegerdea0fe52021-08-04 16:36:20 -0700683 unsigned int table_count = data->tables.get_population ();
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700684 unsigned int face_length = table_count * 16 + 12;
685
Garret Riegerdea0fe52021-08-04 16:36:20 -0700686 for (hb_blob_t* b : data->tables.values())
687 face_length += hb_ceil_to_4 (hb_blob_get_length (b));
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700688
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600689 char *buf = (char *) hb_malloc (face_length);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700690 if (unlikely (!buf))
691 return nullptr;
692
693 hb_serialize_context_t c (buf, face_length);
Behdad Esfahbodf9417af2018-12-18 13:23:32 -0500694 c.propagate_error (data->tables);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700695 OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
696
Garret Riegerdea0fe52021-08-04 16:36:20 -0700697 bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' '))
698 || data->tables.has (HB_TAG ('C','F','F','2')));
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700699 hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
700
Garret Riegerdea0fe52021-08-04 16:36:20 -0700701 // Sort the tags so that produced face is deterministic.
Garret Riegerc2ee1fd2021-08-04 16:42:49 -0700702 hb_vector_t<hb_pair_t <hb_tag_t, hb_blob_t*>> sorted_entries;
703 data->tables.iter () | hb_sink (sorted_entries);
Garret Rieger8c0c2172021-08-06 10:45:38 -0700704 if (unlikely (sorted_entries.in_error ()))
705 {
706 hb_free (buf);
707 return nullptr;
708 }
709
Garret Riegerc2ee1fd2021-08-04 16:42:49 -0700710 sorted_entries.qsort (compare_entries);
711 bool ret = f->serialize_single (&c, sfnt_tag, + sorted_entries.iter());
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700712
713 c.end_serialize ();
714
715 if (unlikely (!ret))
716 {
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600717 hb_free (buf);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700718 return nullptr;
719 }
720
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600721 return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700722}
723
724static hb_blob_t *
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700725_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 -0700726{
727 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
728
729 if (!tag)
730 return _hb_face_builder_data_reference_blob (data);
731
Garret Riegerc2ee1fd2021-08-04 16:42:49 -0700732 return hb_blob_reference (data->tables[tag]);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700733}
734
735
736/**
737 * hb_face_builder_create:
738 *
739 * Creates a #hb_face_t that can be used with hb_face_builder_add_table().
740 * After tables are added to the face, it can be compiled to a binary
741 * font file by calling hb_face_reference_blob().
742 *
HinTakbd1be872018-10-03 07:11:22 +0800743 * Return value: (transfer full): New face.
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700744 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200745 * Since: 1.9.0
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700746 **/
747hb_face_t *
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330748hb_face_builder_create ()
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700749{
750 hb_face_builder_data_t *data = _hb_face_builder_data_create ();
751 if (unlikely (!data)) return hb_face_get_empty ();
752
753 return hb_face_create_for_tables (_hb_face_builder_reference_table,
754 data,
755 _hb_face_builder_data_destroy);
756}
757
758/**
759 * hb_face_builder_add_table:
Nathan Willis3e72feb2019-04-22 19:21:27 +0100760 * @face: A face object created with hb_face_builder_create()
761 * @tag: The #hb_tag_t of the table to add
762 * @blob: The blob containing the table data to add
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700763 *
764 * Add table for @tag with data provided by @blob to the face. @face must
765 * be created using hb_face_builder_create().
766 *
Behdad Esfahbod54d332d2018-09-10 11:37:24 +0200767 * Since: 1.9.0
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700768 **/
769hb_bool_t
770hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
771{
Garret Riegere5bfd492021-08-05 14:03:25 -0700772 if (tag == HB_MAP_VALUE_INVALID)
773 return false;
774
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700775 if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
776 return false;
777
778 hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
Garret Riegerdae32b42020-07-28 18:31:46 -0700779
Garret Rieger222b74f2021-08-05 11:39:26 -0700780 hb_blob_t* previous = data->tables.get (tag);
Garret Riegerdea0fe52021-08-04 16:36:20 -0700781 if (!data->tables.set (tag, hb_blob_reference (blob)))
782 {
783 hb_blob_destroy (blob);
Garret Riegerdae32b42020-07-28 18:31:46 -0700784 return false;
Garret Riegerdea0fe52021-08-04 16:36:20 -0700785 }
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700786
Garret Rieger222b74f2021-08-05 11:39:26 -0700787 hb_blob_destroy (previous);
Behdad Esfahbodaadb2a92018-08-25 08:18:53 -0700788 return true;
789}