gfx/harfbuzz/src/hb-common.cc

changeset 0
6474c204b198
     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 +}

mercurial