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