49f3eb8857fde094aebb3ea5ea6b1a15a8d1e854
[apps/home/video-player.git] / src / hb-common.cc
1 /*
2  * Copyright © 2009,2010  Red Hat, Inc.
3  * Copyright © 2011  Google, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
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.
12  *
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.
18  *
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.
24  *
25  * Red Hat Author(s): Behdad Esfahbod
26  * Google Author(s): Behdad Esfahbod
27  */
28
29 #include "hb-private.hh"
30
31 #include "hb-version.h"
32
33 #include "hb-mutex-private.hh"
34 #include "hb-object-private.hh"
35
36 HB_BEGIN_DECLS
37
38
39 /* hb_tag_t */
40
41 hb_tag_t
42 hb_tag_from_string (const char *s)
43 {
44   char tag[4];
45   unsigned int i;
46
47   if (!s || !*s)
48     return HB_TAG_NONE;
49
50   for (i = 0; i < 4 && s[i]; i++)
51     tag[i] = s[i];
52   for (; i < 4; i++)
53     tag[i] = ' ';
54
55   return HB_TAG_CHAR4 (tag);
56 }
57
58
59 /* hb_direction_t */
60
61 const char direction_strings[][4] = {
62   "ltr",
63   "rtl",
64   "ttb",
65   "btt"
66 };
67
68 hb_direction_t
69 hb_direction_from_string (const char *str)
70 {
71   if (unlikely (!str || !*str))
72     return HB_DIRECTION_INVALID;
73
74   /* Lets match loosely: just match the first letter, such that
75    * all of "ltr", "left-to-right", etc work!
76    */
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;
81
82   return HB_DIRECTION_INVALID;
83 }
84
85 const char *
86 hb_direction_to_string (hb_direction_t direction)
87 {
88   if (likely ((unsigned int) direction < ARRAY_LENGTH (direction_strings)))
89     return direction_strings[direction];
90
91   return "invalid";
92 }
93
94
95 /* hb_language_t */
96
97 struct _hb_language_t {
98   const char s[1];
99 };
100
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
110 };
111
112 static hb_bool_t
113 lang_equal (const void *v1,
114             const void *v2)
115 {
116   const unsigned char *p1 = (const unsigned char *) v1;
117   const unsigned char *p2 = (const unsigned char *) v2;
118
119   while (canon_map[*p1] && canon_map[*p1] == canon_map[*p2])
120     {
121       p1++, p2++;
122     }
123
124   return (canon_map[*p1] == canon_map[*p2]);
125 }
126
127 #if 0
128 static unsigned int
129 lang_hash (const void *key)
130 {
131   const unsigned char *p = key;
132   unsigned int h = 0;
133   while (canon_map[*p])
134     {
135       h = (h << 5) - h + canon_map[*p];
136       p++;
137     }
138
139   return h;
140 }
141 #endif
142
143
144 struct hb_language_item_t {
145
146   hb_language_t lang;
147
148   inline bool operator == (const char *s) const {
149     return lang_equal (lang, s);
150   }
151
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++)
155       *p = canon_map[*p];
156
157     return *this;
158   }
159
160   void finish (void) { free (lang); }
161 };
162
163 static hb_threadsafe_set_t<hb_language_item_t> langs;
164
165 hb_language_t
166 hb_language_from_string (const char *str)
167 {
168   if (!str || !*str)
169     return NULL;
170
171   hb_language_item_t *item = langs.find_or_insert (str);
172
173   return likely (item) ? item->lang : NULL;
174 }
175
176 const char *
177 hb_language_to_string (hb_language_t language)
178 {
179   return language->s;
180 }
181
182
183 /* hb_script_t */
184
185 hb_script_t
186 hb_script_from_iso15924_tag (hb_tag_t tag)
187 {
188   if (unlikely (tag == HB_TAG_NONE))
189     return HB_SCRIPT_INVALID;
190
191   /* Be lenient, adjust case (one capital letter followed by three small letters) */
192   tag = (tag & 0xDFDFDFDF) | 0x00202020;
193
194   switch (tag) {
195
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;
201
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;
209   }
210
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;
214
215   /* Otherwise, return unknown */
216   return HB_SCRIPT_UNKNOWN;
217 }
218
219 hb_script_t
220 hb_script_from_string (const char *s)
221 {
222   return hb_script_from_iso15924_tag (hb_tag_from_string (s));
223 }
224
225 hb_tag_t
226 hb_script_to_iso15924_tag (hb_script_t script)
227 {
228   return (hb_tag_t) script;
229 }
230
231 hb_direction_t
232 hb_script_get_horizontal_direction (hb_script_t script)
233 {
234   switch ((hb_tag_t) script)
235   {
236     case HB_SCRIPT_ARABIC:
237     case HB_SCRIPT_HEBREW:
238     case HB_SCRIPT_SYRIAC:
239     case HB_SCRIPT_THAANA:
240
241     /* Unicode-4.0 additions */
242     case HB_SCRIPT_CYPRIOT:
243
244     /* Unicode-5.0 additions */
245     case HB_SCRIPT_PHOENICIAN:
246     case HB_SCRIPT_NKO:
247
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:
256
257     /* Unicode-6.0 additions */
258     case HB_SCRIPT_MANDAIC:
259
260       return HB_DIRECTION_RTL;
261   }
262
263   return HB_DIRECTION_LTR;
264 }
265
266
267 /* hb_user_data_array_t */
268
269
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.
273  */
274
275 static hb_static_mutex_t user_data_mutex;
276
277 bool
278 hb_user_data_array_t::set (hb_user_data_key_t *key,
279                            void *              data,
280                            hb_destroy_func_t   destroy)
281 {
282   if (!key)
283     return false;
284
285   hb_mutex_lock (&user_data_mutex);
286
287   if (!data && !destroy) {
288     items.remove (key);
289     return true;
290   }
291   hb_user_data_item_t item = {key, data, destroy};
292   bool ret = !!items.insert (item);
293
294   hb_mutex_unlock (&user_data_mutex);
295
296   return ret;
297 }
298
299 void *
300 hb_user_data_array_t::get (hb_user_data_key_t *key)
301 {
302   hb_mutex_lock (&user_data_mutex);
303
304   hb_user_data_item_t *item = items.find (key);
305   void *ret = item ? item->data : NULL;
306
307   hb_mutex_unlock (&user_data_mutex);
308
309   return ret;
310 }
311
312
313 /* hb_version */
314
315 void
316 hb_version (unsigned int *major,
317             unsigned int *minor,
318             unsigned int *micro)
319 {
320   *major = HB_VERSION_MAJOR;
321   *minor = HB_VERSION_MINOR;
322   *micro = HB_VERSION_MICRO;
323 }
324
325 const char *
326 hb_version_string (void)
327 {
328   return HB_VERSION_STRING;
329 }
330
331 hb_bool_t
332 hb_version_check (unsigned int major,
333                   unsigned int minor,
334                   unsigned int micro)
335 {
336   return HB_VERSION_CHECK (major, minor, micro);
337 }
338
339
340 HB_END_DECLS