jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.cc
changeset 34414 e496a8d8fc8a
child 40435 553eb1a50733
equal deleted inserted replaced
34413:bbed9966db6e 34414:e496a8d8fc8a
       
     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-private.hh"
       
    30 
       
    31 #include "hb-mutex-private.hh"
       
    32 #include "hb-object-private.hh"
       
    33 
       
    34 #include <locale.h>
       
    35 
       
    36 
       
    37 /* hb_options_t */
       
    38 
       
    39 hb_options_union_t _hb_options;
       
    40 
       
    41 void
       
    42 _hb_options_init (void)
       
    43 {
       
    44   hb_options_union_t u;
       
    45   u.i = 0;
       
    46   u.opts.initialized = 1;
       
    47 
       
    48   char *c = getenv ("HB_OPTIONS");
       
    49   u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
       
    50 
       
    51   /* This is idempotent and threadsafe. */
       
    52   _hb_options = u;
       
    53 }
       
    54 
       
    55 
       
    56 /* hb_tag_t */
       
    57 
       
    58 /**
       
    59  * hb_tag_from_string:
       
    60  * @str: (array length=len) (element-type uint8_t):
       
    61  * @len:
       
    62  *
       
    63  *
       
    64  *
       
    65  * Return value:
       
    66  *
       
    67  * Since: 0.9.2
       
    68  **/
       
    69 hb_tag_t
       
    70 hb_tag_from_string (const char *str, int len)
       
    71 {
       
    72   char tag[4];
       
    73   unsigned int i;
       
    74 
       
    75   if (!str || !len || !*str)
       
    76     return HB_TAG_NONE;
       
    77 
       
    78   if (len < 0 || len > 4)
       
    79     len = 4;
       
    80   for (i = 0; i < (unsigned) len && str[i]; i++)
       
    81     tag[i] = str[i];
       
    82   for (; i < 4; i++)
       
    83     tag[i] = ' ';
       
    84 
       
    85   return HB_TAG_CHAR4 (tag);
       
    86 }
       
    87 
       
    88 /**
       
    89  * hb_tag_to_string:
       
    90  * @tag:
       
    91  * @buf: (array fixed-size=4):
       
    92  *
       
    93  *
       
    94  *
       
    95  * Since: 0.9.5
       
    96  **/
       
    97 void
       
    98 hb_tag_to_string (hb_tag_t tag, char *buf)
       
    99 {
       
   100   buf[0] = (char) (uint8_t) (tag >> 24);
       
   101   buf[1] = (char) (uint8_t) (tag >> 16);
       
   102   buf[2] = (char) (uint8_t) (tag >>  8);
       
   103   buf[3] = (char) (uint8_t) (tag >>  0);
       
   104 }
       
   105 
       
   106 
       
   107 /* hb_direction_t */
       
   108 
       
   109 const char direction_strings[][4] = {
       
   110   "ltr",
       
   111   "rtl",
       
   112   "ttb",
       
   113   "btt"
       
   114 };
       
   115 
       
   116 /**
       
   117  * hb_direction_from_string:
       
   118  * @str: (array length=len) (element-type uint8_t):
       
   119  * @len:
       
   120  *
       
   121  *
       
   122  *
       
   123  * Return value:
       
   124  *
       
   125  * Since: 0.9.2
       
   126  **/
       
   127 hb_direction_t
       
   128 hb_direction_from_string (const char *str, int len)
       
   129 {
       
   130   if (unlikely (!str || !len || !*str))
       
   131     return HB_DIRECTION_INVALID;
       
   132 
       
   133   /* Lets match loosely: just match the first letter, such that
       
   134    * all of "ltr", "left-to-right", etc work!
       
   135    */
       
   136   char c = TOLOWER (str[0]);
       
   137   for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
       
   138     if (c == direction_strings[i][0])
       
   139       return (hb_direction_t) (HB_DIRECTION_LTR + i);
       
   140 
       
   141   return HB_DIRECTION_INVALID;
       
   142 }
       
   143 
       
   144 /**
       
   145  * hb_direction_to_string:
       
   146  * @direction:
       
   147  *
       
   148  *
       
   149  *
       
   150  * Return value: (transfer none):
       
   151  *
       
   152  * Since: 0.9.2
       
   153  **/
       
   154 const char *
       
   155 hb_direction_to_string (hb_direction_t direction)
       
   156 {
       
   157   if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
       
   158               < ARRAY_LENGTH (direction_strings)))
       
   159     return direction_strings[direction - HB_DIRECTION_LTR];
       
   160 
       
   161   return "invalid";
       
   162 }
       
   163 
       
   164 
       
   165 /* hb_language_t */
       
   166 
       
   167 struct hb_language_impl_t {
       
   168   const char s[1];
       
   169 };
       
   170 
       
   171 static const char canon_map[256] = {
       
   172    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
       
   173    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
       
   174    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
       
   175   '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
       
   176   '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
       
   177   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
       
   178    0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
       
   179   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
       
   180 };
       
   181 
       
   182 static bool
       
   183 lang_equal (hb_language_t  v1,
       
   184             const void    *v2)
       
   185 {
       
   186   const unsigned char *p1 = (const unsigned char *) v1;
       
   187   const unsigned char *p2 = (const unsigned char *) v2;
       
   188 
       
   189   while (*p1 && *p1 == canon_map[*p2])
       
   190     p1++, p2++;
       
   191 
       
   192   return *p1 == canon_map[*p2];
       
   193 }
       
   194 
       
   195 #if 0
       
   196 static unsigned int
       
   197 lang_hash (const void *key)
       
   198 {
       
   199   const unsigned char *p = key;
       
   200   unsigned int h = 0;
       
   201   while (canon_map[*p])
       
   202     {
       
   203       h = (h << 5) - h + canon_map[*p];
       
   204       p++;
       
   205     }
       
   206 
       
   207   return h;
       
   208 }
       
   209 #endif
       
   210 
       
   211 
       
   212 struct hb_language_item_t {
       
   213 
       
   214   struct hb_language_item_t *next;
       
   215   hb_language_t lang;
       
   216 
       
   217   inline bool operator == (const char *s) const {
       
   218     return lang_equal (lang, s);
       
   219   }
       
   220 
       
   221   inline hb_language_item_t & operator = (const char *s) {
       
   222     lang = (hb_language_t) strdup (s);
       
   223     for (unsigned char *p = (unsigned char *) lang; *p; p++)
       
   224       *p = canon_map[*p];
       
   225 
       
   226     return *this;
       
   227   }
       
   228 
       
   229   void finish (void) { free ((void *) lang); }
       
   230 };
       
   231 
       
   232 
       
   233 /* Thread-safe lock-free language list */
       
   234 
       
   235 static hb_language_item_t *langs;
       
   236 
       
   237 #ifdef HB_USE_ATEXIT
       
   238 static
       
   239 void free_langs (void)
       
   240 {
       
   241   while (langs) {
       
   242     hb_language_item_t *next = langs->next;
       
   243     langs->finish ();
       
   244     free (langs);
       
   245     langs = next;
       
   246   }
       
   247 }
       
   248 #endif
       
   249 
       
   250 static hb_language_item_t *
       
   251 lang_find_or_insert (const char *key)
       
   252 {
       
   253 retry:
       
   254   hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
       
   255 
       
   256   for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
       
   257     if (*lang == key)
       
   258       return lang;
       
   259 
       
   260   /* Not found; allocate one. */
       
   261   hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
       
   262   if (unlikely (!lang))
       
   263     return NULL;
       
   264   lang->next = first_lang;
       
   265   *lang = key;
       
   266 
       
   267   if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
       
   268     lang->finish ();
       
   269     free (lang);
       
   270     goto retry;
       
   271   }
       
   272 
       
   273 #ifdef HB_USE_ATEXIT
       
   274   if (!first_lang)
       
   275     atexit (free_langs); /* First person registers atexit() callback. */
       
   276 #endif
       
   277 
       
   278   return lang;
       
   279 }
       
   280 
       
   281 
       
   282 /**
       
   283  * hb_language_from_string:
       
   284  * @str: (array length=len) (element-type uint8_t):
       
   285  * @len:
       
   286  *
       
   287  *
       
   288  *
       
   289  * Return value: (transfer none):
       
   290  *
       
   291  * Since: 0.9.2
       
   292  **/
       
   293 hb_language_t
       
   294 hb_language_from_string (const char *str, int len)
       
   295 {
       
   296   if (!str || !len || !*str)
       
   297     return HB_LANGUAGE_INVALID;
       
   298 
       
   299   hb_language_item_t *item = NULL;
       
   300   if (len >= 0)
       
   301   {
       
   302     /* NUL-terminate it. */
       
   303     char strbuf[64];
       
   304     len = MIN (len, (int) sizeof (strbuf) - 1);
       
   305     memcpy (strbuf, str, len);
       
   306     strbuf[len] = '\0';
       
   307     item = lang_find_or_insert (strbuf);
       
   308   }
       
   309   else
       
   310     item = lang_find_or_insert (str);
       
   311 
       
   312   return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
       
   313 }
       
   314 
       
   315 /**
       
   316  * hb_language_to_string:
       
   317  * @language:
       
   318  *
       
   319  *
       
   320  *
       
   321  * Return value: (transfer none):
       
   322  *
       
   323  * Since: 0.9.2
       
   324  **/
       
   325 const char *
       
   326 hb_language_to_string (hb_language_t language)
       
   327 {
       
   328   /* This is actually NULL-safe! */
       
   329   return language->s;
       
   330 }
       
   331 
       
   332 /**
       
   333  * hb_language_get_default:
       
   334  *
       
   335  *
       
   336  *
       
   337  * Return value: (transfer none):
       
   338  *
       
   339  * Since: 0.9.2
       
   340  **/
       
   341 hb_language_t
       
   342 hb_language_get_default (void)
       
   343 {
       
   344   static hb_language_t default_language = HB_LANGUAGE_INVALID;
       
   345 
       
   346   hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
       
   347   if (unlikely (language == HB_LANGUAGE_INVALID)) {
       
   348     language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
       
   349     (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
       
   350   }
       
   351 
       
   352   return default_language;
       
   353 }
       
   354 
       
   355 
       
   356 /* hb_script_t */
       
   357 
       
   358 /**
       
   359  * hb_script_from_iso15924_tag:
       
   360  * @tag:
       
   361  *
       
   362  *
       
   363  *
       
   364  * Return value:
       
   365  *
       
   366  * Since: 0.9.2
       
   367  **/
       
   368 hb_script_t
       
   369 hb_script_from_iso15924_tag (hb_tag_t tag)
       
   370 {
       
   371   if (unlikely (tag == HB_TAG_NONE))
       
   372     return HB_SCRIPT_INVALID;
       
   373 
       
   374   /* Be lenient, adjust case (one capital letter followed by three small letters) */
       
   375   tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
       
   376 
       
   377   switch (tag) {
       
   378 
       
   379     /* These graduated from the 'Q' private-area codes, but
       
   380      * the old code is still aliased by Unicode, and the Qaai
       
   381      * one in use by ICU. */
       
   382     case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
       
   383     case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
       
   384 
       
   385     /* Script variants from http://unicode.org/iso15924/ */
       
   386     case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
       
   387     case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
       
   388     case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
       
   389     case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
       
   390     case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
       
   391     case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
       
   392   }
       
   393 
       
   394   /* If it looks right, just use the tag as a script */
       
   395   if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
       
   396     return (hb_script_t) tag;
       
   397 
       
   398   /* Otherwise, return unknown */
       
   399   return HB_SCRIPT_UNKNOWN;
       
   400 }
       
   401 
       
   402 /**
       
   403  * hb_script_from_string:
       
   404  * @s: (array length=len) (element-type uint8_t):
       
   405  * @len:
       
   406  *
       
   407  *
       
   408  *
       
   409  * Return value:
       
   410  *
       
   411  * Since: 0.9.2
       
   412  **/
       
   413 hb_script_t
       
   414 hb_script_from_string (const char *s, int len)
       
   415 {
       
   416   return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
       
   417 }
       
   418 
       
   419 /**
       
   420  * hb_script_to_iso15924_tag:
       
   421  * @script:
       
   422  *
       
   423  *
       
   424  *
       
   425  * Return value:
       
   426  *
       
   427  * Since: 0.9.2
       
   428  **/
       
   429 hb_tag_t
       
   430 hb_script_to_iso15924_tag (hb_script_t script)
       
   431 {
       
   432   return (hb_tag_t) script;
       
   433 }
       
   434 
       
   435 /**
       
   436  * hb_script_get_horizontal_direction:
       
   437  * @script:
       
   438  *
       
   439  *
       
   440  *
       
   441  * Return value:
       
   442  *
       
   443  * Since: 0.9.2
       
   444  **/
       
   445 hb_direction_t
       
   446 hb_script_get_horizontal_direction (hb_script_t script)
       
   447 {
       
   448   /* http://goo.gl/x9ilM */
       
   449   switch ((hb_tag_t) script)
       
   450   {
       
   451     /* Unicode-1.1 additions */
       
   452     case HB_SCRIPT_ARABIC:
       
   453     case HB_SCRIPT_HEBREW:
       
   454 
       
   455     /* Unicode-3.0 additions */
       
   456     case HB_SCRIPT_SYRIAC:
       
   457     case HB_SCRIPT_THAANA:
       
   458 
       
   459     /* Unicode-4.0 additions */
       
   460     case HB_SCRIPT_CYPRIOT:
       
   461 
       
   462     /* Unicode-4.1 additions */
       
   463     case HB_SCRIPT_KHAROSHTHI:
       
   464 
       
   465     /* Unicode-5.0 additions */
       
   466     case HB_SCRIPT_PHOENICIAN:
       
   467     case HB_SCRIPT_NKO:
       
   468 
       
   469     /* Unicode-5.1 additions */
       
   470     case HB_SCRIPT_LYDIAN:
       
   471 
       
   472     /* Unicode-5.2 additions */
       
   473     case HB_SCRIPT_AVESTAN:
       
   474     case HB_SCRIPT_IMPERIAL_ARAMAIC:
       
   475     case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
       
   476     case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
       
   477     case HB_SCRIPT_OLD_SOUTH_ARABIAN:
       
   478     case HB_SCRIPT_OLD_TURKIC:
       
   479     case HB_SCRIPT_SAMARITAN:
       
   480 
       
   481     /* Unicode-6.0 additions */
       
   482     case HB_SCRIPT_MANDAIC:
       
   483 
       
   484     /* Unicode-6.1 additions */
       
   485     case HB_SCRIPT_MEROITIC_CURSIVE:
       
   486     case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
       
   487 
       
   488     /* Unicode-7.0 additions */
       
   489     case HB_SCRIPT_MANICHAEAN:
       
   490     case HB_SCRIPT_MENDE_KIKAKUI:
       
   491     case HB_SCRIPT_NABATAEAN:
       
   492     case HB_SCRIPT_OLD_NORTH_ARABIAN:
       
   493     case HB_SCRIPT_PALMYRENE:
       
   494     case HB_SCRIPT_PSALTER_PAHLAVI:
       
   495 
       
   496     /* Unicode-8.0 additions */
       
   497     case HB_SCRIPT_OLD_HUNGARIAN:
       
   498 
       
   499       return HB_DIRECTION_RTL;
       
   500   }
       
   501 
       
   502   return HB_DIRECTION_LTR;
       
   503 }
       
   504 
       
   505 
       
   506 /* hb_user_data_array_t */
       
   507 
       
   508 bool
       
   509 hb_user_data_array_t::set (hb_user_data_key_t *key,
       
   510                            void *              data,
       
   511                            hb_destroy_func_t   destroy,
       
   512                            hb_bool_t           replace)
       
   513 {
       
   514   if (!key)
       
   515     return false;
       
   516 
       
   517   if (replace) {
       
   518     if (!data && !destroy) {
       
   519       items.remove (key, lock);
       
   520       return true;
       
   521     }
       
   522   }
       
   523   hb_user_data_item_t item = {key, data, destroy};
       
   524   bool ret = !!items.replace_or_insert (item, lock, replace);
       
   525 
       
   526   return ret;
       
   527 }
       
   528 
       
   529 void *
       
   530 hb_user_data_array_t::get (hb_user_data_key_t *key)
       
   531 {
       
   532   hb_user_data_item_t item = {NULL };
       
   533 
       
   534   return items.find (key, &item, lock) ? item.data : NULL;
       
   535 }
       
   536 
       
   537 
       
   538 /* hb_version */
       
   539 
       
   540 /**
       
   541  * hb_version:
       
   542  * @major: (out): Library major version component.
       
   543  * @minor: (out): Library minor version component.
       
   544  * @micro: (out): Library micro version component.
       
   545  *
       
   546  * Returns library version as three integer components.
       
   547  *
       
   548  * Since: 0.9.2
       
   549  **/
       
   550 void
       
   551 hb_version (unsigned int *major,
       
   552             unsigned int *minor,
       
   553             unsigned int *micro)
       
   554 {
       
   555   *major = HB_VERSION_MAJOR;
       
   556   *minor = HB_VERSION_MINOR;
       
   557   *micro = HB_VERSION_MICRO;
       
   558 }
       
   559 
       
   560 /**
       
   561  * hb_version_string:
       
   562  *
       
   563  * Returns library version as a string with three components.
       
   564  *
       
   565  * Return value: library version string.
       
   566  *
       
   567  * Since: 0.9.2
       
   568  **/
       
   569 const char *
       
   570 hb_version_string (void)
       
   571 {
       
   572   return HB_VERSION_STRING;
       
   573 }
       
   574 
       
   575 /**
       
   576  * hb_version_atleast:
       
   577  * @major:
       
   578  * @minor:
       
   579  * @micro:
       
   580  *
       
   581  *
       
   582  *
       
   583  * Return value:
       
   584  *
       
   585  * Since: 0.9.30
       
   586  **/
       
   587 hb_bool_t
       
   588 hb_version_atleast (unsigned int major,
       
   589                     unsigned int minor,
       
   590                     unsigned int micro)
       
   591 {
       
   592   return HB_VERSION_ATLEAST (major, minor, micro);
       
   593 }