2 * Copyright © 2009,2010 Red Hat, Inc.
3 * Copyright © 2011 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
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"
42 hb_tag_from_string (const char *s)
50 for (i = 0; i < 4 && s[i]; i++)
55 return HB_TAG_CHAR4 (tag);
61 const char direction_strings[][4] = {
69 hb_direction_from_string (const char *str)
71 if (unlikely (!str || !*str))
72 return HB_DIRECTION_INVALID;
74 /* Lets match loosely: just match the first letter, such that
75 * all of "ltr", "left-to-right", etc work!
77 char c = TOLOWER (str[0]);
78 for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
79 if (c == direction_strings[i][0])
80 return (hb_direction_t) i;
82 return HB_DIRECTION_INVALID;
86 hb_direction_to_string (hb_direction_t direction)
88 if (likely ((unsigned int) direction < ARRAY_LENGTH (direction_strings)))
89 return direction_strings[direction];
97 struct _hb_language_t {
101 static const char canon_map[256] = {
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0,
105 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
106 '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
107 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-',
108 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
109 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
113 lang_equal (const void *v1,
116 const unsigned char *p1 = (const unsigned char *) v1;
117 const unsigned char *p2 = (const unsigned char *) v2;
119 while (canon_map[*p1] && canon_map[*p1] == canon_map[*p2])
124 return (canon_map[*p1] == canon_map[*p2]);
129 lang_hash (const void *key)
131 const unsigned char *p = key;
133 while (canon_map[*p])
135 h = (h << 5) - h + canon_map[*p];
144 struct hb_language_item_t {
148 inline bool operator == (const char *s) const {
149 return lang_equal (lang, s);
152 inline hb_language_item_t & operator = (const char *s) {
153 lang = (hb_language_t) strdup (s);
154 for (unsigned char *p = (unsigned char *) lang; *p; p++)
160 void finish (void) { free (lang); }
163 static hb_threadsafe_set_t<hb_language_item_t> langs;
166 hb_language_from_string (const char *str)
171 hb_language_item_t *item = langs.find_or_insert (str);
173 return likely (item) ? item->lang : NULL;
177 hb_language_to_string (hb_language_t language)
186 hb_script_from_iso15924_tag (hb_tag_t tag)
188 if (unlikely (tag == HB_TAG_NONE))
189 return HB_SCRIPT_INVALID;
191 /* Be lenient, adjust case (one capital letter followed by three small letters) */
192 tag = (tag & 0xDFDFDFDF) | 0x00202020;
196 /* These graduated from the 'Q' private-area codes, but
197 * the old code is still aliased by Unicode, and the Qaai
198 * one in use by ICU. */
199 case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
200 case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
202 /* Script variants from http://unicode.org/iso15924/ */
203 case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
204 case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
205 case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
206 case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
207 case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
208 case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
211 /* If it looks right, just use the tag as a script */
212 if (((uint32_t) tag & 0xE0E0E0E0) == 0x40606060)
213 return (hb_script_t) tag;
215 /* Otherwise, return unknown */
216 return HB_SCRIPT_UNKNOWN;
220 hb_script_from_string (const char *s)
222 return hb_script_from_iso15924_tag (hb_tag_from_string (s));
226 hb_script_to_iso15924_tag (hb_script_t script)
228 return (hb_tag_t) script;
232 hb_script_get_horizontal_direction (hb_script_t script)
234 switch ((hb_tag_t) script)
236 case HB_SCRIPT_ARABIC:
237 case HB_SCRIPT_HEBREW:
238 case HB_SCRIPT_SYRIAC:
239 case HB_SCRIPT_THAANA:
241 /* Unicode-4.0 additions */
242 case HB_SCRIPT_CYPRIOT:
244 /* Unicode-5.0 additions */
245 case HB_SCRIPT_PHOENICIAN:
248 /* Unicode-5.2 additions */
249 case HB_SCRIPT_AVESTAN:
250 case HB_SCRIPT_IMPERIAL_ARAMAIC:
251 case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
252 case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
253 case HB_SCRIPT_OLD_SOUTH_ARABIAN:
254 case HB_SCRIPT_OLD_TURKIC:
255 case HB_SCRIPT_SAMARITAN:
257 /* Unicode-6.0 additions */
258 case HB_SCRIPT_MANDAIC:
260 return HB_DIRECTION_RTL;
263 return HB_DIRECTION_LTR;
267 /* hb_user_data_array_t */
270 /* NOTE: Currently we use a global lock for user_data access
271 * threadsafety. If one day we add a mutex to any object, we
272 * should switch to using that insted for these too.
275 static hb_static_mutex_t user_data_mutex;
278 hb_user_data_array_t::set (hb_user_data_key_t *key,
280 hb_destroy_func_t destroy)
285 hb_mutex_lock (&user_data_mutex);
287 if (!data && !destroy) {
291 hb_user_data_item_t item = {key, data, destroy};
292 bool ret = !!items.insert (item);
294 hb_mutex_unlock (&user_data_mutex);
300 hb_user_data_array_t::get (hb_user_data_key_t *key)
302 hb_mutex_lock (&user_data_mutex);
304 hb_user_data_item_t *item = items.find (key);
305 void *ret = item ? item->data : NULL;
307 hb_mutex_unlock (&user_data_mutex);
316 hb_version (unsigned int *major,
320 *major = HB_VERSION_MAJOR;
321 *minor = HB_VERSION_MINOR;
322 *micro = HB_VERSION_MICRO;
326 hb_version_string (void)
328 return HB_VERSION_STRING;
332 hb_version_check (unsigned int major,
336 return HB_VERSION_CHECK (major, minor, micro);