1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-common.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,577 @@ 1.4 +/* 1.5 + * Copyright © 2009,2010 Red Hat, Inc. 1.6 + * Copyright © 2011,2012 Google, Inc. 1.7 + * 1.8 + * This is part of HarfBuzz, a text shaping library. 1.9 + * 1.10 + * Permission is hereby granted, without written agreement and without 1.11 + * license or royalty fees, to use, copy, modify, and distribute this 1.12 + * software and its documentation for any purpose, provided that the 1.13 + * above copyright notice and the following two paragraphs appear in 1.14 + * all copies of this software. 1.15 + * 1.16 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.17 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.18 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.19 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.20 + * DAMAGE. 1.21 + * 1.22 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.23 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.24 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.25 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.26 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.27 + * 1.28 + * Red Hat Author(s): Behdad Esfahbod 1.29 + * Google Author(s): Behdad Esfahbod 1.30 + */ 1.31 + 1.32 +#include "hb-private.hh" 1.33 + 1.34 +#include "hb-mutex-private.hh" 1.35 +#include "hb-object-private.hh" 1.36 + 1.37 +#include <locale.h> 1.38 + 1.39 + 1.40 +/* hb_options_t */ 1.41 + 1.42 +hb_options_union_t _hb_options; 1.43 + 1.44 +void 1.45 +_hb_options_init (void) 1.46 +{ 1.47 + hb_options_union_t u; 1.48 + u.i = 0; 1.49 + u.opts.initialized = 1; 1.50 + 1.51 + char *c = getenv ("HB_OPTIONS"); 1.52 + u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); 1.53 + 1.54 + /* This is idempotent and threadsafe. */ 1.55 + _hb_options = u; 1.56 +} 1.57 + 1.58 + 1.59 +/* hb_tag_t */ 1.60 + 1.61 +/** 1.62 + * hb_tag_from_string: 1.63 + * @str: (array length=len): 1.64 + * @len: 1.65 + * 1.66 + * 1.67 + * 1.68 + * Return value: 1.69 + * 1.70 + * Since: 1.0 1.71 + **/ 1.72 +hb_tag_t 1.73 +hb_tag_from_string (const char *str, int len) 1.74 +{ 1.75 + char tag[4]; 1.76 + unsigned int i; 1.77 + 1.78 + if (!str || !len || !*str) 1.79 + return HB_TAG_NONE; 1.80 + 1.81 + if (len < 0 || len > 4) 1.82 + len = 4; 1.83 + for (i = 0; i < (unsigned) len && str[i]; i++) 1.84 + tag[i] = str[i]; 1.85 + for (; i < 4; i++) 1.86 + tag[i] = ' '; 1.87 + 1.88 + return HB_TAG_CHAR4 (tag); 1.89 +} 1.90 + 1.91 +/** 1.92 + * hb_tag_to_string: 1.93 + * @tag: 1.94 + * @buf: (array fixed-size=4): 1.95 + * 1.96 + * 1.97 + * 1.98 + * Since: 1.0 1.99 + **/ 1.100 +void 1.101 +hb_tag_to_string (hb_tag_t tag, char *buf) 1.102 +{ 1.103 + buf[0] = (char) (uint8_t) (tag >> 24); 1.104 + buf[1] = (char) (uint8_t) (tag >> 16); 1.105 + buf[2] = (char) (uint8_t) (tag >> 8); 1.106 + buf[3] = (char) (uint8_t) (tag >> 0); 1.107 +} 1.108 + 1.109 + 1.110 +/* hb_direction_t */ 1.111 + 1.112 +const char direction_strings[][4] = { 1.113 + "ltr", 1.114 + "rtl", 1.115 + "ttb", 1.116 + "btt" 1.117 +}; 1.118 + 1.119 +/** 1.120 + * hb_direction_from_string: 1.121 + * @str: (array length=len): 1.122 + * @len: 1.123 + * 1.124 + * 1.125 + * 1.126 + * Return value: 1.127 + * 1.128 + * Since: 1.0 1.129 + **/ 1.130 +hb_direction_t 1.131 +hb_direction_from_string (const char *str, int len) 1.132 +{ 1.133 + if (unlikely (!str || !len || !*str)) 1.134 + return HB_DIRECTION_INVALID; 1.135 + 1.136 + /* Lets match loosely: just match the first letter, such that 1.137 + * all of "ltr", "left-to-right", etc work! 1.138 + */ 1.139 + char c = TOLOWER (str[0]); 1.140 + for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++) 1.141 + if (c == direction_strings[i][0]) 1.142 + return (hb_direction_t) (HB_DIRECTION_LTR + i); 1.143 + 1.144 + return HB_DIRECTION_INVALID; 1.145 +} 1.146 + 1.147 +/** 1.148 + * hb_direction_to_string: 1.149 + * @direction: 1.150 + * 1.151 + * 1.152 + * 1.153 + * Return value: (transfer none): 1.154 + * 1.155 + * Since: 1.0 1.156 + **/ 1.157 +const char * 1.158 +hb_direction_to_string (hb_direction_t direction) 1.159 +{ 1.160 + if (likely ((unsigned int) (direction - HB_DIRECTION_LTR) 1.161 + < ARRAY_LENGTH (direction_strings))) 1.162 + return direction_strings[direction - HB_DIRECTION_LTR]; 1.163 + 1.164 + return "invalid"; 1.165 +} 1.166 + 1.167 + 1.168 +/* hb_language_t */ 1.169 + 1.170 +struct hb_language_impl_t { 1.171 + const char s[1]; 1.172 +}; 1.173 + 1.174 +static const char canon_map[256] = { 1.175 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.176 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.177 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 1.178 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0, 1.179 + '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 1.180 + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-', 1.181 + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 1.182 + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0 1.183 +}; 1.184 + 1.185 +static hb_bool_t 1.186 +lang_equal (hb_language_t v1, 1.187 + const void *v2) 1.188 +{ 1.189 + const unsigned char *p1 = (const unsigned char *) v1; 1.190 + const unsigned char *p2 = (const unsigned char *) v2; 1.191 + 1.192 + while (*p1 && *p1 == canon_map[*p2]) 1.193 + p1++, p2++; 1.194 + 1.195 + return *p1 == canon_map[*p2]; 1.196 +} 1.197 + 1.198 +#if 0 1.199 +static unsigned int 1.200 +lang_hash (const void *key) 1.201 +{ 1.202 + const unsigned char *p = key; 1.203 + unsigned int h = 0; 1.204 + while (canon_map[*p]) 1.205 + { 1.206 + h = (h << 5) - h + canon_map[*p]; 1.207 + p++; 1.208 + } 1.209 + 1.210 + return h; 1.211 +} 1.212 +#endif 1.213 + 1.214 + 1.215 +struct hb_language_item_t { 1.216 + 1.217 + struct hb_language_item_t *next; 1.218 + hb_language_t lang; 1.219 + 1.220 + inline bool operator == (const char *s) const { 1.221 + return lang_equal (lang, s); 1.222 + } 1.223 + 1.224 + inline hb_language_item_t & operator = (const char *s) { 1.225 + lang = (hb_language_t) strdup (s); 1.226 + for (unsigned char *p = (unsigned char *) lang; *p; p++) 1.227 + *p = canon_map[*p]; 1.228 + 1.229 + return *this; 1.230 + } 1.231 + 1.232 + void finish (void) { free ((void *) lang); } 1.233 +}; 1.234 + 1.235 + 1.236 +/* Thread-safe lock-free language list */ 1.237 + 1.238 +static hb_language_item_t *langs; 1.239 + 1.240 +static inline 1.241 +void free_langs (void) 1.242 +{ 1.243 + while (langs) { 1.244 + hb_language_item_t *next = langs->next; 1.245 + langs->finish (); 1.246 + free (langs); 1.247 + langs = next; 1.248 + } 1.249 +} 1.250 + 1.251 +static hb_language_item_t * 1.252 +lang_find_or_insert (const char *key) 1.253 +{ 1.254 +retry: 1.255 + hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs); 1.256 + 1.257 + for (hb_language_item_t *lang = first_lang; lang; lang = lang->next) 1.258 + if (*lang == key) 1.259 + return lang; 1.260 + 1.261 + /* Not found; allocate one. */ 1.262 + hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t)); 1.263 + if (unlikely (!lang)) 1.264 + return NULL; 1.265 + lang->next = first_lang; 1.266 + *lang = key; 1.267 + 1.268 + if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) { 1.269 + free (lang); 1.270 + goto retry; 1.271 + } 1.272 + 1.273 +#ifdef HAVE_ATEXIT 1.274 + if (!first_lang) 1.275 + atexit (free_langs); /* First person registers atexit() callback. */ 1.276 +#endif 1.277 + 1.278 + return lang; 1.279 +} 1.280 + 1.281 + 1.282 +/** 1.283 + * hb_language_from_string: 1.284 + * @str: (array length=len): 1.285 + * @len: 1.286 + * 1.287 + * 1.288 + * 1.289 + * Return value: 1.290 + * 1.291 + * Since: 1.0 1.292 + **/ 1.293 +hb_language_t 1.294 +hb_language_from_string (const char *str, int len) 1.295 +{ 1.296 + char strbuf[64]; 1.297 + 1.298 + if (!str || !len || !*str) 1.299 + return HB_LANGUAGE_INVALID; 1.300 + 1.301 + if (len >= 0) 1.302 + { 1.303 + len = MIN (len, (int) sizeof (strbuf) - 1); 1.304 + str = (char *) memcpy (strbuf, str, len); 1.305 + strbuf[len] = '\0'; 1.306 + } 1.307 + 1.308 + hb_language_item_t *item = lang_find_or_insert (str); 1.309 + 1.310 + return likely (item) ? item->lang : HB_LANGUAGE_INVALID; 1.311 +} 1.312 + 1.313 +/** 1.314 + * hb_language_to_string: 1.315 + * @language: 1.316 + * 1.317 + * 1.318 + * 1.319 + * Return value: (transfer none): 1.320 + * 1.321 + * Since: 1.0 1.322 + **/ 1.323 +const char * 1.324 +hb_language_to_string (hb_language_t language) 1.325 +{ 1.326 + /* This is actually NULL-safe! */ 1.327 + return language->s; 1.328 +} 1.329 + 1.330 +/** 1.331 + * hb_language_get_default: 1.332 + * 1.333 + * 1.334 + * 1.335 + * Return value: 1.336 + * 1.337 + * Since: 1.0 1.338 + **/ 1.339 +hb_language_t 1.340 +hb_language_get_default (void) 1.341 +{ 1.342 + static hb_language_t default_language = HB_LANGUAGE_INVALID; 1.343 + 1.344 + hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language); 1.345 + if (unlikely (language == HB_LANGUAGE_INVALID)) { 1.346 + language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1); 1.347 + hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language); 1.348 + } 1.349 + 1.350 + return default_language; 1.351 +} 1.352 + 1.353 + 1.354 +/* hb_script_t */ 1.355 + 1.356 +/** 1.357 + * hb_script_from_iso15924_tag: 1.358 + * @tag: 1.359 + * 1.360 + * 1.361 + * 1.362 + * Return value: 1.363 + * 1.364 + * Since: 1.0 1.365 + **/ 1.366 +hb_script_t 1.367 +hb_script_from_iso15924_tag (hb_tag_t tag) 1.368 +{ 1.369 + if (unlikely (tag == HB_TAG_NONE)) 1.370 + return HB_SCRIPT_INVALID; 1.371 + 1.372 + /* Be lenient, adjust case (one capital letter followed by three small letters) */ 1.373 + tag = (tag & 0xDFDFDFDF) | 0x00202020; 1.374 + 1.375 + switch (tag) { 1.376 + 1.377 + /* These graduated from the 'Q' private-area codes, but 1.378 + * the old code is still aliased by Unicode, and the Qaai 1.379 + * one in use by ICU. */ 1.380 + case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED; 1.381 + case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC; 1.382 + 1.383 + /* Script variants from http://unicode.org/iso15924/ */ 1.384 + case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC; 1.385 + case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN; 1.386 + case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN; 1.387 + case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC; 1.388 + case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC; 1.389 + case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC; 1.390 + } 1.391 + 1.392 + /* If it looks right, just use the tag as a script */ 1.393 + if (((uint32_t) tag & 0xE0E0E0E0) == 0x40606060) 1.394 + return (hb_script_t) tag; 1.395 + 1.396 + /* Otherwise, return unknown */ 1.397 + return HB_SCRIPT_UNKNOWN; 1.398 +} 1.399 + 1.400 +/** 1.401 + * hb_script_from_string: 1.402 + * @s: (array length=len): 1.403 + * @len: 1.404 + * 1.405 + * 1.406 + * 1.407 + * Return value: 1.408 + * 1.409 + * Since: 1.0 1.410 + **/ 1.411 +hb_script_t 1.412 +hb_script_from_string (const char *s, int len) 1.413 +{ 1.414 + return hb_script_from_iso15924_tag (hb_tag_from_string (s, len)); 1.415 +} 1.416 + 1.417 +/** 1.418 + * hb_script_to_iso15924_tag: 1.419 + * @script: 1.420 + * 1.421 + * 1.422 + * 1.423 + * Return value: 1.424 + * 1.425 + * Since: 1.0 1.426 + **/ 1.427 +hb_tag_t 1.428 +hb_script_to_iso15924_tag (hb_script_t script) 1.429 +{ 1.430 + return (hb_tag_t) script; 1.431 +} 1.432 + 1.433 +/** 1.434 + * hb_script_get_horizontal_direction: 1.435 + * @script: 1.436 + * 1.437 + * 1.438 + * 1.439 + * Return value: 1.440 + * 1.441 + * Since: 1.0 1.442 + **/ 1.443 +hb_direction_t 1.444 +hb_script_get_horizontal_direction (hb_script_t script) 1.445 +{ 1.446 + /* http://goo.gl/x9ilM */ 1.447 + switch ((hb_tag_t) script) 1.448 + { 1.449 + /* Unicode-1.1 additions */ 1.450 + case HB_SCRIPT_ARABIC: 1.451 + case HB_SCRIPT_HEBREW: 1.452 + 1.453 + /* Unicode-3.0 additions */ 1.454 + case HB_SCRIPT_SYRIAC: 1.455 + case HB_SCRIPT_THAANA: 1.456 + 1.457 + /* Unicode-4.0 additions */ 1.458 + case HB_SCRIPT_CYPRIOT: 1.459 + 1.460 + /* Unicode-4.1 additions */ 1.461 + case HB_SCRIPT_KHAROSHTHI: 1.462 + 1.463 + /* Unicode-5.0 additions */ 1.464 + case HB_SCRIPT_PHOENICIAN: 1.465 + case HB_SCRIPT_NKO: 1.466 + 1.467 + /* Unicode-5.1 additions */ 1.468 + case HB_SCRIPT_LYDIAN: 1.469 + 1.470 + /* Unicode-5.2 additions */ 1.471 + case HB_SCRIPT_AVESTAN: 1.472 + case HB_SCRIPT_IMPERIAL_ARAMAIC: 1.473 + case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: 1.474 + case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: 1.475 + case HB_SCRIPT_OLD_SOUTH_ARABIAN: 1.476 + case HB_SCRIPT_OLD_TURKIC: 1.477 + case HB_SCRIPT_SAMARITAN: 1.478 + 1.479 + /* Unicode-6.0 additions */ 1.480 + case HB_SCRIPT_MANDAIC: 1.481 + 1.482 + /* Unicode-6.1 additions */ 1.483 + case HB_SCRIPT_MEROITIC_CURSIVE: 1.484 + case HB_SCRIPT_MEROITIC_HIEROGLYPHS: 1.485 + 1.486 + return HB_DIRECTION_RTL; 1.487 + } 1.488 + 1.489 + return HB_DIRECTION_LTR; 1.490 +} 1.491 + 1.492 + 1.493 +/* hb_user_data_array_t */ 1.494 + 1.495 +bool 1.496 +hb_user_data_array_t::set (hb_user_data_key_t *key, 1.497 + void * data, 1.498 + hb_destroy_func_t destroy, 1.499 + hb_bool_t replace) 1.500 +{ 1.501 + if (!key) 1.502 + return false; 1.503 + 1.504 + if (replace) { 1.505 + if (!data && !destroy) { 1.506 + items.remove (key, lock); 1.507 + return true; 1.508 + } 1.509 + } 1.510 + hb_user_data_item_t item = {key, data, destroy}; 1.511 + bool ret = !!items.replace_or_insert (item, lock, replace); 1.512 + 1.513 + return ret; 1.514 +} 1.515 + 1.516 +void * 1.517 +hb_user_data_array_t::get (hb_user_data_key_t *key) 1.518 +{ 1.519 + hb_user_data_item_t item = {NULL }; 1.520 + 1.521 + return items.find (key, &item, lock) ? item.data : NULL; 1.522 +} 1.523 + 1.524 + 1.525 +/* hb_version */ 1.526 + 1.527 +/** 1.528 + * hb_version: 1.529 + * @major: (out): Library major version component. 1.530 + * @minor: (out): Library minor version component. 1.531 + * @micro: (out): Library micro version component. 1.532 + * 1.533 + * Returns library version as three integer components. 1.534 + * 1.535 + * Since: 1.0 1.536 + **/ 1.537 +void 1.538 +hb_version (unsigned int *major, 1.539 + unsigned int *minor, 1.540 + unsigned int *micro) 1.541 +{ 1.542 + *major = HB_VERSION_MAJOR; 1.543 + *minor = HB_VERSION_MINOR; 1.544 + *micro = HB_VERSION_MICRO; 1.545 +} 1.546 + 1.547 +/** 1.548 + * hb_version_string: 1.549 + * 1.550 + * Returns library version as a string with three components. 1.551 + * 1.552 + * Return value: library version string. 1.553 + * 1.554 + * Since: 1.0 1.555 + **/ 1.556 +const char * 1.557 +hb_version_string (void) 1.558 +{ 1.559 + return HB_VERSION_STRING; 1.560 +} 1.561 + 1.562 +/** 1.563 + * hb_version_check: 1.564 + * @major: 1.565 + * @minor: 1.566 + * @micro: 1.567 + * 1.568 + * 1.569 + * 1.570 + * Return value: 1.571 + * 1.572 + * Since: 1.0 1.573 + **/ 1.574 +hb_bool_t 1.575 +hb_version_check (unsigned int major, 1.576 + unsigned int minor, 1.577 + unsigned int micro) 1.578 +{ 1.579 + return HB_VERSION_CHECK (major, minor, micro); 1.580 +}