hb-common.cc (32249B)
1 /* 2 * Copyright © 2009,2010 Red Hat, Inc. 3 * Copyright © 2011,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 #include "hb-machinery.hh" 31 32 33 /** 34 * SECTION:hb-common 35 * @title: hb-common 36 * @short_description: Common data types 37 * @include: hb.h 38 * 39 * Common data types used across HarfBuzz are defined here. 40 **/ 41 42 43 /* hb_tag_t */ 44 45 /** 46 * hb_tag_from_string: 47 * @str: (array length=len) (element-type uint8_t): String to convert 48 * @len: Length of @str, or -1 if it is `NULL`-terminated 49 * 50 * Converts a string into an #hb_tag_t. Valid tags 51 * are four characters. Shorter input strings will be 52 * padded with spaces. Longer input strings will be 53 * truncated. 54 * 55 * Return value: The #hb_tag_t corresponding to @str 56 * 57 * Since: 0.9.2 58 **/ 59 hb_tag_t 60 hb_tag_from_string (const char *str, int len) 61 { 62 char tag[4]; 63 unsigned int i; 64 65 if (!str || !len || !*str) 66 return HB_TAG_NONE; 67 68 if (len < 0 || len > 4) 69 len = 4; 70 for (i = 0; i < (unsigned) len && str[i]; i++) 71 tag[i] = str[i]; 72 for (; i < 4; i++) 73 tag[i] = ' '; 74 75 return HB_TAG (tag[0], tag[1], tag[2], tag[3]); 76 } 77 78 /** 79 * hb_tag_to_string: 80 * @tag: #hb_tag_t to convert 81 * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string 82 * 83 * Converts an #hb_tag_t to a string and returns it in @buf. 84 * Strings will be four characters long. 85 * 86 * Since: 0.9.5 87 **/ 88 void 89 hb_tag_to_string (hb_tag_t tag, char *buf) 90 { 91 buf[0] = (char) (uint8_t) (tag >> 24); 92 buf[1] = (char) (uint8_t) (tag >> 16); 93 buf[2] = (char) (uint8_t) (tag >> 8); 94 buf[3] = (char) (uint8_t) (tag >> 0); 95 } 96 97 98 /* hb_direction_t */ 99 100 static const char direction_strings[][4] = { 101 "ltr", 102 "rtl", 103 "ttb", 104 "btt" 105 }; 106 107 /** 108 * hb_direction_from_string: 109 * @str: (array length=len) (element-type uint8_t): String to convert 110 * @len: Length of @str, or -1 if it is `NULL`-terminated 111 * 112 * Converts a string to an #hb_direction_t. 113 * 114 * Matching is loose and applies only to the first letter. For 115 * examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR. 116 * 117 * Unmatched strings will return #HB_DIRECTION_INVALID. 118 * 119 * Return value: The #hb_direction_t matching @str 120 * 121 * Since: 0.9.2 122 **/ 123 hb_direction_t 124 hb_direction_from_string (const char *str, int len) 125 { 126 if (unlikely (!str || !len || !*str)) 127 return HB_DIRECTION_INVALID; 128 129 /* Lets match loosely: just match the first letter, such that 130 * all of "ltr", "left-to-right", etc work! 131 */ 132 char c = TOLOWER (str[0]); 133 for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++) 134 if (c == direction_strings[i][0]) 135 return (hb_direction_t) (HB_DIRECTION_LTR + i); 136 137 return HB_DIRECTION_INVALID; 138 } 139 140 /** 141 * hb_direction_to_string: 142 * @direction: The #hb_direction_t to convert 143 * 144 * Converts an #hb_direction_t to a string. 145 * 146 * Return value: (transfer none): The string corresponding to @direction 147 * 148 * Since: 0.9.2 149 **/ 150 const char * 151 hb_direction_to_string (hb_direction_t direction) 152 { 153 if (likely ((unsigned int) (direction - HB_DIRECTION_LTR) 154 < ARRAY_LENGTH (direction_strings))) 155 return direction_strings[direction - HB_DIRECTION_LTR]; 156 157 return "invalid"; 158 } 159 160 161 /* hb_language_t */ 162 163 struct hb_language_impl_t { 164 const char s[1]; 165 }; 166 167 static const char canon_map[256] = { 168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 171 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0, 172 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 173 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-', 174 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 175 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0 176 }; 177 178 static bool 179 lang_equal (hb_language_t v1, 180 const void *v2) 181 { 182 const unsigned char *p1 = (const unsigned char *) v1; 183 const unsigned char *p2 = (const unsigned char *) v2; 184 185 while (*p1 && *p1 == canon_map[*p2]) { 186 p1++; 187 p2++; 188 } 189 190 return *p1 == canon_map[*p2]; 191 } 192 193 #if 0 194 static unsigned int 195 lang_hash (const void *key) 196 { 197 const unsigned char *p = key; 198 unsigned int h = 0; 199 while (canon_map[*p]) 200 { 201 h = (h << 5) - h + canon_map[*p]; 202 p++; 203 } 204 205 return h; 206 } 207 #endif 208 209 210 struct hb_language_item_t { 211 212 struct hb_language_item_t *next; 213 hb_language_t lang; 214 215 bool operator == (const char *s) const 216 { return lang_equal (lang, s); } 217 218 hb_language_item_t & operator = (const char *s) 219 { 220 /* We can't call strdup(), because we allow custom allocators. */ 221 size_t len = strlen(s) + 1; 222 lang = (hb_language_t) hb_malloc(len); 223 if (likely (lang)) 224 { 225 hb_memcpy((unsigned char *) lang, s, len); 226 for (unsigned char *p = (unsigned char *) lang; *p; p++) 227 *p = canon_map[*p]; 228 } 229 230 return *this; 231 } 232 233 void fini () { hb_free ((void *) lang); } 234 }; 235 236 237 /* Thread-safe lockfree language list */ 238 239 static hb_atomic_t<hb_language_item_t *> langs; 240 241 static inline void 242 free_langs () 243 { 244 retry: 245 hb_language_item_t *first_lang = langs; 246 if (unlikely (!langs.cmpexch (first_lang, nullptr))) 247 goto retry; 248 249 while (first_lang) { 250 hb_language_item_t *next = first_lang->next; 251 first_lang->fini (); 252 hb_free (first_lang); 253 first_lang = next; 254 } 255 } 256 257 static hb_language_item_t * 258 lang_find_or_insert (const char *key) 259 { 260 retry: 261 hb_language_item_t *first_lang = langs; 262 263 for (hb_language_item_t *lang = first_lang; lang; lang = lang->next) 264 if (*lang == key) 265 return lang; 266 267 /* Not found; allocate one. */ 268 hb_language_item_t *lang = (hb_language_item_t *) hb_calloc (1, sizeof (hb_language_item_t)); 269 if (unlikely (!lang)) 270 return nullptr; 271 lang->next = first_lang; 272 *lang = key; 273 if (unlikely (!lang->lang)) 274 { 275 hb_free (lang); 276 return nullptr; 277 } 278 279 if (unlikely (!langs.cmpexch (first_lang, lang))) 280 { 281 lang->fini (); 282 hb_free (lang); 283 goto retry; 284 } 285 286 if (!first_lang) 287 hb_atexit (free_langs); /* First person registers atexit() callback. */ 288 289 return lang; 290 } 291 292 293 /** 294 * hb_language_from_string: 295 * @str: (array length=len) (element-type uint8_t): a string representing 296 * a BCP 47 language tag 297 * @len: length of the @str, or -1 if it is `NULL`-terminated. 298 * 299 * Converts @str representing a BCP 47 language tag to the corresponding 300 * #hb_language_t. 301 * 302 * Return value: (transfer none): 303 * The #hb_language_t corresponding to the BCP 47 language tag. 304 * 305 * Since: 0.9.2 306 **/ 307 hb_language_t 308 hb_language_from_string (const char *str, int len) 309 { 310 if (!str || !len || !*str) 311 return HB_LANGUAGE_INVALID; 312 313 hb_language_item_t *item = nullptr; 314 if (len >= 0) 315 { 316 /* NUL-terminate it. */ 317 char strbuf[64]; 318 len = hb_min (len, (int) sizeof (strbuf) - 1); 319 hb_memcpy (strbuf, str, len); 320 strbuf[len] = '\0'; 321 item = lang_find_or_insert (strbuf); 322 } 323 else 324 item = lang_find_or_insert (str); 325 326 return likely (item) ? item->lang : HB_LANGUAGE_INVALID; 327 } 328 329 /** 330 * hb_language_to_string: 331 * @language: The #hb_language_t to convert 332 * 333 * Converts an #hb_language_t to a string. 334 * 335 * Return value: (transfer none): 336 * A `NULL`-terminated string representing the @language. Must not be freed by 337 * the caller. 338 * 339 * Since: 0.9.2 340 **/ 341 const char * 342 hb_language_to_string (hb_language_t language) 343 { 344 if (unlikely (!language)) return nullptr; 345 346 return language->s; 347 } 348 349 /** 350 * hb_language_get_default: 351 * 352 * Fetch the default language from current locale. 353 * 354 * <note>Note that the first time this function is called, it calls 355 * "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying 356 * setlocale function is, in many implementations, NOT threadsafe. To avoid 357 * problems, call this function once before multiple threads can call it. 358 * This function is only used from hb_buffer_guess_segment_properties() by 359 * HarfBuzz itself.</note> 360 * 361 * Return value: (transfer none): The default language of the locale as 362 * an #hb_language_t 363 * 364 * Since: 0.9.2 365 **/ 366 hb_language_t 367 hb_language_get_default () 368 { 369 static hb_atomic_t<hb_language_t> default_language; 370 371 hb_language_t language = default_language; 372 if (unlikely (language == HB_LANGUAGE_INVALID)) 373 { 374 language = hb_language_from_string (hb_setlocale (LC_CTYPE, nullptr), -1); 375 (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language); 376 } 377 378 return language; 379 } 380 381 /** 382 * hb_language_matches: 383 * @language: The #hb_language_t to work on 384 * @specific: Another #hb_language_t 385 * 386 * Check whether a second language tag is the same or a more 387 * specific version of the provided language tag. For example, 388 * "fa_IR.utf8" is a more specific tag for "fa" or for "fa_IR". 389 * 390 * Return value: `true` if languages match, `false` otherwise. 391 * 392 * Since: 5.0.0 393 **/ 394 hb_bool_t 395 hb_language_matches (hb_language_t language, 396 hb_language_t specific) 397 { 398 if (language == specific) return true; 399 if (!language || !specific) return false; 400 401 const char *l = language->s; 402 const char *s = specific->s; 403 unsigned ll = strlen (l); 404 unsigned sl = strlen (s); 405 406 if (ll > sl) 407 return false; 408 409 return strncmp (l, s, ll) == 0 && 410 (s[ll] == '\0' || s[ll] == '-'); 411 } 412 413 414 /* hb_script_t */ 415 416 /** 417 * hb_script_from_iso15924_tag: 418 * @tag: an #hb_tag_t representing an ISO 15924 tag. 419 * 420 * Converts an ISO 15924 script tag to a corresponding #hb_script_t. 421 * 422 * Return value: 423 * An #hb_script_t corresponding to the ISO 15924 tag. 424 * 425 * Since: 0.9.2 426 **/ 427 hb_script_t 428 hb_script_from_iso15924_tag (hb_tag_t tag) 429 { 430 if (unlikely (tag == HB_TAG_NONE)) 431 return HB_SCRIPT_INVALID; 432 433 /* Be lenient, adjust case (one capital letter followed by three small letters) */ 434 tag = (tag & 0xDFDFDFDFu) | 0x00202020u; 435 436 switch (tag) { 437 438 /* These graduated from the 'Q' private-area codes, but 439 * the old code is still aliased by Unicode, and the Qaai 440 * one in use by ICU. */ 441 case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED; 442 case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC; 443 444 /* Script variants from https://unicode.org/iso15924/ */ 445 case HB_TAG('A','r','a','n'): return HB_SCRIPT_ARABIC; 446 case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC; 447 case HB_TAG('G','e','o','k'): return HB_SCRIPT_GEORGIAN; 448 case HB_TAG('H','a','n','s'): return HB_SCRIPT_HAN; 449 case HB_TAG('H','a','n','t'): return HB_SCRIPT_HAN; 450 case HB_TAG('J','a','m','o'): return HB_SCRIPT_HANGUL; 451 case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN; 452 case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN; 453 case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC; 454 case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC; 455 case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC; 456 } 457 458 /* If it looks right, just use the tag as a script */ 459 if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u) 460 return (hb_script_t) tag; 461 462 /* Otherwise, return unknown */ 463 return HB_SCRIPT_UNKNOWN; 464 } 465 466 /** 467 * hb_script_from_string: 468 * @str: (array length=len) (element-type uint8_t): a string representing an 469 * ISO 15924 tag. 470 * @len: length of the @str, or -1 if it is `NULL`-terminated. 471 * 472 * Converts a string @str representing an ISO 15924 script tag to a 473 * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then 474 * hb_script_from_iso15924_tag(). 475 * 476 * Return value: 477 * An #hb_script_t corresponding to the ISO 15924 tag. 478 * 479 * Since: 0.9.2 480 **/ 481 hb_script_t 482 hb_script_from_string (const char *str, int len) 483 { 484 return hb_script_from_iso15924_tag (hb_tag_from_string (str, len)); 485 } 486 487 /** 488 * hb_script_to_iso15924_tag: 489 * @script: an #hb_script_t to convert. 490 * 491 * Converts an #hb_script_t to a corresponding ISO 15924 script tag. 492 * 493 * Return value: 494 * An #hb_tag_t representing an ISO 15924 script tag. 495 * 496 * Since: 0.9.2 497 **/ 498 hb_tag_t 499 hb_script_to_iso15924_tag (hb_script_t script) 500 { 501 return (hb_tag_t) script; 502 } 503 504 /** 505 * hb_script_get_horizontal_direction: 506 * @script: The #hb_script_t to query 507 * 508 * Fetches the #hb_direction_t of a script when it is 509 * set horizontally. All right-to-left scripts will return 510 * #HB_DIRECTION_RTL. All left-to-right scripts will return 511 * #HB_DIRECTION_LTR. 512 * 513 * Scripts that can be written either right-to-left or 514 * left-to-right will return #HB_DIRECTION_INVALID. 515 * 516 * Unknown scripts will return #HB_DIRECTION_LTR. 517 * 518 * Return value: The horizontal #hb_direction_t of @script 519 * 520 * Since: 0.9.2 521 **/ 522 hb_direction_t 523 hb_script_get_horizontal_direction (hb_script_t script) 524 { 525 /* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */ 526 switch ((hb_tag_t) script) 527 { 528 /* Unicode-1.1 additions */ 529 case HB_SCRIPT_ARABIC: 530 case HB_SCRIPT_HEBREW: 531 532 /* Unicode-3.0 additions */ 533 case HB_SCRIPT_SYRIAC: 534 case HB_SCRIPT_THAANA: 535 536 /* Unicode-4.0 additions */ 537 case HB_SCRIPT_CYPRIOT: 538 539 /* Unicode-4.1 additions */ 540 case HB_SCRIPT_KHAROSHTHI: 541 542 /* Unicode-5.0 additions */ 543 case HB_SCRIPT_PHOENICIAN: 544 case HB_SCRIPT_NKO: 545 546 /* Unicode-5.1 additions */ 547 case HB_SCRIPT_LYDIAN: 548 549 /* Unicode-5.2 additions */ 550 case HB_SCRIPT_AVESTAN: 551 case HB_SCRIPT_IMPERIAL_ARAMAIC: 552 case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: 553 case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: 554 case HB_SCRIPT_OLD_SOUTH_ARABIAN: 555 case HB_SCRIPT_OLD_TURKIC: 556 case HB_SCRIPT_SAMARITAN: 557 558 /* Unicode-6.0 additions */ 559 case HB_SCRIPT_MANDAIC: 560 561 /* Unicode-6.1 additions */ 562 case HB_SCRIPT_MEROITIC_CURSIVE: 563 case HB_SCRIPT_MEROITIC_HIEROGLYPHS: 564 565 /* Unicode-7.0 additions */ 566 case HB_SCRIPT_MANICHAEAN: 567 case HB_SCRIPT_MENDE_KIKAKUI: 568 case HB_SCRIPT_NABATAEAN: 569 case HB_SCRIPT_OLD_NORTH_ARABIAN: 570 case HB_SCRIPT_PALMYRENE: 571 case HB_SCRIPT_PSALTER_PAHLAVI: 572 573 /* Unicode-8.0 additions */ 574 case HB_SCRIPT_HATRAN: 575 576 /* Unicode-9.0 additions */ 577 case HB_SCRIPT_ADLAM: 578 579 /* Unicode-11.0 additions */ 580 case HB_SCRIPT_HANIFI_ROHINGYA: 581 case HB_SCRIPT_OLD_SOGDIAN: 582 case HB_SCRIPT_SOGDIAN: 583 584 /* Unicode-12.0 additions */ 585 case HB_SCRIPT_ELYMAIC: 586 587 /* Unicode-13.0 additions */ 588 case HB_SCRIPT_CHORASMIAN: 589 case HB_SCRIPT_YEZIDI: 590 591 /* Unicode-14.0 additions */ 592 case HB_SCRIPT_OLD_UYGHUR: 593 594 /* Unicode-16.0 additions */ 595 case HB_SCRIPT_GARAY: 596 597 /* Unicode-17.0 additions */ 598 case HB_SCRIPT_SIDETIC: 599 600 return HB_DIRECTION_RTL; 601 602 603 /* https://github.com/harfbuzz/harfbuzz/issues/1000 */ 604 case HB_SCRIPT_OLD_HUNGARIAN: 605 case HB_SCRIPT_OLD_ITALIC: 606 case HB_SCRIPT_RUNIC: 607 case HB_SCRIPT_TIFINAGH: 608 609 return HB_DIRECTION_INVALID; 610 } 611 612 return HB_DIRECTION_LTR; 613 } 614 615 616 /* hb_version */ 617 618 619 /** 620 * SECTION:hb-version 621 * @title: hb-version 622 * @short_description: Information about the version of HarfBuzz in use 623 * @include: hb.h 624 * 625 * These functions and macros allow accessing version of the HarfBuzz 626 * library used at compile- as well as run-time, and to direct code 627 * conditionally based on those versions, again, at compile- or run-time. 628 **/ 629 630 631 /** 632 * hb_version: 633 * @major: (out): Library major version component 634 * @minor: (out): Library minor version component 635 * @micro: (out): Library micro version component 636 * 637 * Returns library version as three integer components. 638 * 639 * Since: 0.9.2 640 **/ 641 void 642 hb_version (unsigned int *major, 643 unsigned int *minor, 644 unsigned int *micro) 645 { 646 *major = HB_VERSION_MAJOR; 647 *minor = HB_VERSION_MINOR; 648 *micro = HB_VERSION_MICRO; 649 } 650 651 /** 652 * hb_version_string: 653 * 654 * Returns library version as a string with three components. 655 * 656 * Return value: Library version string 657 * 658 * Since: 0.9.2 659 **/ 660 const char * 661 hb_version_string () 662 { 663 return HB_VERSION_STRING; 664 } 665 666 /** 667 * hb_version_atleast: 668 * @major: Library major version component 669 * @minor: Library minor version component 670 * @micro: Library micro version component 671 * 672 * Tests the library version against a minimum value, 673 * as three integer components. 674 * 675 * Return value: `true` if the library is equal to or greater than 676 * the test value, `false` otherwise 677 * 678 * Since: 0.9.30 679 **/ 680 hb_bool_t 681 hb_version_atleast (unsigned int major, 682 unsigned int minor, 683 unsigned int micro) 684 { 685 return HB_VERSION_ATLEAST (major, minor, micro); 686 } 687 688 689 690 /* hb_feature_t and hb_variation_t */ 691 692 static bool 693 parse_space (const char **pp, const char *end) 694 { 695 while (*pp < end && ISSPACE (**pp)) 696 (*pp)++; 697 return true; 698 } 699 700 static bool 701 parse_char (const char **pp, const char *end, char c) 702 { 703 parse_space (pp, end); 704 705 if (*pp == end || **pp != c) 706 return false; 707 708 (*pp)++; 709 return true; 710 } 711 712 static bool 713 parse_uint (const char **pp, const char *end, unsigned int *pv) 714 { 715 /* Intentionally use hb_parse_int inside instead of hb_parse_uint, 716 * such that -1 turns into "big number"... */ 717 int v; 718 if (unlikely (!hb_parse_int (pp, end, &v))) return false; 719 720 *pv = v; 721 return true; 722 } 723 724 static bool 725 parse_uint32 (const char **pp, const char *end, uint32_t *pv) 726 { 727 /* Intentionally use hb_parse_int inside instead of hb_parse_uint, 728 * such that -1 turns into "big number"... */ 729 int v; 730 if (unlikely (!hb_parse_int (pp, end, &v))) return false; 731 732 *pv = v; 733 return true; 734 } 735 736 static bool 737 parse_bool (const char **pp, const char *end, uint32_t *pv) 738 { 739 parse_space (pp, end); 740 741 const char *p = *pp; 742 while (*pp < end && ISALPHA(**pp)) 743 (*pp)++; 744 745 /* CSS allows on/off as aliases 1/0. */ 746 if (*pp - p == 2 747 && TOLOWER (p[0]) == 'o' 748 && TOLOWER (p[1]) == 'n') 749 *pv = 1; 750 else if (*pp - p == 3 751 && TOLOWER (p[0]) == 'o' 752 && TOLOWER (p[1]) == 'f' 753 && TOLOWER (p[2]) == 'f') 754 *pv = 0; 755 else 756 return false; 757 758 return true; 759 } 760 761 /* hb_feature_t */ 762 763 static bool 764 parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature) 765 { 766 if (parse_char (pp, end, '-')) 767 feature->value = 0; 768 else { 769 parse_char (pp, end, '+'); 770 feature->value = 1; 771 } 772 773 return true; 774 } 775 776 static bool 777 parse_tag (const char **pp, const char *end, hb_tag_t *tag) 778 { 779 parse_space (pp, end); 780 781 char quote = 0; 782 783 if (*pp < end && (**pp == '\'' || **pp == '"')) 784 { 785 quote = **pp; 786 (*pp)++; 787 } 788 789 const char *p = *pp; 790 while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '[' && **pp != quote)) 791 (*pp)++; 792 793 if (p == *pp || *pp - p > 4) 794 return false; 795 796 *tag = hb_tag_from_string (p, *pp - p); 797 798 if (quote) 799 { 800 /* CSS expects exactly four bytes. And we only allow quotations for 801 * CSS compatibility. So, enforce the length. */ 802 if (*pp - p != 4) 803 return false; 804 if (*pp == end || **pp != quote) 805 return false; 806 (*pp)++; 807 } 808 809 return true; 810 } 811 812 static bool 813 parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature) 814 { 815 parse_space (pp, end); 816 817 bool has_start; 818 819 feature->start = HB_FEATURE_GLOBAL_START; 820 feature->end = HB_FEATURE_GLOBAL_END; 821 822 if (!parse_char (pp, end, '[')) 823 return true; 824 825 has_start = parse_uint (pp, end, &feature->start); 826 827 if (parse_char (pp, end, ':') || parse_char (pp, end, ';')) { 828 parse_uint (pp, end, &feature->end); 829 } else { 830 if (has_start) 831 feature->end = feature->start + 1; 832 } 833 834 return parse_char (pp, end, ']'); 835 } 836 837 static bool 838 parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature) 839 { 840 bool had_equal = parse_char (pp, end, '='); 841 bool had_value = parse_uint32 (pp, end, &feature->value) || 842 parse_bool (pp, end, &feature->value); 843 /* CSS doesn't use equal-sign between tag and value. 844 * If there was an equal-sign, then there *must* be a value. 845 * A value without an equal-sign is ok, but not required. */ 846 return !had_equal || had_value; 847 } 848 849 static bool 850 parse_one_feature (const char **pp, const char *end, hb_feature_t *feature) 851 { 852 return parse_feature_value_prefix (pp, end, feature) && 853 parse_tag (pp, end, &feature->tag) && 854 parse_feature_indices (pp, end, feature) && 855 parse_feature_value_postfix (pp, end, feature) && 856 parse_space (pp, end) && 857 *pp == end; 858 } 859 860 /** 861 * hb_feature_from_string: 862 * @str: (array length=len) (element-type uint8_t): a string to parse 863 * @len: length of @str, or -1 if string is `NULL` terminated 864 * @feature: (out): the #hb_feature_t to initialize with the parsed values 865 * 866 * Parses a string into a #hb_feature_t. 867 * 868 * The format for specifying feature strings follows. All valid CSS 869 * font-feature-settings values other than 'normal' and the global values are 870 * also accepted, though not documented below. CSS string escapes are not 871 * supported. 872 * 873 * The range indices refer to the positions between Unicode characters. The 874 * position before the first character is always 0. 875 * 876 * The format is Python-esque. Here is how it all works: 877 * 878 * <informaltable pgwide='1' align='left' frame='none'> 879 * <tgroup cols='5'> 880 * <thead> 881 * <row><entry>Syntax</entry> <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row> 882 * </thead> 883 * <tbody> 884 * <row><entry>Setting value:</entry></row> 885 * <row><entry>kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row> 886 * <row><entry>+kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row> 887 * <row><entry>-kern</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row> 888 * <row><entry>kern=0</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row> 889 * <row><entry>kern=1</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row> 890 * <row><entry>aalt=2</entry> <entry>2</entry> <entry>0</entry> <entry>∞</entry> <entry>Choose 2nd alternate</entry></row> 891 * <row><entry>Setting index:</entry></row> 892 * <row><entry>kern[]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row> 893 * <row><entry>kern[:]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row> 894 * <row><entry>kern[5:]</entry> <entry>1</entry> <entry>5</entry> <entry>∞</entry> <entry>Turn feature on, partial</entry></row> 895 * <row><entry>kern[:5]</entry> <entry>1</entry> <entry>0</entry> <entry>5</entry> <entry>Turn feature on, partial</entry></row> 896 * <row><entry>kern[3:5]</entry> <entry>1</entry> <entry>3</entry> <entry>5</entry> <entry>Turn feature on, range</entry></row> 897 * <row><entry>kern[3]</entry> <entry>1</entry> <entry>3</entry> <entry>3+1</entry> <entry>Turn feature on, single char</entry></row> 898 * <row><entry>Mixing it all:</entry></row> 899 * <row><entry>aalt[3:5]=2</entry> <entry>2</entry> <entry>3</entry> <entry>5</entry> <entry>Turn 2nd alternate on for range</entry></row> 900 * </tbody> 901 * </tgroup> 902 * </informaltable> 903 * 904 * Return value: 905 * `true` if @str is successfully parsed, `false` otherwise 906 * 907 * Since: 0.9.5 908 **/ 909 hb_bool_t 910 hb_feature_from_string (const char *str, int len, 911 hb_feature_t *feature) 912 { 913 hb_feature_t feat; 914 915 if (len < 0) 916 len = strlen (str); 917 918 if (likely (parse_one_feature (&str, str + len, &feat))) 919 { 920 if (feature) 921 *feature = feat; 922 return true; 923 } 924 925 if (feature) 926 hb_memset (feature, 0, sizeof (*feature)); 927 return false; 928 } 929 930 /** 931 * hb_feature_to_string: 932 * @feature: an #hb_feature_t to convert 933 * @buf: (array length=size) (out): output string 934 * @size: the allocated size of @buf 935 * 936 * Converts a #hb_feature_t into a `NULL`-terminated string in the format 937 * understood by hb_feature_from_string(). The client in responsible for 938 * allocating big enough size for @buf, 128 bytes is more than enough. 939 * 940 * Note that the feature value will be omitted if it is '1', but the 941 * string won't include any whitespace. 942 * 943 * Since: 0.9.5 944 **/ 945 void 946 hb_feature_to_string (hb_feature_t *feature, 947 char *buf, unsigned int size) 948 { 949 if (unlikely (!size)) return; 950 951 char s[128]; 952 unsigned int len = 0; 953 if (feature->value == 0) 954 s[len++] = '-'; 955 hb_tag_to_string (feature->tag, s + len); 956 len += 4; 957 while (len && s[len - 1] == ' ') 958 len--; 959 if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END) 960 { 961 s[len++] = '['; 962 if (feature->start) 963 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start)); 964 if (feature->end != feature->start + 1) { 965 s[len++] = ':'; 966 if (feature->end != HB_FEATURE_GLOBAL_END) 967 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end)); 968 } 969 s[len++] = ']'; 970 } 971 if (feature->value > 1) 972 { 973 s[len++] = '='; 974 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%" PRIu32, feature->value)); 975 } 976 assert (len < ARRAY_LENGTH (s)); 977 len = hb_min (len, size - 1); 978 hb_memcpy (buf, s, len); 979 buf[len] = '\0'; 980 } 981 982 /* hb_variation_t */ 983 984 static bool 985 parse_variation_value (const char **pp, const char *end, hb_variation_t *variation) 986 { 987 parse_char (pp, end, '='); /* Optional. */ 988 double v; 989 if (unlikely (!hb_parse_double (pp, end, &v))) return false; 990 991 variation->value = v; 992 return true; 993 } 994 995 static bool 996 parse_one_variation (const char **pp, const char *end, hb_variation_t *variation) 997 { 998 return parse_tag (pp, end, &variation->tag) && 999 parse_variation_value (pp, end, variation) && 1000 parse_space (pp, end) && 1001 *pp == end; 1002 } 1003 1004 /** 1005 * hb_variation_from_string: 1006 * @str: (array length=len) (element-type uint8_t): a string to parse 1007 * @len: length of @str, or -1 if string is `NULL` terminated 1008 * @variation: (out): the #hb_variation_t to initialize with the parsed values 1009 * 1010 * Parses a string into a #hb_variation_t. 1011 * 1012 * The format for specifying variation settings follows. All valid CSS 1013 * font-variation-settings values other than 'normal' and 'inherited' are also 1014 * accepted, though, not documented below. 1015 * 1016 * The format is a tag, optionally followed by an equals sign, followed by a 1017 * number. For example `wght=500`, or `slnt=-7.5`. 1018 * 1019 * Return value: 1020 * `true` if @str is successfully parsed, `false` otherwise 1021 * 1022 * Since: 1.4.2 1023 */ 1024 hb_bool_t 1025 hb_variation_from_string (const char *str, int len, 1026 hb_variation_t *variation) 1027 { 1028 hb_variation_t var; 1029 1030 if (len < 0) 1031 len = strlen (str); 1032 1033 if (likely (parse_one_variation (&str, str + len, &var))) 1034 { 1035 if (variation) 1036 *variation = var; 1037 return true; 1038 } 1039 1040 if (variation) 1041 hb_memset (variation, 0, sizeof (*variation)); 1042 return false; 1043 } 1044 1045 #ifndef HB_NO_SETLOCALE 1046 1047 static inline void free_static_C_locale (); 1048 1049 static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>, 1050 hb_C_locale_lazy_loader_t> 1051 { 1052 static hb_locale_t create () 1053 { 1054 hb_locale_t l = newlocale (LC_ALL_MASK, "C", NULL); 1055 if (!l) 1056 return l; 1057 1058 hb_atexit (free_static_C_locale); 1059 1060 return l; 1061 } 1062 static void destroy (hb_locale_t l) 1063 { 1064 freelocale (l); 1065 } 1066 static hb_locale_t get_null () 1067 { 1068 return (hb_locale_t) 0; 1069 } 1070 } static_C_locale; 1071 1072 static inline 1073 void free_static_C_locale () 1074 { 1075 static_C_locale.free_instance (); 1076 } 1077 1078 static hb_locale_t 1079 get_C_locale () 1080 { 1081 return static_C_locale.get_unconst (); 1082 } 1083 1084 #endif 1085 1086 /** 1087 * hb_variation_to_string: 1088 * @variation: an #hb_variation_t to convert 1089 * @buf: (array length=size) (out caller-allocates): output string 1090 * @size: the allocated size of @buf 1091 * 1092 * Converts an #hb_variation_t into a `NULL`-terminated string in the format 1093 * understood by hb_variation_from_string(). The client in responsible for 1094 * allocating big enough size for @buf, 128 bytes is more than enough. 1095 * 1096 * Note that the string won't include any whitespace. 1097 * 1098 * Since: 1.4.2 1099 */ 1100 void 1101 hb_variation_to_string (hb_variation_t *variation, 1102 char *buf, unsigned int size) 1103 { 1104 if (unlikely (!size)) return; 1105 1106 char s[128]; 1107 unsigned int len = 0; 1108 hb_tag_to_string (variation->tag, s + len); 1109 len += 4; 1110 while (len && s[len - 1] == ' ') 1111 len--; 1112 s[len++] = '='; 1113 1114 hb_locale_t oldlocale HB_UNUSED; 1115 oldlocale = hb_uselocale (get_C_locale ()); 1116 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value)); 1117 (void) hb_uselocale (oldlocale); 1118 1119 assert (len < ARRAY_LENGTH (s)); 1120 len = hb_min (len, size - 1); 1121 hb_memcpy (buf, s, len); 1122 buf[len] = '\0'; 1123 } 1124 1125 /** 1126 * hb_color_get_alpha: 1127 * @color: an #hb_color_t we are interested in its channels. 1128 * 1129 * Fetches the alpha channel of the given @color. 1130 * 1131 * Return value: Alpha channel value 1132 * 1133 * Since: 2.1.0 1134 */ 1135 uint8_t 1136 (hb_color_get_alpha) (hb_color_t color) 1137 { 1138 return hb_color_get_alpha (color); 1139 } 1140 1141 /** 1142 * hb_color_get_red: 1143 * @color: an #hb_color_t we are interested in its channels. 1144 * 1145 * Fetches the red channel of the given @color. 1146 * 1147 * Return value: Red channel value 1148 * 1149 * Since: 2.1.0 1150 */ 1151 uint8_t 1152 (hb_color_get_red) (hb_color_t color) 1153 { 1154 return hb_color_get_red (color); 1155 } 1156 1157 /** 1158 * hb_color_get_green: 1159 * @color: an #hb_color_t we are interested in its channels. 1160 * 1161 * Fetches the green channel of the given @color. 1162 * 1163 * Return value: Green channel value 1164 * 1165 * Since: 2.1.0 1166 */ 1167 uint8_t 1168 (hb_color_get_green) (hb_color_t color) 1169 { 1170 return hb_color_get_green (color); 1171 } 1172 1173 /** 1174 * hb_color_get_blue: 1175 * @color: an #hb_color_t we are interested in its channels. 1176 * 1177 * Fetches the blue channel of the given @color. 1178 * 1179 * Return value: Blue channel value 1180 * 1181 * Since: 2.1.0 1182 */ 1183 uint8_t 1184 (hb_color_get_blue) (hb_color_t color) 1185 { 1186 return hb_color_get_blue (color); 1187 } 1188 1189 /** 1190 * hb_malloc: 1191 * @size: The size of the memory to allocate. 1192 * 1193 * Allocates @size bytes of memory, using the allocator set at 1194 * compile-time. Typically just malloc(). 1195 * 1196 * Return value: A pointer to the allocated memory. 1197 * 1198 * Since: 11.0.0 1199 **/ 1200 void* hb_malloc(size_t size) { return hb_malloc_impl (size); } 1201 1202 /** 1203 * hb_calloc: 1204 * @nmemb: The number of elements to allocate. 1205 * @size: The size of each element. 1206 * 1207 * Allocates @nmemb elements of @size bytes each, initialized to zero, 1208 * using the allocator set at compile-time. Typically just calloc(). 1209 * 1210 * Return value: A pointer to the allocated memory. 1211 * 1212 * Since: 11.0.0 1213 **/ 1214 void* hb_calloc(size_t nmemb, size_t size) { return hb_calloc_impl (nmemb, size); } 1215 1216 /** 1217 * hb_realloc: 1218 * @ptr: The pointer to the memory to reallocate. 1219 * @size: The new size of the memory. 1220 * 1221 * Reallocates the memory pointed to by @ptr to @size bytes, using the 1222 * allocator set at compile-time. Typically just realloc(). 1223 * 1224 * Return value: A pointer to the reallocated memory. 1225 * 1226 * Since: 11.0.0 1227 **/ 1228 void* hb_realloc(void *ptr, size_t size) { return hb_realloc_impl (ptr, size); } 1229 1230 /** 1231 * hb_free: 1232 * @ptr: The pointer to the memory to free. 1233 * 1234 * Frees the memory pointed to by @ptr, using the allocator set at 1235 * compile-time. Typically just free(). 1236 * 1237 * Since: 11.0.0 1238 **/ 1239 void hb_free(void *ptr) { hb_free_impl (ptr); } 1240 1241 1242 /* If there is no visibility control, then hb-static.cc will NOT 1243 * define anything. Instead, we get it to define one set in here 1244 * only, so only libharfbuzz.so defines them, not other libs. */ 1245 #ifdef HB_NO_VISIBILITY 1246 #undef HB_NO_VISIBILITY 1247 #include "hb-static.cc" 1248 #define HB_NO_VISIBILITY 1 1249 #endif