< prev index next >

src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.cc

Print this page




   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-private.hh"
  30 
  31 #include "hb-mutex-private.hh"
  32 #include "hb-object-private.hh"
  33 
  34 #include <locale.h>
  35 #ifdef HAVE_XLOCALE_H
  36 #include <xlocale.h>
  37 #endif
  38 
  39 










  40 /* hb_options_t */
  41 
  42 hb_options_union_t _hb_options;
  43 
  44 void
  45 _hb_options_init (void)
  46 {
  47   hb_options_union_t u;
  48   u.i = 0;
  49   u.opts.initialized = 1;
  50 
  51   char *c = getenv ("HB_OPTIONS");
  52   u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");



















  53 
  54   /* This is idempotent and threadsafe. */
  55   _hb_options = u;
  56 }
  57 
  58 
  59 /* hb_tag_t */
  60 
  61 /**
  62  * hb_tag_from_string:
  63  * @str: (array length=len) (element-type uint8_t):
  64  * @len:
  65  *
  66  *
  67  *
  68  * Return value:
  69  *
  70  * Since: 0.9.2
  71  **/
  72 hb_tag_t
  73 hb_tag_from_string (const char *str, int len)
  74 {
  75   char tag[4];


 159 {
 160   if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
 161               < ARRAY_LENGTH (direction_strings)))
 162     return direction_strings[direction - HB_DIRECTION_LTR];
 163 
 164   return "invalid";
 165 }
 166 
 167 
 168 /* hb_language_t */
 169 
 170 struct hb_language_impl_t {
 171   const char s[1];
 172 };
 173 
 174 static const char canon_map[256] = {
 175    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
 176    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
 177    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
 178   '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
 179   '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
 180   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
 181    0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
 182   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
 183 };
 184 
 185 static bool
 186 lang_equal (hb_language_t  v1,
 187             const void    *v2)
 188 {
 189   const unsigned char *p1 = (const unsigned char *) v1;
 190   const unsigned char *p2 = (const unsigned char *) v2;
 191 
 192   while (*p1 && *p1 == canon_map[*p2]) {
 193     p1++;
 194     p2++;
 195   }
 196 
 197   return *p1 == canon_map[*p2];
 198 }
 199 


 202 lang_hash (const void *key)
 203 {
 204   const unsigned char *p = key;
 205   unsigned int h = 0;
 206   while (canon_map[*p])
 207     {
 208       h = (h << 5) - h + canon_map[*p];
 209       p++;
 210     }
 211 
 212   return h;
 213 }
 214 #endif
 215 
 216 
 217 struct hb_language_item_t {
 218 
 219   struct hb_language_item_t *next;
 220   hb_language_t lang;
 221 
 222   inline bool operator == (const char *s) const {
 223     return lang_equal (lang, s);
 224   }
 225 
 226   inline hb_language_item_t & operator = (const char *s) {
 227     /* If a custom allocated is used calling strdup() pairs
 228     badly with a call to the custom free() in fini() below.
 229     Therefore don't call strdup(), implement its behavior.
 230     */
 231     size_t len = strlen(s) + 1;
 232     lang = (hb_language_t) malloc(len);
 233     if (likely (lang))
 234     {
 235       memcpy((unsigned char *) lang, s, len);
 236       for (unsigned char *p = (unsigned char *) lang; *p; p++)
 237         *p = canon_map[*p];
 238     }
 239 
 240     return *this;
 241   }
 242 
 243   void fini (void) { free ((void *) lang); }
 244 };
 245 
 246 
 247 /* Thread-safe lock-free language list */
 248 
 249 static hb_language_item_t *langs;
 250 
 251 #ifdef HB_USE_ATEXIT
 252 static void
 253 free_langs (void)
 254 {
 255 retry:
 256   hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
 257   if (!hb_atomic_ptr_cmpexch (&langs, first_lang, nullptr))
 258     goto retry;
 259 
 260   while (first_lang) {
 261     hb_language_item_t *next = first_lang->next;
 262     first_lang->fini ();
 263     free (first_lang);
 264     first_lang = next;
 265   }
 266 }
 267 #endif
 268 
 269 static hb_language_item_t *
 270 lang_find_or_insert (const char *key)
 271 {
 272 retry:
 273   hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
 274 
 275   for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
 276     if (*lang == key)
 277       return lang;
 278 
 279   /* Not found; allocate one. */
 280   hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
 281   if (unlikely (!lang))
 282     return nullptr;
 283   lang->next = first_lang;
 284   *lang = key;
 285   if (unlikely (!lang->lang))
 286   {
 287     free (lang);
 288     return nullptr;
 289   }
 290 
 291   if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {

 292     lang->fini ();
 293     free (lang);
 294     goto retry;
 295   }
 296 
 297 #ifdef HB_USE_ATEXIT
 298   if (!first_lang)
 299     atexit (free_langs); /* First person registers atexit() callback. */
 300 #endif
 301 
 302   return lang;
 303 }
 304 
 305 
 306 /**
 307  * hb_language_from_string:
 308  * @str: (array length=len) (element-type uint8_t): a string representing
 309  *       ISO 639 language code
 310  * @len: length of the @str, or -1 if it is %NULL-terminated.
 311  *
 312  * Converts @str representing an ISO 639 language code to the corresponding
 313  * #hb_language_t.
 314  *
 315  * Return value: (transfer none):
 316  * The #hb_language_t corresponding to the ISO 639 language code.
 317  *
 318  * Since: 0.9.2
 319  **/
 320 hb_language_t
 321 hb_language_from_string (const char *str, int len)
 322 {
 323   if (!str || !len || !*str)
 324     return HB_LANGUAGE_INVALID;
 325 
 326   hb_language_item_t *item = nullptr;
 327   if (len >= 0)
 328   {
 329     /* NUL-terminate it. */
 330     char strbuf[64];
 331     len = MIN (len, (int) sizeof (strbuf) - 1);
 332     memcpy (strbuf, str, len);
 333     strbuf[len] = '\0';
 334     item = lang_find_or_insert (strbuf);
 335   }
 336   else


 344  * @language: an #hb_language_t to convert.
 345  *
 346  * See hb_language_from_string().
 347  *
 348  * Return value: (transfer none):
 349  * A %NULL-terminated string representing the @language. Must not be freed by
 350  * the caller.
 351  *
 352  * Since: 0.9.2
 353  **/
 354 const char *
 355 hb_language_to_string (hb_language_t language)
 356 {
 357   /* This is actually nullptr-safe! */
 358   return language->s;
 359 }
 360 
 361 /**
 362  * hb_language_get_default:
 363  *

 364  *






 365  *
 366  * Return value: (transfer none):
 367  *
 368  * Since: 0.9.2
 369  **/
 370 hb_language_t
 371 hb_language_get_default (void)
 372 {
 373   static hb_language_t default_language = HB_LANGUAGE_INVALID;
 374 
 375   hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
 376   if (unlikely (language == HB_LANGUAGE_INVALID)) {

 377     language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
 378     (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
 379   }
 380 
 381   return default_language;
 382 }
 383 
 384 
 385 /* hb_script_t */
 386 
 387 /**
 388  * hb_script_from_iso15924_tag:
 389  * @tag: an #hb_tag_t representing an ISO 15924 tag.
 390  *
 391  * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
 392  *
 393  * Return value:
 394  * An #hb_script_t corresponding to the ISO 15924 tag.
 395  *
 396  * Since: 0.9.2
 397  **/
 398 hb_script_t
 399 hb_script_from_iso15924_tag (hb_tag_t tag)
 400 {
 401   if (unlikely (tag == HB_TAG_NONE))


 513     case HB_SCRIPT_OLD_TURKIC:
 514     case HB_SCRIPT_SAMARITAN:
 515 
 516     /* Unicode-6.0 additions */
 517     case HB_SCRIPT_MANDAIC:
 518 
 519     /* Unicode-6.1 additions */
 520     case HB_SCRIPT_MEROITIC_CURSIVE:
 521     case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
 522 
 523     /* Unicode-7.0 additions */
 524     case HB_SCRIPT_MANICHAEAN:
 525     case HB_SCRIPT_MENDE_KIKAKUI:
 526     case HB_SCRIPT_NABATAEAN:
 527     case HB_SCRIPT_OLD_NORTH_ARABIAN:
 528     case HB_SCRIPT_PALMYRENE:
 529     case HB_SCRIPT_PSALTER_PAHLAVI:
 530 
 531     /* Unicode-8.0 additions */
 532     case HB_SCRIPT_HATRAN:
 533     case HB_SCRIPT_OLD_HUNGARIAN:
 534 
 535     /* Unicode-9.0 additions */
 536     case HB_SCRIPT_ADLAM:
 537 
 538     /* Unicode-11.0 additions */
 539     case HB_SCRIPT_HANIFI_ROHINGYA:
 540     case HB_SCRIPT_OLD_SOGDIAN:
 541     case HB_SCRIPT_SOGDIAN:
 542 
 543       return HB_DIRECTION_RTL;
 544 
 545 
 546     /* https://github.com/harfbuzz/harfbuzz/issues/1000 */

 547     case HB_SCRIPT_OLD_ITALIC:

 548 
 549       return HB_DIRECTION_INVALID;
 550   }
 551 
 552   return HB_DIRECTION_LTR;
 553 }
 554 
 555 
 556 /* hb_user_data_array_t */
 557 
 558 bool
 559 hb_user_data_array_t::set (hb_user_data_key_t *key,
 560                            void *              data,
 561                            hb_destroy_func_t   destroy,
 562                            hb_bool_t           replace)
 563 {
 564   if (!key)
 565     return false;
 566 
 567   if (replace) {


 570       return true;
 571     }
 572   }
 573   hb_user_data_item_t item = {key, data, destroy};
 574   bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
 575 
 576   return ret;
 577 }
 578 
 579 void *
 580 hb_user_data_array_t::get (hb_user_data_key_t *key)
 581 {
 582   hb_user_data_item_t item = {nullptr, nullptr, nullptr};
 583 
 584   return items.find (key, &item, lock) ? item.data : nullptr;
 585 }
 586 
 587 
 588 /* hb_version */
 589 













 590 /**
 591  * hb_version:
 592  * @major: (out): Library major version component.
 593  * @minor: (out): Library minor version component.
 594  * @micro: (out): Library micro version component.
 595  *
 596  * Returns library version as three integer components.
 597  *
 598  * Since: 0.9.2
 599  **/
 600 void
 601 hb_version (unsigned int *major,
 602             unsigned int *minor,
 603             unsigned int *micro)
 604 {
 605   *major = HB_VERSION_MAJOR;
 606   *minor = HB_VERSION_MINOR;
 607   *micro = HB_VERSION_MICRO;
 608 }
 609 
 610 /**
 611  * hb_version_string:
 612  *
 613  * Returns library version as a string with three components.
 614  *
 615  * Return value: library version string.
 616  *
 617  * Since: 0.9.2
 618  **/
 619 const char *
 620 hb_version_string (void)
 621 {
 622   return HB_VERSION_STRING;
 623 }
 624 
 625 /**
 626  * hb_version_atleast:
 627  * @major:
 628  * @minor:
 629  * @micro:
 630  *
 631  *
 632  *
 633  * Return value:
 634  *
 635  * Since: 0.9.30
 636  **/
 637 hb_bool_t
 638 hb_version_atleast (unsigned int major,
 639                     unsigned int minor,
 640                     unsigned int micro)


 712   *pv = v;
 713   *pp += pend - p;
 714   return true;
 715 }
 716 
 717 #if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
 718 #define USE_XLOCALE 1
 719 #define HB_LOCALE_T locale_t
 720 #define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
 721 #define HB_FREE_LOCALE(loc) freelocale (loc)
 722 #elif defined(_MSC_VER)
 723 #define USE_XLOCALE 1
 724 #define HB_LOCALE_T _locale_t
 725 #define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
 726 #define HB_FREE_LOCALE(loc) _free_locale (loc)
 727 #define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
 728 #endif
 729 
 730 #ifdef USE_XLOCALE
 731 
 732 static HB_LOCALE_T C_locale;


 733 
 734 #ifdef HB_USE_ATEXIT
 735 static void
 736 free_C_locale (void)
 737 {
 738 retry:
 739   HB_LOCALE_T locale = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
 740 
 741   if (!hb_atomic_ptr_cmpexch (&C_locale, locale, nullptr))
 742     goto retry;
 743 
 744   if (locale)
 745     HB_FREE_LOCALE (locale);
 746 }
 747 #endif
 748 
 749 static HB_LOCALE_T
 750 get_C_locale (void)
 751 {
 752 retry:
 753   HB_LOCALE_T C = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
 754 
 755   if (unlikely (!C))
 756   {
 757     C = HB_CREATE_LOCALE ("C");
 758 
 759     if (!hb_atomic_ptr_cmpexch (&C_locale, nullptr, C))
 760     {
 761       HB_FREE_LOCALE (C_locale);
 762       goto retry;
 763     }

 764 
 765 #ifdef HB_USE_ATEXIT
 766     atexit (free_C_locale); /* First person registers atexit() callback. */




 767 #endif
 768   }
 769 
 770   return C;



 771 }
 772 #endif
 773 
 774 static bool
 775 parse_float (const char **pp, const char *end, float *pv)
 776 {
 777   char buf[32];
 778   unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
 779   strncpy (buf, *pp, len);
 780   buf[len] = '\0';
 781 
 782   char *p = buf;
 783   char *pend = p;
 784   float v;
 785 
 786   errno = 0;
 787 #ifdef USE_XLOCALE
 788   v = strtod_l (p, &pend, get_C_locale ());
 789 #else
 790   v = strtod (p, &pend);
 791 #endif
 792   if (errno || p == pend)


 829     feature->value = 1;
 830   }
 831 
 832   return true;
 833 }
 834 
 835 static bool
 836 parse_tag (const char **pp, const char *end, hb_tag_t *tag)
 837 {
 838   parse_space (pp, end);
 839 
 840   char quote = 0;
 841 
 842   if (*pp < end && (**pp == '\'' || **pp == '"'))
 843   {
 844     quote = **pp;
 845     (*pp)++;
 846   }
 847 
 848   const char *p = *pp;
 849   while (*pp < end && ISALNUM(**pp))
 850     (*pp)++;
 851 
 852   if (p == *pp || *pp - p > 4)
 853     return false;
 854 
 855   *tag = hb_tag_from_string (p, *pp - p);
 856 
 857   if (quote)
 858   {
 859     /* CSS expects exactly four bytes.  And we only allow quotations for
 860      * CSS compatibility.  So, enforce the length. */
 861      if (*pp - p != 4)
 862        return false;
 863     if (*pp == end || **pp != quote)
 864       return false;
 865     (*pp)++;
 866   }
 867 
 868   return true;
 869 }
 870 
 871 static bool
 872 parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
 873 {
 874   parse_space (pp, end);
 875 
 876   bool has_start;
 877 
 878   feature->start = 0;
 879   feature->end = (unsigned int) -1;
 880 
 881   if (!parse_char (pp, end, '['))
 882     return true;
 883 
 884   has_start = parse_uint (pp, end, &feature->start);
 885 
 886   if (parse_char (pp, end, ':')) {
 887     parse_uint (pp, end, &feature->end);
 888   } else {
 889     if (has_start)
 890       feature->end = feature->start + 1;
 891   }
 892 
 893   return parse_char (pp, end, ']');
 894 }
 895 
 896 static bool
 897 parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
 898 {
 899   bool had_equal = parse_char (pp, end, '=');
 900   bool had_value = parse_uint32 (pp, end, &feature->value) ||
 901                    parse_bool (pp, end, &feature->value);
 902   /* CSS doesn't use equal-sign between tag and value.
 903    * If there was an equal-sign, then there *must* be a value.
 904    * A value without an equal-sign is ok, but not required. */
 905   return !had_equal || had_value;
 906 }


1046 }
1047 
1048 /**
1049  * hb_variation_to_string:
1050  *
1051  * Since: 1.4.2
1052  */
1053 void
1054 hb_variation_to_string (hb_variation_t *variation,
1055                         char *buf, unsigned int size)
1056 {
1057   if (unlikely (!size)) return;
1058 
1059   char s[128];
1060   unsigned int len = 0;
1061   hb_tag_to_string (variation->tag, s + len);
1062   len += 4;
1063   while (len && s[len - 1] == ' ')
1064     len--;
1065   s[len++] = '=';
1066   len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", variation->value));
1067 
1068   assert (len < ARRAY_LENGTH (s));
1069   len = MIN (len, size - 1);
1070   memcpy (buf, s, len);
1071   buf[len] = '\0';
1072 }











   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-machinery.hh"

  32 
  33 #include <locale.h>
  34 #ifdef HAVE_XLOCALE_H
  35 #include <xlocale.h>
  36 #endif
  37 
  38 
  39 /**
  40  * SECTION:hb-common
  41  * @title: hb-common
  42  * @short_description: Common data types
  43  * @include: hb.h
  44  *
  45  * Common data types used across HarfBuzz are defined here.
  46  **/
  47 
  48 
  49 /* hb_options_t */
  50 
  51 hb_atomic_int_t _hb_options;
  52 
  53 void
  54 _hb_options_init ()
  55 {
  56   hb_options_union_t u;
  57   u.i = 0;
  58   u.opts.initialized = true;
  59 
  60   const char *c = getenv ("HB_OPTIONS");
  61   if (c)
  62   {
  63     while (*c)
  64     {
  65       const char *p = strchr (c, ':');
  66       if (!p)
  67         p = c + strlen (c);
  68 
  69 #define OPTION(name, symbol) \
  70         if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true;
  71 
  72       OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
  73       OPTION ("aat", aat);
  74 
  75 #undef OPTION
  76 
  77       c = *p ? p + 1 : p;
  78     }
  79 
  80   }
  81 
  82   /* This is idempotent and threadsafe. */
  83   _hb_options.set_relaxed (u.i);
  84 }
  85 
  86 
  87 /* hb_tag_t */
  88 
  89 /**
  90  * hb_tag_from_string:
  91  * @str: (array length=len) (element-type uint8_t):
  92  * @len:
  93  *
  94  *
  95  *
  96  * Return value:
  97  *
  98  * Since: 0.9.2
  99  **/
 100 hb_tag_t
 101 hb_tag_from_string (const char *str, int len)
 102 {
 103   char tag[4];


 187 {
 188   if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
 189               < ARRAY_LENGTH (direction_strings)))
 190     return direction_strings[direction - HB_DIRECTION_LTR];
 191 
 192   return "invalid";
 193 }
 194 
 195 
 196 /* hb_language_t */
 197 
 198 struct hb_language_impl_t {
 199   const char s[1];
 200 };
 201 
 202 static const char canon_map[256] = {
 203    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
 204    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
 205    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
 206   '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
 207    0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
 208   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
 209    0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
 210   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
 211 };
 212 
 213 static bool
 214 lang_equal (hb_language_t  v1,
 215             const void    *v2)
 216 {
 217   const unsigned char *p1 = (const unsigned char *) v1;
 218   const unsigned char *p2 = (const unsigned char *) v2;
 219 
 220   while (*p1 && *p1 == canon_map[*p2]) {
 221     p1++;
 222     p2++;
 223   }
 224 
 225   return *p1 == canon_map[*p2];
 226 }
 227 


 230 lang_hash (const void *key)
 231 {
 232   const unsigned char *p = key;
 233   unsigned int h = 0;
 234   while (canon_map[*p])
 235     {
 236       h = (h << 5) - h + canon_map[*p];
 237       p++;
 238     }
 239 
 240   return h;
 241 }
 242 #endif
 243 
 244 
 245 struct hb_language_item_t {
 246 
 247   struct hb_language_item_t *next;
 248   hb_language_t lang;
 249 
 250   bool operator == (const char *s) const
 251   { return lang_equal (lang, s); }

 252 
 253   hb_language_item_t & operator = (const char *s) {
 254     /* If a custom allocated is used calling strdup() pairs
 255     badly with a call to the custom free() in fini() below.
 256     Therefore don't call strdup(), implement its behavior.
 257     */
 258     size_t len = strlen(s) + 1;
 259     lang = (hb_language_t) malloc(len);
 260     if (likely (lang))
 261     {
 262       memcpy((unsigned char *) lang, s, len);
 263       for (unsigned char *p = (unsigned char *) lang; *p; p++)
 264         *p = canon_map[*p];
 265     }
 266 
 267     return *this;
 268   }
 269 
 270   void fini () { free ((void *) lang); }
 271 };
 272 
 273 
 274 /* Thread-safe lock-free language list */
 275 
 276 static hb_atomic_ptr_t <hb_language_item_t> langs;
 277 
 278 #if HB_USE_ATEXIT
 279 static void
 280 free_langs ()
 281 {
 282 retry:
 283   hb_language_item_t *first_lang = langs;
 284   if (unlikely (!langs.cmpexch (first_lang, nullptr)))
 285     goto retry;
 286 
 287   while (first_lang) {
 288     hb_language_item_t *next = first_lang->next;
 289     first_lang->fini ();
 290     free (first_lang);
 291     first_lang = next;
 292   }
 293 }
 294 #endif
 295 
 296 static hb_language_item_t *
 297 lang_find_or_insert (const char *key)
 298 {
 299 retry:
 300   hb_language_item_t *first_lang = langs;
 301 
 302   for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
 303     if (*lang == key)
 304       return lang;
 305 
 306   /* Not found; allocate one. */
 307   hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
 308   if (unlikely (!lang))
 309     return nullptr;
 310   lang->next = first_lang;
 311   *lang = key;
 312   if (unlikely (!lang->lang))
 313   {
 314     free (lang);
 315     return nullptr;
 316   }
 317 
 318   if (unlikely (!langs.cmpexch (first_lang, lang)))
 319   {
 320     lang->fini ();
 321     free (lang);
 322     goto retry;
 323   }
 324 
 325 #if HB_USE_ATEXIT
 326   if (!first_lang)
 327     atexit (free_langs); /* First person registers atexit() callback. */
 328 #endif
 329 
 330   return lang;
 331 }
 332 
 333 
 334 /**
 335  * hb_language_from_string:
 336  * @str: (array length=len) (element-type uint8_t): a string representing
 337  *       a BCP 47 language tag
 338  * @len: length of the @str, or -1 if it is %NULL-terminated.
 339  *
 340  * Converts @str representing a BCP 47 language tag to the corresponding
 341  * #hb_language_t.
 342  *
 343  * Return value: (transfer none):
 344  * The #hb_language_t corresponding to the BCP 47 language tag.
 345  *
 346  * Since: 0.9.2
 347  **/
 348 hb_language_t
 349 hb_language_from_string (const char *str, int len)
 350 {
 351   if (!str || !len || !*str)
 352     return HB_LANGUAGE_INVALID;
 353 
 354   hb_language_item_t *item = nullptr;
 355   if (len >= 0)
 356   {
 357     /* NUL-terminate it. */
 358     char strbuf[64];
 359     len = MIN (len, (int) sizeof (strbuf) - 1);
 360     memcpy (strbuf, str, len);
 361     strbuf[len] = '\0';
 362     item = lang_find_or_insert (strbuf);
 363   }
 364   else


 372  * @language: an #hb_language_t to convert.
 373  *
 374  * See hb_language_from_string().
 375  *
 376  * Return value: (transfer none):
 377  * A %NULL-terminated string representing the @language. Must not be freed by
 378  * the caller.
 379  *
 380  * Since: 0.9.2
 381  **/
 382 const char *
 383 hb_language_to_string (hb_language_t language)
 384 {
 385   /* This is actually nullptr-safe! */
 386   return language->s;
 387 }
 388 
 389 /**
 390  * hb_language_get_default:
 391  *
 392  * Get default language from current locale.
 393  *
 394  * Note that the first time this function is called, it calls
 395  * "setlocale (LC_CTYPE, nullptr)" to fetch current locale.  The underlying
 396  * setlocale function is, in many implementations, NOT threadsafe.  To avoid
 397  * problems, call this function once before multiple threads can call it.
 398  * This function is only used from hb_buffer_guess_segment_properties() by
 399  * HarfBuzz itself.
 400  *
 401  * Return value: (transfer none):
 402  *
 403  * Since: 0.9.2
 404  **/
 405 hb_language_t
 406 hb_language_get_default ()
 407 {
 408   static hb_atomic_ptr_t <hb_language_t> default_language;
 409 
 410   hb_language_t language = default_language;
 411   if (unlikely (language == HB_LANGUAGE_INVALID))
 412   {
 413     language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
 414     (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language);
 415   }
 416 
 417   return language;
 418 }
 419 
 420 
 421 /* hb_script_t */
 422 
 423 /**
 424  * hb_script_from_iso15924_tag:
 425  * @tag: an #hb_tag_t representing an ISO 15924 tag.
 426  *
 427  * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
 428  *
 429  * Return value:
 430  * An #hb_script_t corresponding to the ISO 15924 tag.
 431  *
 432  * Since: 0.9.2
 433  **/
 434 hb_script_t
 435 hb_script_from_iso15924_tag (hb_tag_t tag)
 436 {
 437   if (unlikely (tag == HB_TAG_NONE))


 549     case HB_SCRIPT_OLD_TURKIC:
 550     case HB_SCRIPT_SAMARITAN:
 551 
 552     /* Unicode-6.0 additions */
 553     case HB_SCRIPT_MANDAIC:
 554 
 555     /* Unicode-6.1 additions */
 556     case HB_SCRIPT_MEROITIC_CURSIVE:
 557     case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
 558 
 559     /* Unicode-7.0 additions */
 560     case HB_SCRIPT_MANICHAEAN:
 561     case HB_SCRIPT_MENDE_KIKAKUI:
 562     case HB_SCRIPT_NABATAEAN:
 563     case HB_SCRIPT_OLD_NORTH_ARABIAN:
 564     case HB_SCRIPT_PALMYRENE:
 565     case HB_SCRIPT_PSALTER_PAHLAVI:
 566 
 567     /* Unicode-8.0 additions */
 568     case HB_SCRIPT_HATRAN:

 569 
 570     /* Unicode-9.0 additions */
 571     case HB_SCRIPT_ADLAM:
 572 
 573     /* Unicode-11.0 additions */
 574     case HB_SCRIPT_HANIFI_ROHINGYA:
 575     case HB_SCRIPT_OLD_SOGDIAN:
 576     case HB_SCRIPT_SOGDIAN:
 577 
 578       return HB_DIRECTION_RTL;
 579 
 580 
 581     /* https://github.com/harfbuzz/harfbuzz/issues/1000 */
 582     case HB_SCRIPT_OLD_HUNGARIAN:
 583     case HB_SCRIPT_OLD_ITALIC:
 584     case HB_SCRIPT_RUNIC:
 585 
 586       return HB_DIRECTION_INVALID;
 587   }
 588 
 589   return HB_DIRECTION_LTR;
 590 }
 591 
 592 
 593 /* hb_user_data_array_t */
 594 
 595 bool
 596 hb_user_data_array_t::set (hb_user_data_key_t *key,
 597                            void *              data,
 598                            hb_destroy_func_t   destroy,
 599                            hb_bool_t           replace)
 600 {
 601   if (!key)
 602     return false;
 603 
 604   if (replace) {


 607       return true;
 608     }
 609   }
 610   hb_user_data_item_t item = {key, data, destroy};
 611   bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
 612 
 613   return ret;
 614 }
 615 
 616 void *
 617 hb_user_data_array_t::get (hb_user_data_key_t *key)
 618 {
 619   hb_user_data_item_t item = {nullptr, nullptr, nullptr};
 620 
 621   return items.find (key, &item, lock) ? item.data : nullptr;
 622 }
 623 
 624 
 625 /* hb_version */
 626 
 627 
 628 /**
 629  * SECTION:hb-version
 630  * @title: hb-version
 631  * @short_description: Information about the version of HarfBuzz in use
 632  * @include: hb.h
 633  *
 634  * These functions and macros allow accessing version of the HarfBuzz
 635  * library used at compile- as well as run-time, and to direct code
 636  * conditionally based on those versions, again, at compile- or run-time.
 637  **/
 638 
 639 
 640 /**
 641  * hb_version:
 642  * @major: (out): Library major version component.
 643  * @minor: (out): Library minor version component.
 644  * @micro: (out): Library micro version component.
 645  *
 646  * Returns library version as three integer components.
 647  *
 648  * Since: 0.9.2
 649  **/
 650 void
 651 hb_version (unsigned int *major,
 652             unsigned int *minor,
 653             unsigned int *micro)
 654 {
 655   *major = HB_VERSION_MAJOR;
 656   *minor = HB_VERSION_MINOR;
 657   *micro = HB_VERSION_MICRO;
 658 }
 659 
 660 /**
 661  * hb_version_string:
 662  *
 663  * Returns library version as a string with three components.
 664  *
 665  * Return value: library version string.
 666  *
 667  * Since: 0.9.2
 668  **/
 669 const char *
 670 hb_version_string ()
 671 {
 672   return HB_VERSION_STRING;
 673 }
 674 
 675 /**
 676  * hb_version_atleast:
 677  * @major:
 678  * @minor:
 679  * @micro:
 680  *
 681  *
 682  *
 683  * Return value:
 684  *
 685  * Since: 0.9.30
 686  **/
 687 hb_bool_t
 688 hb_version_atleast (unsigned int major,
 689                     unsigned int minor,
 690                     unsigned int micro)


 762   *pv = v;
 763   *pp += pend - p;
 764   return true;
 765 }
 766 
 767 #if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
 768 #define USE_XLOCALE 1
 769 #define HB_LOCALE_T locale_t
 770 #define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
 771 #define HB_FREE_LOCALE(loc) freelocale (loc)
 772 #elif defined(_MSC_VER)
 773 #define USE_XLOCALE 1
 774 #define HB_LOCALE_T _locale_t
 775 #define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
 776 #define HB_FREE_LOCALE(loc) _free_locale (loc)
 777 #define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
 778 #endif
 779 
 780 #ifdef USE_XLOCALE
 781 
 782 #if HB_USE_ATEXIT
 783 static void free_static_C_locale ();
 784 #endif
 785 
 786 static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (HB_LOCALE_T),
 787                                                           hb_C_locale_lazy_loader_t>

 788 {
 789   static HB_LOCALE_T create ()
 790   {
 791     HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");


 792 
 793 #if HB_USE_ATEXIT
 794     atexit (free_static_C_locale);

 795 #endif
 796 
 797     return C_locale;
 798   }
 799   static void destroy (HB_LOCALE_T p)




 800   {
 801     HB_FREE_LOCALE (p);
 802   }
 803   static HB_LOCALE_T get_null ()
 804   {
 805     return nullptr;

 806   }
 807 } static_C_locale;
 808 
 809 #if HB_USE_ATEXIT
 810 static
 811 void free_static_C_locale ()
 812 {
 813   static_C_locale.free_instance ();
 814 }
 815 #endif

 816 
 817 static HB_LOCALE_T
 818 get_C_locale ()
 819 {
 820   return static_C_locale.get_unconst ();
 821 }
 822 #endif /* USE_XLOCALE */
 823 
 824 static bool
 825 parse_float (const char **pp, const char *end, float *pv)
 826 {
 827   char buf[32];
 828   unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
 829   strncpy (buf, *pp, len);
 830   buf[len] = '\0';
 831 
 832   char *p = buf;
 833   char *pend = p;
 834   float v;
 835 
 836   errno = 0;
 837 #ifdef USE_XLOCALE
 838   v = strtod_l (p, &pend, get_C_locale ());
 839 #else
 840   v = strtod (p, &pend);
 841 #endif
 842   if (errno || p == pend)


 879     feature->value = 1;
 880   }
 881 
 882   return true;
 883 }
 884 
 885 static bool
 886 parse_tag (const char **pp, const char *end, hb_tag_t *tag)
 887 {
 888   parse_space (pp, end);
 889 
 890   char quote = 0;
 891 
 892   if (*pp < end && (**pp == '\'' || **pp == '"'))
 893   {
 894     quote = **pp;
 895     (*pp)++;
 896   }
 897 
 898   const char *p = *pp;
 899   while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
 900     (*pp)++;
 901 
 902   if (p == *pp || *pp - p > 4)
 903     return false;
 904 
 905   *tag = hb_tag_from_string (p, *pp - p);
 906 
 907   if (quote)
 908   {
 909     /* CSS expects exactly four bytes.  And we only allow quotations for
 910      * CSS compatibility.  So, enforce the length. */
 911      if (*pp - p != 4)
 912        return false;
 913     if (*pp == end || **pp != quote)
 914       return false;
 915     (*pp)++;
 916   }
 917 
 918   return true;
 919 }
 920 
 921 static bool
 922 parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
 923 {
 924   parse_space (pp, end);
 925 
 926   bool has_start;
 927 
 928   feature->start = HB_FEATURE_GLOBAL_START;
 929   feature->end = HB_FEATURE_GLOBAL_END;
 930 
 931   if (!parse_char (pp, end, '['))
 932     return true;
 933 
 934   has_start = parse_uint (pp, end, &feature->start);
 935 
 936   if (parse_char (pp, end, ':') || parse_char (pp, end, ';')) {
 937     parse_uint (pp, end, &feature->end);
 938   } else {
 939     if (has_start)
 940       feature->end = feature->start + 1;
 941   }
 942 
 943   return parse_char (pp, end, ']');
 944 }
 945 
 946 static bool
 947 parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
 948 {
 949   bool had_equal = parse_char (pp, end, '=');
 950   bool had_value = parse_uint32 (pp, end, &feature->value) ||
 951                    parse_bool (pp, end, &feature->value);
 952   /* CSS doesn't use equal-sign between tag and value.
 953    * If there was an equal-sign, then there *must* be a value.
 954    * A value without an equal-sign is ok, but not required. */
 955   return !had_equal || had_value;
 956 }


1096 }
1097 
1098 /**
1099  * hb_variation_to_string:
1100  *
1101  * Since: 1.4.2
1102  */
1103 void
1104 hb_variation_to_string (hb_variation_t *variation,
1105                         char *buf, unsigned int size)
1106 {
1107   if (unlikely (!size)) return;
1108 
1109   char s[128];
1110   unsigned int len = 0;
1111   hb_tag_to_string (variation->tag, s + len);
1112   len += 4;
1113   while (len && s[len - 1] == ' ')
1114     len--;
1115   s[len++] = '=';
1116   len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
1117 
1118   assert (len < ARRAY_LENGTH (s));
1119   len = MIN (len, size - 1);
1120   memcpy (buf, s, len);
1121   buf[len] = '\0';
1122 }
1123 
1124 /* If there is no visibility control, then hb-static.cc will NOT
1125  * define anything.  Instead, we get it to define one set in here
1126  * only, so only libharfbuzz.so defines them, not other libs. */
1127 #ifdef HB_NO_VISIBILITY
1128 #undef HB_NO_VISIBILITY
1129 #include "hb-static.cc"
1130 #define HB_NO_VISIBILITY 1
1131 #endif
< prev index next >