41229b9183ef996493113a62aa8b891b1cd7b857
[platform/upstream/harfbuzz.git] / src / hb-common.cc
1 /*
2  * Copyright © 2009,2010  Red Hat, Inc.
3  * Copyright © 2011,2012  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.hh"
30 #include "hb-machinery.hh"
31
32 #if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE))
33 #define HB_NO_SETLOCALE 1
34 #endif
35
36 #ifndef HB_NO_SETLOCALE
37
38 #include <locale.h>
39 #ifdef HAVE_XLOCALE_H
40 #include <xlocale.h> // Needed on BSD/OS X for uselocale
41 #endif
42
43 #ifdef WIN32
44 #define hb_locale_t _locale_t
45 #else
46 #define hb_locale_t locale_t
47 #endif
48 #define hb_setlocale setlocale
49 #define hb_uselocale uselocale
50
51 #else
52
53 #define hb_locale_t void *
54 #define hb_setlocale(Category, Locale) "C"
55 #define hb_uselocale(Locale) ((hb_locale_t) 0)
56
57 #endif
58
59 /**
60  * SECTION:hb-common
61  * @title: hb-common
62  * @short_description: Common data types
63  * @include: hb.h
64  *
65  * Common data types used across HarfBuzz are defined here.
66  **/
67
68
69 /* hb_options_t */
70
71 hb_atomic_int_t _hb_options;
72
73 void
74 _hb_options_init ()
75 {
76   hb_options_union_t u;
77   u.i = 0;
78   u.opts.initialized = true;
79
80   const char *c = getenv ("HB_OPTIONS");
81   if (c)
82   {
83     while (*c)
84     {
85       const char *p = strchr (c, ':');
86       if (!p)
87         p = c + strlen (c);
88
89 #define OPTION(name, symbol) \
90         if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
91
92       OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
93
94 #undef OPTION
95
96       c = *p ? p + 1 : p;
97     }
98
99   }
100
101   /* This is idempotent and threadsafe. */
102   _hb_options.set_relaxed (u.i);
103 }
104
105
106 /* hb_tag_t */
107
108 /**
109  * hb_tag_from_string:
110  * @str: (array length=len) (element-type uint8_t): String to convert
111  * @len: Length of @str, or -1 if it is %NULL-terminated
112  *
113  * Converts a string into an #hb_tag_t. Valid tags
114  * are four characters. Shorter input strings will be
115  * padded with spaces. Longer input strings will be
116  * truncated.
117  *
118  * Return value: The #hb_tag_t corresponding to @str
119  *
120  * Since: 0.9.2
121  **/
122 hb_tag_t
123 hb_tag_from_string (const char *str, int len)
124 {
125   char tag[4];
126   unsigned int i;
127
128   if (!str || !len || !*str)
129     return HB_TAG_NONE;
130
131   if (len < 0 || len > 4)
132     len = 4;
133   for (i = 0; i < (unsigned) len && str[i]; i++)
134     tag[i] = str[i];
135   for (; i < 4; i++)
136     tag[i] = ' ';
137
138   return HB_TAG (tag[0], tag[1], tag[2], tag[3]);
139 }
140
141 /**
142  * hb_tag_to_string:
143  * @tag: #hb_tag_t to convert
144  * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string
145  *
146  * Converts an #hb_tag_t to a string and returns it in @buf.
147  * Strings will be four characters long.
148  *
149  * Since: 0.9.5
150  **/
151 void
152 hb_tag_to_string (hb_tag_t tag, char *buf)
153 {
154   buf[0] = (char) (uint8_t) (tag >> 24);
155   buf[1] = (char) (uint8_t) (tag >> 16);
156   buf[2] = (char) (uint8_t) (tag >>  8);
157   buf[3] = (char) (uint8_t) (tag >>  0);
158 }
159
160
161 /* hb_direction_t */
162
163 const char direction_strings[][4] = {
164   "ltr",
165   "rtl",
166   "ttb",
167   "btt"
168 };
169
170 /**
171  * hb_direction_from_string:
172  * @str: (array length=len) (element-type uint8_t): String to convert
173  * @len: Length of @str, or -1 if it is %NULL-terminated
174  *
175  * Converts a string to an #hb_direction_t.
176  *
177  * Matching is loose and applies only to the first letter. For
178  * examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR.
179  *
180  * Unmatched strings will return #HB_DIRECTION_INVALID.
181  *
182  * Return value: The #hb_direction_t matching @str
183  *
184  * Since: 0.9.2
185  **/
186 hb_direction_t
187 hb_direction_from_string (const char *str, int len)
188 {
189   if (unlikely (!str || !len || !*str))
190     return HB_DIRECTION_INVALID;
191
192   /* Lets match loosely: just match the first letter, such that
193    * all of "ltr", "left-to-right", etc work!
194    */
195   char c = TOLOWER (str[0]);
196   for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
197     if (c == direction_strings[i][0])
198       return (hb_direction_t) (HB_DIRECTION_LTR + i);
199
200   return HB_DIRECTION_INVALID;
201 }
202
203 /**
204  * hb_direction_to_string:
205  * @direction: The #hb_direction_t to convert
206  *
207  * Converts an #hb_direction_t to a string.
208  *
209  * Return value: (transfer none): The string corresponding to @direction
210  *
211  * Since: 0.9.2
212  **/
213 const char *
214 hb_direction_to_string (hb_direction_t direction)
215 {
216   if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
217               < ARRAY_LENGTH (direction_strings)))
218     return direction_strings[direction - HB_DIRECTION_LTR];
219
220   return "invalid";
221 }
222
223
224 /* hb_language_t */
225
226 struct hb_language_impl_t {
227   const char s[1];
228 };
229
230 static const char canon_map[256] = {
231    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
232    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
233    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
234   '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
235    0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
236   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
237    0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
238   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
239 };
240
241 static bool
242 lang_equal (hb_language_t  v1,
243             const void    *v2)
244 {
245   const unsigned char *p1 = (const unsigned char *) v1;
246   const unsigned char *p2 = (const unsigned char *) v2;
247
248   while (*p1 && *p1 == canon_map[*p2]) {
249     p1++;
250     p2++;
251   }
252
253   return *p1 == canon_map[*p2];
254 }
255
256 #if 0
257 static unsigned int
258 lang_hash (const void *key)
259 {
260   const unsigned char *p = key;
261   unsigned int h = 0;
262   while (canon_map[*p])
263     {
264       h = (h << 5) - h + canon_map[*p];
265       p++;
266     }
267
268   return h;
269 }
270 #endif
271
272
273 struct hb_language_item_t {
274
275   struct hb_language_item_t *next;
276   hb_language_t lang;
277
278   bool operator == (const char *s) const
279   { return lang_equal (lang, s); }
280
281   hb_language_item_t & operator = (const char *s)
282   {
283     /* We can't call strdup(), because we allow custom allocators. */
284     size_t len = strlen(s) + 1;
285     lang = (hb_language_t) hb_malloc(len);
286     if (likely (lang))
287     {
288       memcpy((unsigned char *) lang, s, len);
289       for (unsigned char *p = (unsigned char *) lang; *p; p++)
290         *p = canon_map[*p];
291     }
292
293     return *this;
294   }
295
296   void fini () { hb_free ((void *) lang); }
297 };
298
299
300 /* Thread-safe lockfree language list */
301
302 static hb_atomic_ptr_t <hb_language_item_t> langs;
303
304 static inline void
305 free_langs ()
306 {
307 retry:
308   hb_language_item_t *first_lang = langs;
309   if (unlikely (!langs.cmpexch (first_lang, nullptr)))
310     goto retry;
311
312   while (first_lang) {
313     hb_language_item_t *next = first_lang->next;
314     first_lang->fini ();
315     hb_free (first_lang);
316     first_lang = next;
317   }
318 }
319
320 static hb_language_item_t *
321 lang_find_or_insert (const char *key)
322 {
323 retry:
324   hb_language_item_t *first_lang = langs;
325
326   for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
327     if (*lang == key)
328       return lang;
329
330   /* Not found; allocate one. */
331   hb_language_item_t *lang = (hb_language_item_t *) hb_calloc (1, sizeof (hb_language_item_t));
332   if (unlikely (!lang))
333     return nullptr;
334   lang->next = first_lang;
335   *lang = key;
336   if (unlikely (!lang->lang))
337   {
338     hb_free (lang);
339     return nullptr;
340   }
341
342   if (unlikely (!langs.cmpexch (first_lang, lang)))
343   {
344     lang->fini ();
345     hb_free (lang);
346     goto retry;
347   }
348
349   if (!first_lang)
350     hb_atexit (free_langs); /* First person registers atexit() callback. */
351
352   return lang;
353 }
354
355
356 /**
357  * hb_language_from_string:
358  * @str: (array length=len) (element-type uint8_t): a string representing
359  *       a BCP 47 language tag
360  * @len: length of the @str, or -1 if it is %NULL-terminated.
361  *
362  * Converts @str representing a BCP 47 language tag to the corresponding
363  * #hb_language_t.
364  *
365  * Return value: (transfer none):
366  * The #hb_language_t corresponding to the BCP 47 language tag.
367  *
368  * Since: 0.9.2
369  **/
370 hb_language_t
371 hb_language_from_string (const char *str, int len)
372 {
373   if (!str || !len || !*str)
374     return HB_LANGUAGE_INVALID;
375
376   hb_language_item_t *item = nullptr;
377   if (len >= 0)
378   {
379     /* NUL-terminate it. */
380     char strbuf[64];
381     len = hb_min (len, (int) sizeof (strbuf) - 1);
382     memcpy (strbuf, str, len);
383     strbuf[len] = '\0';
384     item = lang_find_or_insert (strbuf);
385   }
386   else
387     item = lang_find_or_insert (str);
388
389   return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
390 }
391
392 /**
393  * hb_language_to_string:
394  * @language: The #hb_language_t to convert
395  *
396  * Converts an #hb_language_t to a string.
397  *
398  * Return value: (transfer none):
399  * A %NULL-terminated string representing the @language. Must not be freed by
400  * the caller.
401  *
402  * Since: 0.9.2
403  **/
404 const char *
405 hb_language_to_string (hb_language_t language)
406 {
407   if (unlikely (!language)) return nullptr;
408
409   return language->s;
410 }
411
412 /**
413  * hb_language_get_default:
414  *
415  * Fetch the default language from current locale.
416  *
417  * <note>Note that the first time this function is called, it calls
418  * "setlocale (LC_CTYPE, nullptr)" to fetch current locale.  The underlying
419  * setlocale function is, in many implementations, NOT threadsafe.  To avoid
420  * problems, call this function once before multiple threads can call it.
421  * This function is only used from hb_buffer_guess_segment_properties() by
422  * HarfBuzz itself.</note>
423  *
424  * Return value: (transfer none): The default language of the locale as
425  * an #hb_language_t
426  *
427  * Since: 0.9.2
428  **/
429 hb_language_t
430 hb_language_get_default ()
431 {
432   static hb_atomic_ptr_t <hb_language_t> default_language;
433
434   hb_language_t language = default_language;
435   if (unlikely (language == HB_LANGUAGE_INVALID))
436   {
437     language = hb_language_from_string (hb_setlocale (LC_CTYPE, nullptr), -1);
438     (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language);
439   }
440
441   return language;
442 }
443
444
445 /* hb_script_t */
446
447 /**
448  * hb_script_from_iso15924_tag:
449  * @tag: an #hb_tag_t representing an ISO 15924 tag.
450  *
451  * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
452  *
453  * Return value:
454  * An #hb_script_t corresponding to the ISO 15924 tag.
455  *
456  * Since: 0.9.2
457  **/
458 hb_script_t
459 hb_script_from_iso15924_tag (hb_tag_t tag)
460 {
461   if (unlikely (tag == HB_TAG_NONE))
462     return HB_SCRIPT_INVALID;
463
464   /* Be lenient, adjust case (one capital letter followed by three small letters) */
465   tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
466
467   switch (tag) {
468
469     /* These graduated from the 'Q' private-area codes, but
470      * the old code is still aliased by Unicode, and the Qaai
471      * one in use by ICU. */
472     case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
473     case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
474
475     /* Script variants from https://unicode.org/iso15924/ */
476     case HB_TAG('A','r','a','n'): return HB_SCRIPT_ARABIC;
477     case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
478     case HB_TAG('G','e','o','k'): return HB_SCRIPT_GEORGIAN;
479     case HB_TAG('H','a','n','s'): return HB_SCRIPT_HAN;
480     case HB_TAG('H','a','n','t'): return HB_SCRIPT_HAN;
481     case HB_TAG('J','a','m','o'): return HB_SCRIPT_HANGUL;
482     case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
483     case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
484     case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
485     case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
486     case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
487   }
488
489   /* If it looks right, just use the tag as a script */
490   if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
491     return (hb_script_t) tag;
492
493   /* Otherwise, return unknown */
494   return HB_SCRIPT_UNKNOWN;
495 }
496
497 /**
498  * hb_script_from_string:
499  * @str: (array length=len) (element-type uint8_t): a string representing an
500  *       ISO 15924 tag.
501  * @len: length of the @str, or -1 if it is %NULL-terminated.
502  *
503  * Converts a string @str representing an ISO 15924 script tag to a
504  * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
505  * hb_script_from_iso15924_tag().
506  *
507  * Return value:
508  * An #hb_script_t corresponding to the ISO 15924 tag.
509  *
510  * Since: 0.9.2
511  **/
512 hb_script_t
513 hb_script_from_string (const char *str, int len)
514 {
515   return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
516 }
517
518 /**
519  * hb_script_to_iso15924_tag:
520  * @script: an #hb_script_t to convert.
521  *
522  * Converts an #hb_script_t to a corresponding ISO 15924 script tag.
523  *
524  * Return value:
525  * An #hb_tag_t representing an ISO 15924 script tag.
526  *
527  * Since: 0.9.2
528  **/
529 hb_tag_t
530 hb_script_to_iso15924_tag (hb_script_t script)
531 {
532   return (hb_tag_t) script;
533 }
534
535 /**
536  * hb_script_get_horizontal_direction:
537  * @script: The #hb_script_t to query
538  *
539  * Fetches the #hb_direction_t of a script when it is
540  * set horizontally. All right-to-left scripts will return
541  * #HB_DIRECTION_RTL. All left-to-right scripts will return
542  * #HB_DIRECTION_LTR.  Scripts that can be written either
543  * horizontally or vertically will return #HB_DIRECTION_INVALID.
544  * Unknown scripts will return #HB_DIRECTION_LTR.
545  *
546  * Return value: The horizontal #hb_direction_t of @script
547  *
548  * Since: 0.9.2
549  **/
550 hb_direction_t
551 hb_script_get_horizontal_direction (hb_script_t script)
552 {
553   /* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
554   switch ((hb_tag_t) script)
555   {
556     /* Unicode-1.1 additions */
557     case HB_SCRIPT_ARABIC:
558     case HB_SCRIPT_HEBREW:
559
560     /* Unicode-3.0 additions */
561     case HB_SCRIPT_SYRIAC:
562     case HB_SCRIPT_THAANA:
563
564     /* Unicode-4.0 additions */
565     case HB_SCRIPT_CYPRIOT:
566
567     /* Unicode-4.1 additions */
568     case HB_SCRIPT_KHAROSHTHI:
569
570     /* Unicode-5.0 additions */
571     case HB_SCRIPT_PHOENICIAN:
572     case HB_SCRIPT_NKO:
573
574     /* Unicode-5.1 additions */
575     case HB_SCRIPT_LYDIAN:
576
577     /* Unicode-5.2 additions */
578     case HB_SCRIPT_AVESTAN:
579     case HB_SCRIPT_IMPERIAL_ARAMAIC:
580     case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
581     case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
582     case HB_SCRIPT_OLD_SOUTH_ARABIAN:
583     case HB_SCRIPT_OLD_TURKIC:
584     case HB_SCRIPT_SAMARITAN:
585
586     /* Unicode-6.0 additions */
587     case HB_SCRIPT_MANDAIC:
588
589     /* Unicode-6.1 additions */
590     case HB_SCRIPT_MEROITIC_CURSIVE:
591     case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
592
593     /* Unicode-7.0 additions */
594     case HB_SCRIPT_MANICHAEAN:
595     case HB_SCRIPT_MENDE_KIKAKUI:
596     case HB_SCRIPT_NABATAEAN:
597     case HB_SCRIPT_OLD_NORTH_ARABIAN:
598     case HB_SCRIPT_PALMYRENE:
599     case HB_SCRIPT_PSALTER_PAHLAVI:
600
601     /* Unicode-8.0 additions */
602     case HB_SCRIPT_HATRAN:
603
604     /* Unicode-9.0 additions */
605     case HB_SCRIPT_ADLAM:
606
607     /* Unicode-11.0 additions */
608     case HB_SCRIPT_HANIFI_ROHINGYA:
609     case HB_SCRIPT_OLD_SOGDIAN:
610     case HB_SCRIPT_SOGDIAN:
611
612     /* Unicode-12.0 additions */
613     case HB_SCRIPT_ELYMAIC:
614
615     /* Unicode-13.0 additions */
616     case HB_SCRIPT_CHORASMIAN:
617     case HB_SCRIPT_YEZIDI:
618
619     /* Unicode-14.0 additions */
620     case HB_SCRIPT_OLD_UYGHUR:
621
622       return HB_DIRECTION_RTL;
623
624
625     /* https://github.com/harfbuzz/harfbuzz/issues/1000 */
626     case HB_SCRIPT_OLD_HUNGARIAN:
627     case HB_SCRIPT_OLD_ITALIC:
628     case HB_SCRIPT_RUNIC:
629
630       return HB_DIRECTION_INVALID;
631   }
632
633   return HB_DIRECTION_LTR;
634 }
635
636
637 /* hb_version */
638
639
640 /**
641  * SECTION:hb-version
642  * @title: hb-version
643  * @short_description: Information about the version of HarfBuzz in use
644  * @include: hb.h
645  *
646  * These functions and macros allow accessing version of the HarfBuzz
647  * library used at compile- as well as run-time, and to direct code
648  * conditionally based on those versions, again, at compile- or run-time.
649  **/
650
651
652 /**
653  * hb_version:
654  * @major: (out): Library major version component
655  * @minor: (out): Library minor version component
656  * @micro: (out): Library micro version component
657  *
658  * Returns library version as three integer components.
659  *
660  * Since: 0.9.2
661  **/
662 void
663 hb_version (unsigned int *major,
664             unsigned int *minor,
665             unsigned int *micro)
666 {
667   *major = HB_VERSION_MAJOR;
668   *minor = HB_VERSION_MINOR;
669   *micro = HB_VERSION_MICRO;
670 }
671
672 /**
673  * hb_version_string:
674  *
675  * Returns library version as a string with three components.
676  *
677  * Return value: Library version string
678  *
679  * Since: 0.9.2
680  **/
681 const char *
682 hb_version_string ()
683 {
684   return HB_VERSION_STRING;
685 }
686
687 /**
688  * hb_version_atleast:
689  * @major: Library major version component
690  * @minor: Library minor version component
691  * @micro: Library micro version component
692  *
693  * Tests the library version against a minimum value,
694  * as three integer components.
695  *
696  * Return value: %true if the library is equal to or greater than
697  * the test value, %false otherwise
698  *
699  * Since: 0.9.30
700  **/
701 hb_bool_t
702 hb_version_atleast (unsigned int major,
703                     unsigned int minor,
704                     unsigned int micro)
705 {
706   return HB_VERSION_ATLEAST (major, minor, micro);
707 }
708
709
710
711 /* hb_feature_t and hb_variation_t */
712
713 static bool
714 parse_space (const char **pp, const char *end)
715 {
716   while (*pp < end && ISSPACE (**pp))
717     (*pp)++;
718   return true;
719 }
720
721 static bool
722 parse_char (const char **pp, const char *end, char c)
723 {
724   parse_space (pp, end);
725
726   if (*pp == end || **pp != c)
727     return false;
728
729   (*pp)++;
730   return true;
731 }
732
733 static bool
734 parse_uint (const char **pp, const char *end, unsigned int *pv)
735 {
736   /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
737    * such that -1 turns into "big number"... */
738   int v;
739   if (unlikely (!hb_parse_int (pp, end, &v))) return false;
740
741   *pv = v;
742   return true;
743 }
744
745 static bool
746 parse_uint32 (const char **pp, const char *end, uint32_t *pv)
747 {
748   /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
749    * such that -1 turns into "big number"... */
750   int v;
751   if (unlikely (!hb_parse_int (pp, end, &v))) return false;
752
753   *pv = v;
754   return true;
755 }
756
757 static bool
758 parse_bool (const char **pp, const char *end, uint32_t *pv)
759 {
760   parse_space (pp, end);
761
762   const char *p = *pp;
763   while (*pp < end && ISALPHA(**pp))
764     (*pp)++;
765
766   /* CSS allows on/off as aliases 1/0. */
767   if (*pp - p == 2
768       && TOLOWER (p[0]) == 'o'
769       && TOLOWER (p[1]) == 'n')
770     *pv = 1;
771   else if (*pp - p == 3
772            && TOLOWER (p[0]) == 'o'
773            && TOLOWER (p[1]) == 'f'
774            && TOLOWER (p[2]) == 'f')
775     *pv = 0;
776   else
777     return false;
778
779   return true;
780 }
781
782 /* hb_feature_t */
783
784 static bool
785 parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
786 {
787   if (parse_char (pp, end, '-'))
788     feature->value = 0;
789   else {
790     parse_char (pp, end, '+');
791     feature->value = 1;
792   }
793
794   return true;
795 }
796
797 static bool
798 parse_tag (const char **pp, const char *end, hb_tag_t *tag)
799 {
800   parse_space (pp, end);
801
802   char quote = 0;
803
804   if (*pp < end && (**pp == '\'' || **pp == '"'))
805   {
806     quote = **pp;
807     (*pp)++;
808   }
809
810   const char *p = *pp;
811   while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
812     (*pp)++;
813
814   if (p == *pp || *pp - p > 4)
815     return false;
816
817   *tag = hb_tag_from_string (p, *pp - p);
818
819   if (quote)
820   {
821     /* CSS expects exactly four bytes.  And we only allow quotations for
822      * CSS compatibility.  So, enforce the length. */
823      if (*pp - p != 4)
824        return false;
825     if (*pp == end || **pp != quote)
826       return false;
827     (*pp)++;
828   }
829
830   return true;
831 }
832
833 static bool
834 parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
835 {
836   parse_space (pp, end);
837
838   bool has_start;
839
840   feature->start = HB_FEATURE_GLOBAL_START;
841   feature->end = HB_FEATURE_GLOBAL_END;
842
843   if (!parse_char (pp, end, '['))
844     return true;
845
846   has_start = parse_uint (pp, end, &feature->start);
847
848   if (parse_char (pp, end, ':') || parse_char (pp, end, ';')) {
849     parse_uint (pp, end, &feature->end);
850   } else {
851     if (has_start)
852       feature->end = feature->start + 1;
853   }
854
855   return parse_char (pp, end, ']');
856 }
857
858 static bool
859 parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
860 {
861   bool had_equal = parse_char (pp, end, '=');
862   bool had_value = parse_uint32 (pp, end, &feature->value) ||
863                    parse_bool (pp, end, &feature->value);
864   /* CSS doesn't use equal-sign between tag and value.
865    * If there was an equal-sign, then there *must* be a value.
866    * A value without an equal-sign is ok, but not required. */
867   return !had_equal || had_value;
868 }
869
870 static bool
871 parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
872 {
873   return parse_feature_value_prefix (pp, end, feature) &&
874          parse_tag (pp, end, &feature->tag) &&
875          parse_feature_indices (pp, end, feature) &&
876          parse_feature_value_postfix (pp, end, feature) &&
877          parse_space (pp, end) &&
878          *pp == end;
879 }
880
881 /**
882  * hb_feature_from_string:
883  * @str: (array length=len) (element-type uint8_t): a string to parse
884  * @len: length of @str, or -1 if string is %NULL terminated
885  * @feature: (out): the #hb_feature_t to initialize with the parsed values
886  *
887  * Parses a string into a #hb_feature_t.
888  *
889  * The format for specifying feature strings follows. All valid CSS
890  * font-feature-settings values other than 'normal' and the global values are
891  * also accepted, though not documented below. CSS string escapes are not
892  * supported.
893  *
894  * The range indices refer to the positions between Unicode characters. The
895  * position before the first character is always 0.
896  *
897  * The format is Python-esque.  Here is how it all works:
898  *
899  * <informaltable pgwide='1' align='left' frame='none'>
900  * <tgroup cols='5'>
901  * <thead>
902  * <row><entry>Syntax</entry>    <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
903  * </thead>
904  * <tbody>
905  * <row><entry>Setting value:</entry></row>
906  * <row><entry>kern</entry>      <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
907  * <row><entry>+kern</entry>     <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
908  * <row><entry>-kern</entry>     <entry>0</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature off</entry></row>
909  * <row><entry>kern=0</entry>    <entry>0</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature off</entry></row>
910  * <row><entry>kern=1</entry>    <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
911  * <row><entry>aalt=2</entry>    <entry>2</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Choose 2nd alternate</entry></row>
912  * <row><entry>Setting index:</entry></row>
913  * <row><entry>kern[]</entry>    <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
914  * <row><entry>kern[:]</entry>   <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
915  * <row><entry>kern[5:]</entry>  <entry>1</entry>     <entry>5</entry>      <entry>∞</entry>   <entry>Turn feature on, partial</entry></row>
916  * <row><entry>kern[:5]</entry>  <entry>1</entry>     <entry>0</entry>      <entry>5</entry>   <entry>Turn feature on, partial</entry></row>
917  * <row><entry>kern[3:5]</entry> <entry>1</entry>     <entry>3</entry>      <entry>5</entry>   <entry>Turn feature on, range</entry></row>
918  * <row><entry>kern[3]</entry>   <entry>1</entry>     <entry>3</entry>      <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
919  * <row><entry>Mixing it all:</entry></row>
920  * <row><entry>aalt[3:5]=2</entry> <entry>2</entry>   <entry>3</entry>      <entry>5</entry>   <entry>Turn 2nd alternate on for range</entry></row>
921  * </tbody>
922  * </tgroup>
923  * </informaltable>
924  *
925  * Return value:
926  * %true if @str is successfully parsed, %false otherwise
927  *
928  * Since: 0.9.5
929  **/
930 hb_bool_t
931 hb_feature_from_string (const char *str, int len,
932                         hb_feature_t *feature)
933 {
934   hb_feature_t feat;
935
936   if (len < 0)
937     len = strlen (str);
938
939   if (likely (parse_one_feature (&str, str + len, &feat)))
940   {
941     if (feature)
942       *feature = feat;
943     return true;
944   }
945
946   if (feature)
947     memset (feature, 0, sizeof (*feature));
948   return false;
949 }
950
951 /**
952  * hb_feature_to_string:
953  * @feature: an #hb_feature_t to convert
954  * @buf: (array length=size) (out): output string
955  * @size: the allocated size of @buf
956  *
957  * Converts a #hb_feature_t into a %NULL-terminated string in the format
958  * understood by hb_feature_from_string(). The client in responsible for
959  * allocating big enough size for @buf, 128 bytes is more than enough.
960  *
961  * Since: 0.9.5
962  **/
963 void
964 hb_feature_to_string (hb_feature_t *feature,
965                       char *buf, unsigned int size)
966 {
967   if (unlikely (!size)) return;
968
969   char s[128];
970   unsigned int len = 0;
971   if (feature->value == 0)
972     s[len++] = '-';
973   hb_tag_to_string (feature->tag, s + len);
974   len += 4;
975   while (len && s[len - 1] == ' ')
976     len--;
977   if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END)
978   {
979     s[len++] = '[';
980     if (feature->start)
981       len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
982     if (feature->end != feature->start + 1) {
983       s[len++] = ':';
984       if (feature->end != HB_FEATURE_GLOBAL_END)
985         len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
986     }
987     s[len++] = ']';
988   }
989   if (feature->value > 1)
990   {
991     s[len++] = '=';
992     len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
993   }
994   assert (len < ARRAY_LENGTH (s));
995   len = hb_min (len, size - 1);
996   memcpy (buf, s, len);
997   buf[len] = '\0';
998 }
999
1000 /* hb_variation_t */
1001
1002 static bool
1003 parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
1004 {
1005   parse_char (pp, end, '='); /* Optional. */
1006   double v;
1007   if (unlikely (!hb_parse_double (pp, end, &v))) return false;
1008
1009   variation->value = v;
1010   return true;
1011 }
1012
1013 static bool
1014 parse_one_variation (const char **pp, const char *end, hb_variation_t *variation)
1015 {
1016   return parse_tag (pp, end, &variation->tag) &&
1017          parse_variation_value (pp, end, variation) &&
1018          parse_space (pp, end) &&
1019          *pp == end;
1020 }
1021
1022 /**
1023  * hb_variation_from_string:
1024  * @str: (array length=len) (element-type uint8_t): a string to parse
1025  * @len: length of @str, or -1 if string is %NULL terminated
1026  * @variation: (out): the #hb_variation_t to initialize with the parsed values
1027  *
1028  * Parses a string into a #hb_variation_t.
1029  *
1030  * The format for specifying variation settings follows. All valid CSS
1031  * font-variation-settings values other than 'normal' and 'inherited' are also
1032  * accepted, though, not documented below.
1033  *
1034  * The format is a tag, optionally followed by an equals sign, followed by a
1035  * number. For example `wght=500`, or `slnt=-7.5`.
1036  *
1037  * Return value:
1038  * %true if @str is successfully parsed, %false otherwise
1039  *
1040  * Since: 1.4.2
1041  */
1042 hb_bool_t
1043 hb_variation_from_string (const char *str, int len,
1044                           hb_variation_t *variation)
1045 {
1046   hb_variation_t var;
1047
1048   if (len < 0)
1049     len = strlen (str);
1050
1051   if (likely (parse_one_variation (&str, str + len, &var)))
1052   {
1053     if (variation)
1054       *variation = var;
1055     return true;
1056   }
1057
1058   if (variation)
1059     memset (variation, 0, sizeof (*variation));
1060   return false;
1061 }
1062
1063 #ifndef HB_NO_SETLOCALE
1064
1065 static inline void free_static_C_locale ();
1066
1067 static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>,
1068                                                            hb_C_locale_lazy_loader_t>
1069 {
1070   static hb_locale_t create ()
1071   {
1072     hb_locale_t l = newlocale (LC_ALL_MASK, "C", NULL);
1073     if (!l)
1074       return l;
1075
1076     hb_atexit (free_static_C_locale);
1077
1078     return l;
1079   }
1080   static void destroy (hb_locale_t l)
1081   {
1082     freelocale (l);
1083   }
1084   static hb_locale_t get_null ()
1085   {
1086     return (hb_locale_t) 0;
1087   }
1088 } static_C_locale;
1089
1090 static inline
1091 void free_static_C_locale ()
1092 {
1093   static_C_locale.free_instance ();
1094 }
1095
1096 static hb_locale_t
1097 get_C_locale ()
1098 {
1099   return static_C_locale.get_unconst ();
1100 }
1101
1102 #endif
1103
1104 /**
1105  * hb_variation_to_string:
1106  * @variation: an #hb_variation_t to convert
1107  * @buf: (array length=size) (out): output string
1108  * @size: the allocated size of @buf
1109  *
1110  * Converts an #hb_variation_t into a %NULL-terminated string in the format
1111  * understood by hb_variation_from_string(). The client in responsible for
1112  * allocating big enough size for @buf, 128 bytes is more than enough.
1113  *
1114  * Since: 1.4.2
1115  */
1116 void
1117 hb_variation_to_string (hb_variation_t *variation,
1118                         char *buf, unsigned int size)
1119 {
1120   if (unlikely (!size)) return;
1121
1122   char s[128];
1123   unsigned int len = 0;
1124   hb_tag_to_string (variation->tag, s + len);
1125   len += 4;
1126   while (len && s[len - 1] == ' ')
1127     len--;
1128   s[len++] = '=';
1129
1130   hb_locale_t oldlocale HB_UNUSED;
1131   oldlocale = hb_uselocale (get_C_locale ());
1132   len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
1133   (void) hb_uselocale (oldlocale);
1134
1135   assert (len < ARRAY_LENGTH (s));
1136   len = hb_min (len, size - 1);
1137   memcpy (buf, s, len);
1138   buf[len] = '\0';
1139 }
1140
1141 /**
1142  * hb_color_get_alpha:
1143  * @color: an #hb_color_t we are interested in its channels.
1144  *
1145  * Fetches the alpha channel of the given @color.
1146  *
1147  * Return value: Alpha channel value
1148  *
1149  * Since: 2.1.0
1150  */
1151 uint8_t
1152 (hb_color_get_alpha) (hb_color_t color)
1153 {
1154   return hb_color_get_alpha (color);
1155 }
1156
1157 /**
1158  * hb_color_get_red:
1159  * @color: an #hb_color_t we are interested in its channels.
1160  *
1161  * Fetches the red channel of the given @color.
1162  *
1163  * Return value: Red channel value
1164  *
1165  * Since: 2.1.0
1166  */
1167 uint8_t
1168 (hb_color_get_red) (hb_color_t color)
1169 {
1170   return hb_color_get_red (color);
1171 }
1172
1173 /**
1174  * hb_color_get_green:
1175  * @color: an #hb_color_t we are interested in its channels.
1176  *
1177  * Fetches the green channel of the given @color.
1178  *
1179  * Return value: Green channel value
1180  *
1181  * Since: 2.1.0
1182  */
1183 uint8_t
1184 (hb_color_get_green) (hb_color_t color)
1185 {
1186   return hb_color_get_green (color);
1187 }
1188
1189 /**
1190  * hb_color_get_blue:
1191  * @color: an #hb_color_t we are interested in its channels.
1192  *
1193  * Fetches the blue channel of the given @color.
1194  *
1195  * Return value: Blue channel value
1196  *
1197  * Since: 2.1.0
1198  */
1199 uint8_t
1200 (hb_color_get_blue) (hb_color_t color)
1201 {
1202   return hb_color_get_blue (color);
1203 }
1204
1205
1206 /* If there is no visibility control, then hb-static.cc will NOT
1207  * define anything.  Instead, we get it to define one set in here
1208  * only, so only libharfbuzz.so defines them, not other libs. */
1209 #ifdef HB_NO_VISIBILITY
1210 #undef HB_NO_VISIBILITY
1211 #include "hb-static.cc"
1212 #define HB_NO_VISIBILITY 1
1213 #endif