hb-face.cc (25917B)
1 /* 2 * Copyright © 2009 Red Hat, Inc. 3 * Copyright © 2012 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Red Hat Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29 #include "hb.hh" 30 31 #include "hb-face.hh" 32 #include "hb-blob.hh" 33 #include "hb-open-file.hh" 34 #include "hb-ot-face.hh" 35 #include "hb-ot-cmap-table.hh" 36 37 #ifdef HAVE_FREETYPE 38 #include "hb-ft.h" 39 #endif 40 #ifdef HAVE_CORETEXT 41 #include "hb-coretext.h" 42 #endif 43 #ifdef HAVE_DIRECTWRITE 44 #include "hb-directwrite.h" 45 #endif 46 47 48 /** 49 * SECTION:hb-face 50 * @title: hb-face 51 * @short_description: Font face objects 52 * @include: hb.h 53 * 54 * A font face is an object that represents a single face from within a 55 * font family. 56 * 57 * More precisely, a font face represents a single face in a binary font file. 58 * Font faces are typically built from a binary blob and a face index. 59 * Font faces are used to create fonts. 60 * 61 * A font face can be created from a binary blob using hb_face_create(). 62 * The face index is used to select a face from a binary blob that contains 63 * multiple faces. For example, a binary blob that contains both a regular 64 * and a bold face can be used to create two font faces, one for each face 65 * index. 66 **/ 67 68 69 /** 70 * hb_face_count: 71 * @blob: a blob. 72 * 73 * Fetches the number of faces in a blob. 74 * 75 * Return value: Number of faces in @blob 76 * 77 * Since: 1.7.7 78 **/ 79 unsigned int 80 hb_face_count (hb_blob_t *blob) 81 { 82 if (unlikely (!blob)) 83 return 0; 84 85 hb_sanitize_context_t c (blob); 86 87 auto *ot = blob->as<OT::OpenTypeFontFile> (); 88 if (unlikely (!ot->sanitize (&c))) 89 return 0; 90 91 return ot->get_face_count (); 92 } 93 94 /* 95 * hb_face_t 96 */ 97 98 DEFINE_NULL_INSTANCE (hb_face_t) = 99 { 100 HB_OBJECT_HEADER_STATIC, 101 102 0, /* index */ 103 1000, /* upem */ 104 0, /* num_glyphs */ 105 106 /* Zero for the rest is fine. */ 107 }; 108 109 110 /** 111 * hb_face_create_for_tables: 112 * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function 113 * @user_data: A pointer to the user data 114 * @destroy: (nullable): A callback to call when @data is not needed anymore 115 * 116 * Variant of hb_face_create(), built for those cases where it is more 117 * convenient to provide data for individual tables instead of the whole font 118 * data. With the caveat that hb_face_get_table_tags() would not work 119 * with faces created this way. You can address that by calling the 120 * hb_face_set_get_table_tags_func() function and setting the appropriate callback. 121 * 122 * Creates a new face object from the specified @user_data and @reference_table_func, 123 * with the @destroy callback. 124 * 125 * Return value: (transfer full): The new face object 126 * 127 * Since: 0.9.2 128 **/ 129 hb_face_t * 130 hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, 131 void *user_data, 132 hb_destroy_func_t destroy) 133 { 134 hb_face_t *face; 135 136 if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) { 137 if (destroy) 138 destroy (user_data); 139 return hb_face_get_empty (); 140 } 141 142 face->reference_table_func = reference_table_func; 143 face->user_data = user_data; 144 face->destroy = destroy; 145 146 face->num_glyphs = -1; 147 148 face->data.init0 (face); 149 face->table.init0 (face); 150 151 return face; 152 } 153 154 155 typedef struct hb_face_for_data_closure_t { 156 hb_blob_t *blob; 157 uint16_t index; 158 } hb_face_for_data_closure_t; 159 160 static hb_face_for_data_closure_t * 161 _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index) 162 { 163 hb_face_for_data_closure_t *closure; 164 165 closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t)); 166 if (unlikely (!closure)) 167 return nullptr; 168 169 closure->blob = blob; 170 closure->index = (uint16_t) (index & 0xFFFFu); 171 172 return closure; 173 } 174 175 static void 176 _hb_face_for_data_closure_destroy (void *data) 177 { 178 hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data; 179 180 hb_blob_destroy (closure->blob); 181 hb_free (closure); 182 } 183 184 static hb_blob_t * 185 _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) 186 { 187 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; 188 189 if (tag == HB_TAG_NONE) 190 return hb_blob_reference (data->blob); 191 192 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> (); 193 unsigned int base_offset; 194 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset); 195 196 const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag); 197 198 hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length); 199 200 return blob; 201 } 202 203 static unsigned 204 _hb_face_for_data_get_table_tags (const hb_face_t *face HB_UNUSED, 205 unsigned int start_offset, 206 unsigned int *table_count, 207 hb_tag_t *table_tags, 208 void *user_data) 209 { 210 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; 211 212 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> (); 213 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index); 214 215 return ot_face.get_table_tags (start_offset, table_count, table_tags); 216 } 217 218 219 /** 220 * hb_face_create: 221 * @blob: #hb_blob_t to work upon 222 * @index: The index of the face within @blob 223 * 224 * Constructs a new face object from the specified blob and 225 * a face index into that blob. 226 * 227 * The face index is used for blobs of file formats such as TTC and 228 * DFont that can contain more than one face. Face indices within 229 * such collections are zero-based. 230 * 231 * <note>Note: If the blob font format is not a collection, @index 232 * is ignored. Otherwise, only the lower 16-bits of @index are used. 233 * The unmodified @index can be accessed via hb_face_get_index().</note> 234 * 235 * <note>Note: The high 16-bits of @index, if non-zero, are used by 236 * hb_font_create() to load named-instances in variable fonts. See 237 * hb_font_create() for details.</note> 238 * 239 * Return value: (transfer full): The new face object 240 * 241 * Since: 0.9.2 242 **/ 243 hb_face_t * 244 hb_face_create (hb_blob_t *blob, 245 unsigned int index) 246 { 247 hb_face_t *face; 248 249 if (unlikely (!blob)) 250 blob = hb_blob_get_empty (); 251 252 blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)); 253 254 hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index); 255 256 if (unlikely (!closure)) 257 { 258 hb_blob_destroy (blob); 259 return hb_face_get_empty (); 260 } 261 262 face = hb_face_create_for_tables (_hb_face_for_data_reference_table, 263 closure, 264 _hb_face_for_data_closure_destroy); 265 hb_face_set_get_table_tags_func (face, 266 _hb_face_for_data_get_table_tags, 267 closure, 268 nullptr); 269 270 face->index = index; 271 272 return face; 273 } 274 275 /** 276 * hb_face_create_or_fail: 277 * @blob: #hb_blob_t to work upon 278 * @index: The index of the face within @blob 279 * 280 * Like hb_face_create(), but returns `NULL` if the blob data 281 * contains no usable font face at the specified index. 282 * 283 * Return value: (transfer full): The new face object, or `NULL` if 284 * no face is found at the specified index. 285 * 286 * Since: 10.1.0 287 **/ 288 hb_face_t * 289 hb_face_create_or_fail (hb_blob_t *blob, 290 unsigned int index) 291 { 292 unsigned num_faces = hb_face_count (blob); 293 if (index >= num_faces) 294 return nullptr; 295 296 hb_face_t *face = hb_face_create (blob, index); 297 if (hb_object_is_immutable (face)) 298 return nullptr; 299 300 return face; 301 } 302 303 #ifndef HB_NO_OPEN 304 /** 305 * hb_face_create_from_file_or_fail: 306 * @file_name: A font filename 307 * @index: The index of the face within the file 308 * 309 * A thin wrapper around hb_blob_create_from_file_or_fail() 310 * followed by hb_face_create_or_fail(). 311 * 312 * Return value: (transfer full): The new face object, or `NULL` if 313 * no face is found at the specified index or the file cannot be read. 314 * 315 * Since: 10.1.0 316 **/ 317 HB_EXTERN hb_face_t * 318 hb_face_create_from_file_or_fail (const char *file_name, 319 unsigned int index) 320 { 321 hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name); 322 if (unlikely (!blob)) 323 return nullptr; 324 325 hb_face_t *face = hb_face_create_or_fail (blob, index); 326 hb_blob_destroy (blob); 327 328 return face; 329 } 330 331 static const struct supported_face_loaders_t { 332 char name[16]; 333 hb_face_t * (*from_file) (const char *font_file, unsigned face_index); 334 hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index); 335 } supported_face_loaders[] = 336 { 337 {"ot", 338 #ifndef HB_NO_OPEN 339 hb_face_create_from_file_or_fail, 340 #else 341 nullptr, 342 #endif 343 hb_face_create_or_fail 344 }, 345 #ifdef HAVE_FREETYPE 346 {"ft", 347 hb_ft_face_create_from_file_or_fail, 348 hb_ft_face_create_from_blob_or_fail 349 }, 350 #endif 351 #ifdef HAVE_CORETEXT 352 {"coretext", 353 hb_coretext_face_create_from_file_or_fail, 354 hb_coretext_face_create_from_blob_or_fail 355 }, 356 #endif 357 #ifdef HAVE_DIRECTWRITE 358 {"directwrite", 359 hb_directwrite_face_create_from_file_or_fail, 360 hb_directwrite_face_create_from_blob_or_fail 361 }, 362 #endif 363 }; 364 365 static const char *get_default_loader_name () 366 { 367 static hb_atomic_t<const char *> static_loader_name; 368 const char *loader_name = static_loader_name.get_acquire (); 369 if (!loader_name) 370 { 371 loader_name = getenv ("HB_FACE_LOADER"); 372 if (!loader_name) 373 loader_name = ""; 374 if (!static_loader_name.cmpexch (nullptr, loader_name)) 375 loader_name = static_loader_name.get_acquire (); 376 } 377 return loader_name; 378 } 379 380 /** 381 * hb_face_create_from_file_or_fail_using: 382 * @file_name: A font filename 383 * @index: The index of the face within the file 384 * @loader_name: (nullable): The name of the loader to use, or `NULL` 385 * 386 * A thin wrapper around the face loader functions registered with HarfBuzz. 387 * If @loader_name is `NULL` or the empty string, the first available loader 388 * is used. 389 * 390 * For example, the FreeType ("ft") loader might be able to load 391 * WOFF and WOFF2 files if FreeType is built with those features, 392 * whereas the OpenType ("ot") loader will not. 393 * 394 * Return value: (transfer full): The new face object, or `NULL` if 395 * the file cannot be read or the loader fails to load the face. 396 * 397 * Since: 11.0.0 398 **/ 399 hb_face_t * 400 hb_face_create_from_file_or_fail_using (const char *file_name, 401 unsigned int index, 402 const char *loader_name) 403 { 404 // Duplicated in hb_face_create_or_fail_using 405 bool retry = false; 406 if (!loader_name || !*loader_name) 407 { 408 loader_name = get_default_loader_name (); 409 retry = true; 410 } 411 if (loader_name && !*loader_name) loader_name = nullptr; 412 413 retry: 414 for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) 415 { 416 if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name))) 417 return supported_face_loaders[i].from_file (file_name, index); 418 } 419 420 if (retry) 421 { 422 retry = false; 423 loader_name = nullptr; 424 goto retry; 425 } 426 427 return nullptr; 428 } 429 430 /** 431 * hb_face_create_or_fail_using: 432 * @blob: #hb_blob_t to work upon 433 * @index: The index of the face within @blob 434 * @loader_name: (nullable): The name of the loader to use, or `NULL` 435 * 436 * A thin wrapper around the face loader functions registered with HarfBuzz. 437 * If @loader_name is `NULL` or the empty string, the first available loader 438 * is used. 439 * 440 * For example, the FreeType ("ft") loader might be able to load 441 * WOFF and WOFF2 files if FreeType is built with those features, 442 * whereas the OpenType ("ot") loader will not. 443 * 444 * Return value: (transfer full): The new face object, or `NULL` if 445 * the loader fails to load the face. 446 * 447 * Since: 11.0.0 448 **/ 449 hb_face_t * 450 hb_face_create_or_fail_using (hb_blob_t *blob, 451 unsigned int index, 452 const char *loader_name) 453 { 454 // Duplicated in hb_face_create_from_file_or_fail_using 455 bool retry = false; 456 if (!loader_name || !*loader_name) 457 { 458 loader_name = get_default_loader_name (); 459 retry = true; 460 } 461 if (loader_name && !*loader_name) loader_name = nullptr; 462 463 retry: 464 for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) 465 { 466 if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name))) 467 return supported_face_loaders[i].from_blob (blob, index); 468 } 469 470 if (retry) 471 { 472 retry = false; 473 loader_name = nullptr; 474 goto retry; 475 } 476 477 return nullptr; 478 } 479 480 static inline void free_static_face_loader_list (); 481 482 static const char * const nil_face_loader_list[] = {nullptr}; 483 484 static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t<const char *, 485 hb_face_loader_list_lazy_loader_t> 486 { 487 static const char ** create () 488 { 489 const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *)); 490 if (unlikely (!face_loader_list)) 491 return nullptr; 492 493 unsigned i; 494 for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) 495 face_loader_list[i] = supported_face_loaders[i].name; 496 face_loader_list[i] = nullptr; 497 498 hb_atexit (free_static_face_loader_list); 499 500 return face_loader_list; 501 } 502 static void destroy (const char **l) 503 { hb_free (l); } 504 static const char * const * get_null () 505 { return nil_face_loader_list; } 506 } static_face_loader_list; 507 508 static inline 509 void free_static_face_loader_list () 510 { 511 static_face_loader_list.free_instance (); 512 } 513 514 /** 515 * hb_face_list_loaders: 516 * 517 * Retrieves the list of face loaders supported by HarfBuzz. 518 * 519 * Return value: (transfer none) (array zero-terminated=1): a 520 * `NULL`-terminated array of supported face loaders 521 * constant strings. The returned array is owned by HarfBuzz 522 * and should not be modified or freed. 523 * 524 * Since: 11.0.0 525 **/ 526 const char ** 527 hb_face_list_loaders () 528 { 529 return static_face_loader_list.get_unconst (); 530 } 531 #endif 532 533 534 /** 535 * hb_face_get_empty: 536 * 537 * Fetches the singleton empty face object. 538 * 539 * Return value: (transfer full): The empty face object 540 * 541 * Since: 0.9.2 542 **/ 543 hb_face_t * 544 hb_face_get_empty () 545 { 546 return const_cast<hb_face_t *> (&Null (hb_face_t)); 547 } 548 549 550 /** 551 * hb_face_reference: (skip) 552 * @face: A face object 553 * 554 * Increases the reference count on a face object. 555 * 556 * Return value: The @face object 557 * 558 * Since: 0.9.2 559 **/ 560 hb_face_t * 561 hb_face_reference (hb_face_t *face) 562 { 563 return hb_object_reference (face); 564 } 565 566 /** 567 * hb_face_destroy: (skip) 568 * @face: A face object 569 * 570 * Decreases the reference count on a face object. When the 571 * reference count reaches zero, the face is destroyed, 572 * freeing all memory. 573 * 574 * Since: 0.9.2 575 **/ 576 void 577 hb_face_destroy (hb_face_t *face) 578 { 579 if (!hb_object_destroy (face)) return; 580 581 #ifndef HB_NO_SHAPER 582 for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) 583 { 584 hb_face_t::plan_node_t *next = node->next; 585 hb_shape_plan_destroy (node->shape_plan); 586 hb_free (node); 587 node = next; 588 } 589 #endif 590 591 face->data.fini (); 592 face->table.fini (); 593 594 if (face->get_table_tags_destroy) 595 face->get_table_tags_destroy (face->get_table_tags_user_data); 596 597 if (face->destroy) 598 face->destroy (face->user_data); 599 600 hb_free (face); 601 } 602 603 /** 604 * hb_face_set_user_data: (skip) 605 * @face: A face object 606 * @key: The user-data key to set 607 * @data: A pointer to the user data 608 * @destroy: (nullable): A callback to call when @data is not needed anymore 609 * @replace: Whether to replace an existing data with the same key 610 * 611 * Attaches a user-data key/data pair to the given face object. 612 * 613 * Return value: `true` if success, `false` otherwise 614 * 615 * Since: 0.9.2 616 **/ 617 hb_bool_t 618 hb_face_set_user_data (hb_face_t *face, 619 hb_user_data_key_t *key, 620 void * data, 621 hb_destroy_func_t destroy, 622 hb_bool_t replace) 623 { 624 return hb_object_set_user_data (face, key, data, destroy, replace); 625 } 626 627 /** 628 * hb_face_get_user_data: (skip) 629 * @face: A face object 630 * @key: The user-data key to query 631 * 632 * Fetches the user data associated with the specified key, 633 * attached to the specified face object. 634 * 635 * Return value: (transfer none): A pointer to the user data 636 * 637 * Since: 0.9.2 638 **/ 639 void * 640 hb_face_get_user_data (const hb_face_t *face, 641 hb_user_data_key_t *key) 642 { 643 return hb_object_get_user_data (face, key); 644 } 645 646 /** 647 * hb_face_make_immutable: 648 * @face: A face object 649 * 650 * Makes the given face object immutable. 651 * 652 * Since: 0.9.2 653 **/ 654 void 655 hb_face_make_immutable (hb_face_t *face) 656 { 657 if (hb_object_is_immutable (face)) 658 return; 659 660 hb_object_make_immutable (face); 661 } 662 663 /** 664 * hb_face_is_immutable: 665 * @face: A face object 666 * 667 * Tests whether the given face object is immutable. 668 * 669 * Return value: `true` is @face is immutable, `false` otherwise 670 * 671 * Since: 0.9.2 672 **/ 673 hb_bool_t 674 hb_face_is_immutable (hb_face_t *face) 675 { 676 return hb_object_is_immutable (face); 677 } 678 679 680 /** 681 * hb_face_reference_table: 682 * @face: A face object 683 * @tag: The #hb_tag_t of the table to query 684 * 685 * Fetches a reference to the specified table within 686 * the specified face. Returns an empty blob if referencing table data is not 687 * possible. 688 * 689 * Return value: (transfer full): A pointer to the @tag table within @face 690 * 691 * Since: 0.9.2 692 **/ 693 hb_blob_t * 694 hb_face_reference_table (const hb_face_t *face, 695 hb_tag_t tag) 696 { 697 if (unlikely (tag == HB_TAG_NONE)) 698 return hb_blob_get_empty (); 699 700 return face->reference_table (tag); 701 } 702 703 /** 704 * hb_face_reference_blob: 705 * @face: A face object 706 * 707 * Fetches a pointer to the binary blob that contains the specified face. 708 * If referencing the face data is not possible, this function creates a blob 709 * out of individual table blobs if hb_face_get_table_tags() works with this 710 * face, otherwise it returns an empty blob. 711 * 712 * Return value: (transfer full): A pointer to the blob for @face 713 * 714 * Since: 0.9.2 715 **/ 716 hb_blob_t * 717 hb_face_reference_blob (hb_face_t *face) 718 { 719 hb_blob_t *blob = face->reference_table (HB_TAG_NONE); 720 721 if (blob == hb_blob_get_empty ()) 722 { 723 // If referencing the face blob is not possible (e.g. not implemented by the 724 // font functions), use face builder to create a blob out of individual 725 // table blobs. 726 unsigned total_count = hb_face_get_table_tags (face, 0, nullptr, nullptr); 727 if (total_count) 728 { 729 hb_tag_t tags[64]; 730 unsigned count = ARRAY_LENGTH (tags); 731 hb_face_t* builder = hb_face_builder_create (); 732 733 for (unsigned offset = 0; offset < total_count; offset += count) 734 { 735 hb_face_get_table_tags (face, offset, &count, tags); 736 if (unlikely (!count)) 737 break; // Allocation error 738 for (unsigned i = 0; i < count; i++) 739 { 740 if (unlikely (!tags[i])) 741 continue; 742 hb_blob_t *table = hb_face_reference_table (face, tags[i]); 743 hb_face_builder_add_table (builder, tags[i], table); 744 hb_blob_destroy (table); 745 } 746 } 747 748 blob = hb_face_reference_blob (builder); 749 hb_face_destroy (builder); 750 } 751 } 752 753 return blob; 754 } 755 756 /** 757 * hb_face_set_index: 758 * @face: A face object 759 * @index: The index to assign 760 * 761 * Assigns the specified face-index to @face. Fails if the 762 * face is immutable. 763 * 764 * <note>Note: changing the index has no effect on the face itself 765 * This only changes the value returned by hb_face_get_index().</note> 766 * 767 * Since: 0.9.2 768 **/ 769 void 770 hb_face_set_index (hb_face_t *face, 771 unsigned int index) 772 { 773 if (hb_object_is_immutable (face)) 774 return; 775 776 face->index = index; 777 } 778 779 /** 780 * hb_face_get_index: 781 * @face: A face object 782 * 783 * Fetches the face-index corresponding to the given face. 784 * 785 * <note>Note: face indices within a collection are zero-based.</note> 786 * 787 * Return value: The index of @face. 788 * 789 * Since: 0.9.2 790 **/ 791 unsigned int 792 hb_face_get_index (const hb_face_t *face) 793 { 794 return face->index; 795 } 796 797 /** 798 * hb_face_set_upem: 799 * @face: A face object 800 * @upem: The units-per-em value to assign 801 * 802 * Sets the units-per-em (upem) for a face object to the specified value. 803 * 804 * This API is used in rare circumstances. 805 * 806 * Since: 0.9.2 807 **/ 808 void 809 hb_face_set_upem (hb_face_t *face, 810 unsigned int upem) 811 { 812 if (hb_object_is_immutable (face)) 813 return; 814 815 face->upem = upem; 816 } 817 818 /** 819 * hb_face_get_upem: 820 * @face: A face object 821 * 822 * Fetches the units-per-em (UPEM) value of the specified face object. 823 * 824 * Typical UPEM values for fonts are 1000, or 2048, but any value 825 * in between 16 and 16,384 is allowed for OpenType fonts. 826 * 827 * Return value: The upem value of @face 828 * 829 * Since: 0.9.2 830 **/ 831 unsigned int 832 hb_face_get_upem (const hb_face_t *face) 833 { 834 return face->get_upem (); 835 } 836 837 /** 838 * hb_face_set_glyph_count: 839 * @face: A face object 840 * @glyph_count: The glyph-count value to assign 841 * 842 * Sets the glyph count for a face object to the specified value. 843 * 844 * This API is used in rare circumstances. 845 * 846 * Since: 0.9.7 847 **/ 848 void 849 hb_face_set_glyph_count (hb_face_t *face, 850 unsigned int glyph_count) 851 { 852 if (hb_object_is_immutable (face)) 853 return; 854 855 face->num_glyphs = glyph_count; 856 } 857 858 /** 859 * hb_face_get_glyph_count: 860 * @face: A face object 861 * 862 * Fetches the glyph-count value of the specified face object. 863 * 864 * Return value: The glyph-count value of @face 865 * 866 * Since: 0.9.7 867 **/ 868 unsigned int 869 hb_face_get_glyph_count (const hb_face_t *face) 870 { 871 return face->get_num_glyphs (); 872 } 873 874 /** 875 * hb_face_set_get_table_tags_func: 876 * @face: A face object 877 * @func: (closure user_data) (destroy destroy) (scope notified): The table-tag-fetching function 878 * @user_data: A pointer to the user data, to be destroyed by @destroy when not needed anymore 879 * @destroy: (nullable): A callback to call when @func is not needed anymore 880 * 881 * Sets the table-tag-fetching function for the specified face object. 882 * 883 * Since: 10.0.0 884 */ 885 HB_EXTERN void 886 hb_face_set_get_table_tags_func (hb_face_t *face, 887 hb_get_table_tags_func_t func, 888 void *user_data, 889 hb_destroy_func_t destroy) 890 { 891 if (hb_object_is_immutable (face)) 892 { 893 if (destroy) 894 destroy (user_data); 895 return; 896 } 897 898 if (face->get_table_tags_destroy) 899 face->get_table_tags_destroy (face->get_table_tags_user_data); 900 901 face->get_table_tags_func = func; 902 face->get_table_tags_user_data = user_data; 903 face->get_table_tags_destroy = destroy; 904 } 905 906 /** 907 * hb_face_get_table_tags: 908 * @face: A face object 909 * @start_offset: The index of first table tag to retrieve 910 * @table_count: (inout): Input = the maximum number of table tags to return; 911 * Output = the actual number of table tags returned (may be zero) 912 * @table_tags: (out) (array length=table_count): The array of table tags found 913 * 914 * Fetches a list of all table tags for a face, if possible. The list returned will 915 * begin at the offset provided 916 * 917 * Return value: Total number of tables, or zero if it is not possible to list 918 * 919 * Since: 1.6.0 920 **/ 921 unsigned int 922 hb_face_get_table_tags (const hb_face_t *face, 923 unsigned int start_offset, 924 unsigned int *table_count, /* IN/OUT */ 925 hb_tag_t *table_tags /* OUT */) 926 { 927 if (!face->get_table_tags_func) 928 { 929 if (table_count) 930 *table_count = 0; 931 return 0; 932 } 933 934 return face->get_table_tags_func (face, start_offset, table_count, table_tags, face->get_table_tags_user_data); 935 } 936 937 938 /* 939 * Character set. 940 */ 941 942 943 #ifndef HB_NO_FACE_COLLECT_UNICODES 944 /** 945 * hb_face_collect_unicodes: 946 * @face: A face object 947 * @out: (out): The set to add Unicode characters to 948 * 949 * Collects all of the Unicode characters covered by @face and adds 950 * them to the #hb_set_t set @out. 951 * 952 * Since: 1.9.0 953 */ 954 void 955 hb_face_collect_unicodes (hb_face_t *face, 956 hb_set_t *out) 957 { 958 face->table.cmap->collect_unicodes (out, face->get_num_glyphs ()); 959 } 960 /** 961 * hb_face_collect_nominal_glyph_mapping: 962 * @face: A face object 963 * @mapping: (out): The map to add Unicode-to-glyph mapping to 964 * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL` 965 * 966 * Collects the mapping from Unicode characters to nominal glyphs of the @face, 967 * and optionally all of the Unicode characters covered by @face. 968 * 969 * Since: 7.0.0 970 */ 971 void 972 hb_face_collect_nominal_glyph_mapping (hb_face_t *face, 973 hb_map_t *mapping, 974 hb_set_t *unicodes) 975 { 976 hb_set_t stack_unicodes; 977 if (!unicodes) 978 unicodes = &stack_unicodes; 979 face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ()); 980 } 981 /** 982 * hb_face_collect_variation_selectors: 983 * @face: A face object 984 * @out: (out): The set to add Variation Selector characters to 985 * 986 * Collects all Unicode "Variation Selector" characters covered by @face and adds 987 * them to the #hb_set_t set @out. 988 * 989 * Since: 1.9.0 990 */ 991 void 992 hb_face_collect_variation_selectors (hb_face_t *face, 993 hb_set_t *out) 994 { 995 face->table.cmap->collect_variation_selectors (out); 996 } 997 /** 998 * hb_face_collect_variation_unicodes: 999 * @face: A face object 1000 * @variation_selector: The Variation Selector to query 1001 * @out: (out): The set to add Unicode characters to 1002 * 1003 * Collects all Unicode characters for @variation_selector covered by @face and adds 1004 * them to the #hb_set_t set @out. 1005 * 1006 * Since: 1.9.0 1007 */ 1008 void 1009 hb_face_collect_variation_unicodes (hb_face_t *face, 1010 hb_codepoint_t variation_selector, 1011 hb_set_t *out) 1012 { 1013 face->table.cmap->collect_variation_unicodes (variation_selector, out); 1014 } 1015 #endif