1 /*
   2  * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
   3  *
   4  * Permission to use, copy, modify, and/or distribute this software for any
   5  * purpose with or without fee is hereby granted, provided that the above
   6  * copyright notice and this permission notice appear in all copies.
   7  *
   8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15  */
  16 
  17 #include "hb-private.hh"
  18 
  19 #include "hb-unicode-private.hh"
  20 
  21 #include "ucdn.h"
  22 
  23 static const hb_script_t ucdn_script_translate[] =
  24 {
  25     HB_SCRIPT_COMMON,
  26     HB_SCRIPT_LATIN,
  27     HB_SCRIPT_GREEK,
  28     HB_SCRIPT_CYRILLIC,
  29     HB_SCRIPT_ARMENIAN,
  30     HB_SCRIPT_HEBREW,
  31     HB_SCRIPT_ARABIC,
  32     HB_SCRIPT_SYRIAC,
  33     HB_SCRIPT_THAANA,
  34     HB_SCRIPT_DEVANAGARI,
  35     HB_SCRIPT_BENGALI,
  36     HB_SCRIPT_GURMUKHI,
  37     HB_SCRIPT_GUJARATI,
  38     HB_SCRIPT_ORIYA,
  39     HB_SCRIPT_TAMIL,
  40     HB_SCRIPT_TELUGU,
  41     HB_SCRIPT_KANNADA,
  42     HB_SCRIPT_MALAYALAM,
  43     HB_SCRIPT_SINHALA,
  44     HB_SCRIPT_THAI,
  45     HB_SCRIPT_LAO,
  46     HB_SCRIPT_TIBETAN,
  47     HB_SCRIPT_MYANMAR,
  48     HB_SCRIPT_GEORGIAN,
  49     HB_SCRIPT_HANGUL,
  50     HB_SCRIPT_ETHIOPIC,
  51     HB_SCRIPT_CHEROKEE,
  52     HB_SCRIPT_CANADIAN_SYLLABICS,
  53     HB_SCRIPT_OGHAM,
  54     HB_SCRIPT_RUNIC,
  55     HB_SCRIPT_KHMER,
  56     HB_SCRIPT_MONGOLIAN,
  57     HB_SCRIPT_HIRAGANA,
  58     HB_SCRIPT_KATAKANA,
  59     HB_SCRIPT_BOPOMOFO,
  60     HB_SCRIPT_HAN,
  61     HB_SCRIPT_YI,
  62     HB_SCRIPT_OLD_ITALIC,
  63     HB_SCRIPT_GOTHIC,
  64     HB_SCRIPT_DESERET,
  65     HB_SCRIPT_INHERITED,
  66     HB_SCRIPT_TAGALOG,
  67     HB_SCRIPT_HANUNOO,
  68     HB_SCRIPT_BUHID,
  69     HB_SCRIPT_TAGBANWA,
  70     HB_SCRIPT_LIMBU,
  71     HB_SCRIPT_TAI_LE,
  72     HB_SCRIPT_LINEAR_B,
  73     HB_SCRIPT_UGARITIC,
  74     HB_SCRIPT_SHAVIAN,
  75     HB_SCRIPT_OSMANYA,
  76     HB_SCRIPT_CYPRIOT,
  77     HB_SCRIPT_BRAILLE,
  78     HB_SCRIPT_BUGINESE,
  79     HB_SCRIPT_COPTIC,
  80     HB_SCRIPT_NEW_TAI_LUE,
  81     HB_SCRIPT_GLAGOLITIC,
  82     HB_SCRIPT_TIFINAGH,
  83     HB_SCRIPT_SYLOTI_NAGRI,
  84     HB_SCRIPT_OLD_PERSIAN,
  85     HB_SCRIPT_KHAROSHTHI,
  86     HB_SCRIPT_BALINESE,
  87     HB_SCRIPT_CUNEIFORM,
  88     HB_SCRIPT_PHOENICIAN,
  89     HB_SCRIPT_PHAGS_PA,
  90     HB_SCRIPT_NKO,
  91     HB_SCRIPT_SUNDANESE,
  92     HB_SCRIPT_LEPCHA,
  93     HB_SCRIPT_OL_CHIKI,
  94     HB_SCRIPT_VAI,
  95     HB_SCRIPT_SAURASHTRA,
  96     HB_SCRIPT_KAYAH_LI,
  97     HB_SCRIPT_REJANG,
  98     HB_SCRIPT_LYCIAN,
  99     HB_SCRIPT_CARIAN,
 100     HB_SCRIPT_LYDIAN,
 101     HB_SCRIPT_CHAM,
 102     HB_SCRIPT_TAI_THAM,
 103     HB_SCRIPT_TAI_VIET,
 104     HB_SCRIPT_AVESTAN,
 105     HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
 106     HB_SCRIPT_SAMARITAN,
 107     HB_SCRIPT_LISU,
 108     HB_SCRIPT_BAMUM,
 109     HB_SCRIPT_JAVANESE,
 110     HB_SCRIPT_MEETEI_MAYEK,
 111     HB_SCRIPT_IMPERIAL_ARAMAIC,
 112     HB_SCRIPT_OLD_SOUTH_ARABIAN,
 113     HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
 114     HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
 115     HB_SCRIPT_OLD_TURKIC,
 116     HB_SCRIPT_KAITHI,
 117     HB_SCRIPT_BATAK,
 118     HB_SCRIPT_BRAHMI,
 119     HB_SCRIPT_MANDAIC,
 120     HB_SCRIPT_CHAKMA,
 121     HB_SCRIPT_MEROITIC_CURSIVE,
 122     HB_SCRIPT_MEROITIC_HIEROGLYPHS,
 123     HB_SCRIPT_MIAO,
 124     HB_SCRIPT_SHARADA,
 125     HB_SCRIPT_SORA_SOMPENG,
 126     HB_SCRIPT_TAKRI,
 127     HB_SCRIPT_UNKNOWN,
 128     HB_SCRIPT_BASSA_VAH,
 129     HB_SCRIPT_CAUCASIAN_ALBANIAN,
 130     HB_SCRIPT_DUPLOYAN,
 131     HB_SCRIPT_ELBASAN,
 132     HB_SCRIPT_GRANTHA,
 133     HB_SCRIPT_KHOJKI,
 134     HB_SCRIPT_KHUDAWADI,
 135     HB_SCRIPT_LINEAR_A,
 136     HB_SCRIPT_MAHAJANI,
 137     HB_SCRIPT_MANICHAEAN,
 138     HB_SCRIPT_MENDE_KIKAKUI,
 139     HB_SCRIPT_MODI,
 140     HB_SCRIPT_MRO,
 141     HB_SCRIPT_NABATAEAN,
 142     HB_SCRIPT_OLD_NORTH_ARABIAN,
 143     HB_SCRIPT_OLD_PERMIC,
 144     HB_SCRIPT_PAHAWH_HMONG,
 145     HB_SCRIPT_PALMYRENE,
 146     HB_SCRIPT_PAU_CIN_HAU,
 147     HB_SCRIPT_PSALTER_PAHLAVI,
 148     HB_SCRIPT_SIDDHAM,
 149     HB_SCRIPT_TIRHUTA,
 150     HB_SCRIPT_WARANG_CITI,
 151     HB_SCRIPT_AHOM,
 152     HB_SCRIPT_ANATOLIAN_HIEROGLYPHS,
 153     HB_SCRIPT_HATRAN,
 154     HB_SCRIPT_MULTANI,
 155     HB_SCRIPT_OLD_HUNGARIAN,
 156     HB_SCRIPT_SIGNWRITING,
 157     HB_SCRIPT_ADLAM,
 158     HB_SCRIPT_BHAIKSUKI,
 159     HB_SCRIPT_MARCHEN,
 160     HB_SCRIPT_NEWA,
 161     HB_SCRIPT_OSAGE,
 162     HB_SCRIPT_TANGUT,
 163     HB_SCRIPT_MASARAM_GONDI,
 164     HB_SCRIPT_NUSHU,
 165     HB_SCRIPT_SOYOMBO,
 166     HB_SCRIPT_ZANABAZAR_SQUARE,
 167     HB_SCRIPT_DOGRA,
 168     HB_SCRIPT_GUNJALA_GONDI,
 169     HB_SCRIPT_HANIFI_ROHINGYA,
 170     HB_SCRIPT_MAKASAR,
 171     HB_SCRIPT_MEDEFAIDRIN,
 172     HB_SCRIPT_OLD_SOGDIAN,
 173     HB_SCRIPT_SOGDIAN,
 174 };
 175 
 176 static hb_unicode_combining_class_t
 177 hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 178                         hb_codepoint_t unicode,
 179                         void *user_data HB_UNUSED)
 180 {
 181     return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode);
 182 }
 183 
 184 static unsigned int
 185 hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 186                         hb_codepoint_t unicode,
 187                         void *user_data HB_UNUSED)
 188 {
 189     int w = ucdn_get_east_asian_width(unicode);
 190     return (w == UCDN_EAST_ASIAN_F || w == UCDN_EAST_ASIAN_W) ? 2 : 1;
 191 }
 192 
 193 static hb_unicode_general_category_t
 194 hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 195                          hb_codepoint_t unicode,
 196                          void *user_data HB_UNUSED)
 197 {
 198     return (hb_unicode_general_category_t)ucdn_get_general_category(unicode);
 199 }
 200 
 201 static hb_codepoint_t
 202 hb_ucdn_mirroring(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 203                   hb_codepoint_t unicode,
 204                   void *user_data HB_UNUSED)
 205 {
 206     return ucdn_mirror(unicode);
 207 }
 208 
 209 static hb_script_t
 210 hb_ucdn_script(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 211                hb_codepoint_t unicode,
 212                void *user_data HB_UNUSED)
 213 {
 214     return ucdn_script_translate[ucdn_get_script(unicode)];
 215 }
 216 
 217 static hb_bool_t
 218 hb_ucdn_compose(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 219                 hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
 220                 void *user_data HB_UNUSED)
 221 {
 222     return ucdn_compose(ab, a, b);
 223 }
 224 
 225 static hb_bool_t
 226 hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 227                   hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b,
 228                   void *user_data HB_UNUSED)
 229 {
 230     return ucdn_decompose(ab, a, b);
 231 }
 232 
 233 static unsigned int
 234 hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 235                                 hb_codepoint_t u, hb_codepoint_t *decomposed,
 236                                 void *user_data HB_UNUSED)
 237 {
 238     return ucdn_compat_decompose(u, decomposed);
 239 }
 240 
 241 static hb_unicode_funcs_t *static_ucdn_funcs = nullptr;
 242 
 243 #ifdef HB_USE_ATEXIT
 244 static
 245 void free_static_ucdn_funcs (void)
 246 {
 247 retry:
 248   hb_unicode_funcs_t *ucdn_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_ucdn_funcs);
 249   if (!hb_atomic_ptr_cmpexch (&static_ucdn_funcs, ucdn_funcs, nullptr))
 250     goto retry;
 251 
 252   hb_unicode_funcs_destroy (ucdn_funcs);
 253 }
 254 #endif
 255 
 256 extern "C" HB_INTERNAL
 257 hb_unicode_funcs_t *
 258 hb_ucdn_get_unicode_funcs (void)
 259 {
 260 retry:
 261   hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_ucdn_funcs);
 262 
 263   if (unlikely (!funcs))
 264   {
 265     funcs = hb_unicode_funcs_create (nullptr);
 266 
 267 #define HB_UNICODE_FUNC_IMPLEMENT(name) \
 268     hb_unicode_funcs_set_##name##_func (funcs, hb_ucdn_##name, nullptr, nullptr);
 269       HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 270 #undef HB_UNICODE_FUNC_IMPLEMENT
 271 
 272     hb_unicode_funcs_make_immutable (funcs);
 273 
 274     if (!hb_atomic_ptr_cmpexch (&static_ucdn_funcs, nullptr, funcs)) {
 275       hb_unicode_funcs_destroy (funcs);
 276       goto retry;
 277     }
 278 
 279 #ifdef HB_USE_ATEXIT
 280     atexit (free_static_ucdn_funcs); /* First person registers atexit() callback. */
 281 #endif
 282   };
 283 
 284   return hb_unicode_funcs_reference (funcs);
 285 }