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