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