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