Mailbox support for texture layers.
[chromium-blink-merge.git] / third_party / harfbuzz-ng / src / hb-common.cc
blob33a514dbfda8758283208a9e264a8cee98c64137
1 /*
2 * Copyright © 2009,2010 Red Hat, Inc.
3 * Copyright © 2011,2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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.
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #include "hb-private.hh"
31 #include "hb-version.h"
33 #include "hb-mutex-private.hh"
34 #include "hb-object-private.hh"
36 #include <locale.h>
40 /* hb_tag_t */
42 hb_tag_t
43 hb_tag_from_string (const char *s, int len)
45 char tag[4];
46 unsigned int i;
48 if (!s || !len || !*s)
49 return HB_TAG_NONE;
51 if (len < 0 || len > 4)
52 len = 4;
53 for (i = 0; i < (unsigned) len && s[i]; i++)
54 tag[i] = s[i];
55 for (; i < 4; i++)
56 tag[i] = ' ';
58 return HB_TAG_CHAR4 (tag);
61 void
62 hb_tag_to_string (hb_tag_t tag, char *buf)
64 buf[0] = (char) (uint8_t) (tag >> 24);
65 buf[1] = (char) (uint8_t) (tag >> 16);
66 buf[2] = (char) (uint8_t) (tag >> 8);
67 buf[3] = (char) (uint8_t) (tag >> 0);
71 /* hb_direction_t */
73 const char direction_strings[][4] = {
74 "ltr",
75 "rtl",
76 "ttb",
77 "btt"
80 hb_direction_t
81 hb_direction_from_string (const char *str, int len)
83 if (unlikely (!str || !len || !*str))
84 return HB_DIRECTION_INVALID;
86 /* Lets match loosely: just match the first letter, such that
87 * all of "ltr", "left-to-right", etc work!
89 char c = TOLOWER (str[0]);
90 for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
91 if (c == direction_strings[i][0])
92 return (hb_direction_t) (HB_DIRECTION_LTR + i);
94 return HB_DIRECTION_INVALID;
97 const char *
98 hb_direction_to_string (hb_direction_t direction)
100 if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
101 < ARRAY_LENGTH (direction_strings)))
102 return direction_strings[direction - HB_DIRECTION_LTR];
104 return "invalid";
108 /* hb_language_t */
110 struct hb_language_impl_t {
111 const char s[1];
114 static const char canon_map[256] = {
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0,
118 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
119 '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
120 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-',
121 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
122 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
125 static hb_bool_t
126 lang_equal (hb_language_t v1,
127 const void *v2)
129 const unsigned char *p1 = (const unsigned char *) v1;
130 const unsigned char *p2 = (const unsigned char *) v2;
132 while (*p1 && *p1 == canon_map[*p2])
133 p1++, p2++;
135 return *p1 == canon_map[*p2];
138 #if 0
139 static unsigned int
140 lang_hash (const void *key)
142 const unsigned char *p = key;
143 unsigned int h = 0;
144 while (canon_map[*p])
146 h = (h << 5) - h + canon_map[*p];
147 p++;
150 return h;
152 #endif
155 struct hb_language_item_t {
157 struct hb_language_item_t *next;
158 hb_language_t lang;
160 inline bool operator == (const char *s) const {
161 return lang_equal (lang, s);
164 inline hb_language_item_t & operator = (const char *s) {
165 lang = (hb_language_t) strdup (s);
166 for (unsigned char *p = (unsigned char *) lang; *p; p++)
167 *p = canon_map[*p];
169 return *this;
172 void finish (void) { free (lang); }
176 /* Thread-safe lock-free language list */
178 static hb_language_item_t *langs;
180 static
181 void free_langs (void)
183 while (langs) {
184 hb_language_item_t *next = langs->next;
185 langs->finish ();
186 free (langs);
187 langs = next;
191 static hb_language_item_t *
192 lang_find_or_insert (const char *key)
194 retry:
195 hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
197 for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
198 if (*lang == key)
199 return lang;
201 /* Not found; allocate one. */
202 hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
203 if (unlikely (!lang))
204 return NULL;
205 lang->next = first_lang;
206 *lang = key;
208 if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
209 free (lang);
210 goto retry;
213 #ifdef HAVE_ATEXIT
214 if (!first_lang)
215 atexit (free_langs); /* First person registers atexit() callback. */
216 #endif
218 return lang;
222 hb_language_t
223 hb_language_from_string (const char *str, int len)
225 if (!str || !len || !*str)
226 return HB_LANGUAGE_INVALID;
228 char strbuf[32];
229 if (len >= 0) {
230 len = MIN (len, (int) sizeof (strbuf) - 1);
231 str = (char *) memcpy (strbuf, str, len);
232 strbuf[len] = '\0';
235 hb_language_item_t *item = lang_find_or_insert (str);
237 return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
240 const char *
241 hb_language_to_string (hb_language_t language)
243 /* This is actually NULL-safe! */
244 return language->s;
247 hb_language_t
248 hb_language_get_default (void)
250 static hb_language_t default_language = HB_LANGUAGE_INVALID;
252 hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
253 if (unlikely (language == HB_LANGUAGE_INVALID)) {
254 language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
255 hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
258 return default_language;
262 /* hb_script_t */
264 hb_script_t
265 hb_script_from_iso15924_tag (hb_tag_t tag)
267 if (unlikely (tag == HB_TAG_NONE))
268 return HB_SCRIPT_INVALID;
270 /* Be lenient, adjust case (one capital letter followed by three small letters) */
271 tag = (tag & 0xDFDFDFDF) | 0x00202020;
273 switch (tag) {
275 /* These graduated from the 'Q' private-area codes, but
276 * the old code is still aliased by Unicode, and the Qaai
277 * one in use by ICU. */
278 case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
279 case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
281 /* Script variants from http://unicode.org/iso15924/ */
282 case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
283 case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
284 case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
285 case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
286 case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
287 case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
290 /* If it looks right, just use the tag as a script */
291 if (((uint32_t) tag & 0xE0E0E0E0) == 0x40606060)
292 return (hb_script_t) tag;
294 /* Otherwise, return unknown */
295 return HB_SCRIPT_UNKNOWN;
298 hb_script_t
299 hb_script_from_string (const char *s, int len)
301 return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
304 hb_tag_t
305 hb_script_to_iso15924_tag (hb_script_t script)
307 return (hb_tag_t) script;
310 hb_direction_t
311 hb_script_get_horizontal_direction (hb_script_t script)
313 /* http://goo.gl/x9ilM */
314 switch ((hb_tag_t) script)
316 /* Unicode-1.1 additions */
317 case HB_SCRIPT_ARABIC:
318 case HB_SCRIPT_HEBREW:
320 /* Unicode-3.0 additions */
321 case HB_SCRIPT_SYRIAC:
322 case HB_SCRIPT_THAANA:
324 /* Unicode-4.0 additions */
325 case HB_SCRIPT_CYPRIOT:
327 /* Unicode-4.1 additions */
328 case HB_SCRIPT_KHAROSHTHI:
330 /* Unicode-5.0 additions */
331 case HB_SCRIPT_PHOENICIAN:
332 case HB_SCRIPT_NKO:
334 /* Unicode-5.1 additions */
335 case HB_SCRIPT_LYDIAN:
337 /* Unicode-5.2 additions */
338 case HB_SCRIPT_AVESTAN:
339 case HB_SCRIPT_IMPERIAL_ARAMAIC:
340 case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
341 case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
342 case HB_SCRIPT_OLD_SOUTH_ARABIAN:
343 case HB_SCRIPT_OLD_TURKIC:
344 case HB_SCRIPT_SAMARITAN:
346 /* Unicode-6.0 additions */
347 case HB_SCRIPT_MANDAIC:
349 /* Unicode-6.1 additions */
350 case HB_SCRIPT_MEROITIC_CURSIVE:
351 case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
353 return HB_DIRECTION_RTL;
356 return HB_DIRECTION_LTR;
360 /* hb_user_data_array_t */
362 bool
363 hb_user_data_array_t::set (hb_user_data_key_t *key,
364 void * data,
365 hb_destroy_func_t destroy,
366 hb_bool_t replace,
367 hb_mutex_t &lock)
369 if (!key)
370 return false;
372 if (replace) {
373 if (!data && !destroy) {
374 items.remove (key, lock);
375 return true;
378 hb_user_data_item_t item = {key, data, destroy};
379 bool ret = !!items.replace_or_insert (item, lock, replace);
381 return ret;
384 void *
385 hb_user_data_array_t::get (hb_user_data_key_t *key,
386 hb_mutex_t &lock)
388 hb_user_data_item_t item = {NULL };
390 return items.find (key, &item, lock) ? item.data : NULL;
393 void
394 hb_user_data_array_t::finish (hb_mutex_t &lock)
396 items.finish (lock);
400 /* hb_version */
402 void
403 hb_version (unsigned int *major,
404 unsigned int *minor,
405 unsigned int *micro)
407 *major = HB_VERSION_MAJOR;
408 *minor = HB_VERSION_MINOR;
409 *micro = HB_VERSION_MICRO;
412 const char *
413 hb_version_string (void)
415 return HB_VERSION_STRING;
418 hb_bool_t
419 hb_version_check (unsigned int major,
420 unsigned int minor,
421 unsigned int micro)
423 return HB_VERSION_CHECK (major, minor, micro);