blob: 7266d9b01f4430d621e89f08d829d0802737e8ea [file] [log] [blame]
Behdad Esfahbod83f34672010-05-21 13:43:49 +01001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2009,2010 Red Hat, Inc.
Behdad Esfahbodcad38212012-03-07 17:13:25 -05003 * Copyright © 2011,2012 Google, Inc.
Behdad Esfahbod83f34672010-05-21 13:43:49 +01004 *
5 * This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -040026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod83f34672010-05-21 13:43:49 +010027 */
28
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070029#include "hb.hh"
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070030#include "hb-machinery.hh"
Behdad Esfahbodb8d61832011-05-05 15:14:04 -040031
Behdad Esfahbod91b779e2022-01-28 13:52:15 -070032#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE))
Behdad Esfahbod13643932022-01-12 10:54:28 -070033#define HB_NO_SETLOCALE 1
34#endif
Behdad Esfahbod34fb5522011-05-06 00:04:28 -040035
Behdad Esfahbod13643932022-01-12 10:54:28 -070036#ifndef HB_NO_SETLOCALE
37
38#include <locale.h>
Behdad Esfahboda45a6302022-01-08 15:47:33 -080039#ifdef HAVE_XLOCALE_H
40#include <xlocale.h> // Needed on BSD/OS X for uselocale
41#endif
42
Behdad Esfahbod13643932022-01-12 10:54:28 -070043#ifdef WIN32
Behdad Esfahbod589bea12022-01-15 17:55:10 -070044#define hb_locale_t _locale_t
Behdad Esfahbod13643932022-01-12 10:54:28 -070045#else
Behdad Esfahbod589bea12022-01-15 17:55:10 -070046#define hb_locale_t locale_t
Behdad Esfahbod13643932022-01-12 10:54:28 -070047#endif
Behdad Esfahbodb97e4f72022-01-15 17:47:51 -070048#define hb_setlocale setlocale
49#define hb_uselocale uselocale
Behdad Esfahbod13643932022-01-12 10:54:28 -070050
51#else
52
Behdad Esfahbod13643932022-01-12 10:54:28 -070053#define hb_locale_t void *
Behdad Esfahbodb97e4f72022-01-15 17:47:51 -070054#define hb_setlocale(Category, Locale) "C"
55#define hb_uselocale(Locale) ((hb_locale_t) 0)
Behdad Esfahbod13643932022-01-12 10:54:28 -070056
Ebrahim Byagowi19b8eb02019-06-11 01:33:30 +043057#endif
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040058
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -070059/**
60 * SECTION:hb-common
Behdad Esfahbodcf5fa572018-10-27 04:50:38 -070061 * @title: hb-common
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -070062 * @short_description: Common data types
63 * @include: hb.h
64 *
65 * Common data types used across HarfBuzz are defined here.
66 **/
67
68
Behdad Esfahbodbab02d32013-02-12 15:26:45 -050069/* hb_options_t */
70
Behdad Esfahbod4bc16ac2018-07-31 21:05:51 -070071hb_atomic_int_t _hb_options;
Behdad Esfahbodbab02d32013-02-12 15:26:45 -050072
73void
Ebrahim Byagowie4120082018-12-17 21:31:01 +033074_hb_options_init ()
Behdad Esfahbodbab02d32013-02-12 15:26:45 -050075{
76 hb_options_union_t u;
77 u.i = 0;
Bruce Mitchener8d1e4792018-10-18 22:18:42 +070078 u.opts.initialized = true;
Behdad Esfahbodbab02d32013-02-12 15:26:45 -050079
Behdad Esfahbod38a7a8a2018-10-10 17:44:46 -040080 const char *c = getenv ("HB_OPTIONS");
81 if (c)
82 {
83 while (*c)
84 {
85 const char *p = strchr (c, ':');
86 if (!p)
Ebrahim Byagowia0b4ac42019-08-24 17:57:14 +043087 p = c + strlen (c);
Behdad Esfahbod38a7a8a2018-10-10 17:44:46 -040088
89#define OPTION(name, symbol) \
GaryQianccf14482019-06-24 12:57:13 -070090 if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
Behdad Esfahbod38a7a8a2018-10-10 17:44:46 -040091
92 OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
Behdad Esfahbod38a7a8a2018-10-10 17:44:46 -040093
94#undef OPTION
95
96 c = *p ? p + 1 : p;
97 }
98
99 }
Behdad Esfahbodbab02d32013-02-12 15:26:45 -0500100
101 /* This is idempotent and threadsafe. */
Behdad Esfahbod4bc16ac2018-07-31 21:05:51 -0700102 _hb_options.set_relaxed (u.i);
Behdad Esfahbodbab02d32013-02-12 15:26:45 -0500103}
104
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400105
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400106/* hb_tag_t */
107
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400108/**
109 * hb_tag_from_string:
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100110 * @str: (array length=len) (element-type uint8_t): String to convert
111 * @len: Length of @str, or -1 if it is %NULL-terminated
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400112 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100113 * Converts a string into an #hb_tag_t. Valid tags
114 * are four characters. Shorter input strings will be
115 * padded with spaces. Longer input strings will be
116 * truncated.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400117 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100118 * Return value: The #hb_tag_t corresponding to @str
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400119 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430120 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400121 **/
Behdad Esfahbod83f34672010-05-21 13:43:49 +0100122hb_tag_t
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400123hb_tag_from_string (const char *str, int len)
Behdad Esfahbod83f34672010-05-21 13:43:49 +0100124{
125 char tag[4];
126 unsigned int i;
127
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400128 if (!str || !len || !*str)
Behdad Esfahbod7ff74012011-04-11 13:27:30 -0400129 return HB_TAG_NONE;
130
Behdad Esfahbod4c9fe882011-08-26 09:18:53 +0200131 if (len < 0 || len > 4)
132 len = 4;
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400133 for (i = 0; i < (unsigned) len && str[i]; i++)
134 tag[i] = str[i];
Behdad Esfahbod83f34672010-05-21 13:43:49 +0100135 for (; i < 4; i++)
136 tag[i] = ' ';
137
Behdad Esfahbod8eaff982017-10-31 15:30:06 -0600138 return HB_TAG (tag[0], tag[1], tag[2], tag[3]);
Behdad Esfahbod83f34672010-05-21 13:43:49 +0100139}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400140
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400141/**
142 * hb_tag_to_string:
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100143 * @tag: #hb_tag_t to convert
144 * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400145 *
Behdad Esfahboda45a6302022-01-08 15:47:33 -0800146 * Converts an #hb_tag_t to a string and returns it in @buf.
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100147 * Strings will be four characters long.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400148 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200149 * Since: 0.9.5
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400150 **/
Behdad Esfahbode30ebd22012-09-06 22:09:06 -0400151void
152hb_tag_to_string (hb_tag_t tag, char *buf)
153{
154 buf[0] = (char) (uint8_t) (tag >> 24);
155 buf[1] = (char) (uint8_t) (tag >> 16);
156 buf[2] = (char) (uint8_t) (tag >> 8);
157 buf[3] = (char) (uint8_t) (tag >> 0);
158}
159
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400160
Behdad Esfahbod39a840a2011-04-27 14:48:19 -0400161/* hb_direction_t */
162
Behdad Esfahbodc859cbf2022-06-16 13:55:12 -0600163static const char direction_strings[][4] = {
Behdad Esfahbod39a840a2011-04-27 14:48:19 -0400164 "ltr",
165 "rtl",
166 "ttb",
167 "btt"
168};
169
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400170/**
171 * hb_direction_from_string:
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100172 * @str: (array length=len) (element-type uint8_t): String to convert
173 * @len: Length of @str, or -1 if it is %NULL-terminated
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400174 *
Behdad Esfahboda45a6302022-01-08 15:47:33 -0800175 * Converts a string to an #hb_direction_t.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400176 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100177 * Matching is loose and applies only to the first letter. For
178 * examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR.
Ebrahim Byagowi70d36542018-03-30 05:00:28 +0430179 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100180 * Unmatched strings will return #HB_DIRECTION_INVALID.
Behdad Esfahboda45a6302022-01-08 15:47:33 -0800181 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100182 * Return value: The #hb_direction_t matching @str
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400183 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430184 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400185 **/
Behdad Esfahbod39a840a2011-04-27 14:48:19 -0400186hb_direction_t
Behdad Esfahbod4c9fe882011-08-26 09:18:53 +0200187hb_direction_from_string (const char *str, int len)
Behdad Esfahbod39a840a2011-04-27 14:48:19 -0400188{
Behdad Esfahbod4c9fe882011-08-26 09:18:53 +0200189 if (unlikely (!str || !len || !*str))
Behdad Esfahbod39a840a2011-04-27 14:48:19 -0400190 return HB_DIRECTION_INVALID;
191
192 /* Lets match loosely: just match the first letter, such that
193 * all of "ltr", "left-to-right", etc work!
194 */
195 char c = TOLOWER (str[0]);
196 for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
197 if (c == direction_strings[i][0])
Behdad Esfahbod4bf90f62012-04-12 17:38:23 -0400198 return (hb_direction_t) (HB_DIRECTION_LTR + i);
Behdad Esfahbod39a840a2011-04-27 14:48:19 -0400199
200 return HB_DIRECTION_INVALID;
201}
202
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400203/**
204 * hb_direction_to_string:
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100205 * @direction: The #hb_direction_t to convert
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400206 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100207 * Converts an #hb_direction_t to a string.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400208 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100209 * Return value: (transfer none): The string corresponding to @direction
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400210 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430211 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400212 **/
Behdad Esfahbod39a840a2011-04-27 14:48:19 -0400213const char *
214hb_direction_to_string (hb_direction_t direction)
215{
Behdad Esfahbod4bf90f62012-04-12 17:38:23 -0400216 if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
217 < ARRAY_LENGTH (direction_strings)))
218 return direction_strings[direction - HB_DIRECTION_LTR];
Behdad Esfahbod39a840a2011-04-27 14:48:19 -0400219
220 return "invalid";
221}
222
223
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400224/* hb_language_t */
225
Behdad Esfahbod1bc1cb32012-06-16 15:21:55 -0400226struct hb_language_impl_t {
Behdad Esfahbod3cbdf702011-04-15 12:32:06 -0400227 const char s[1];
228};
229
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400230static const char canon_map[256] = {
231 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0,
234 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
David Corbett018ba462018-11-23 13:21:22 -0500235 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400236 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-',
237 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
238 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
239};
240
Behdad Esfahbodf3b170b2015-04-08 16:26:24 -0700241static bool
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400242lang_equal (hb_language_t v1,
243 const void *v2)
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400244{
Behdad Esfahbodc57d4542011-04-20 18:50:27 -0400245 const unsigned char *p1 = (const unsigned char *) v1;
246 const unsigned char *p2 = (const unsigned char *) v2;
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400247
Chris Petersonaacca372017-04-17 23:25:24 -0700248 while (*p1 && *p1 == canon_map[*p2]) {
249 p1++;
250 p2++;
251 }
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400252
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400253 return *p1 == canon_map[*p2];
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400254}
255
256#if 0
257static unsigned int
258lang_hash (const void *key)
259{
260 const unsigned char *p = key;
261 unsigned int h = 0;
262 while (canon_map[*p])
263 {
264 h = (h << 5) - h + canon_map[*p];
265 p++;
266 }
267
268 return h;
269}
270#endif
271
272
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400273struct hb_language_item_t {
274
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400275 struct hb_language_item_t *next;
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400276 hb_language_t lang;
277
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330278 bool operator == (const char *s) const
279 { return lang_equal (lang, s); }
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400280
Behdad Esfahbodbb48bf52021-07-08 10:53:45 -0600281 hb_language_item_t & operator = (const char *s)
282 {
283 /* We can't call strdup(), because we allow custom allocators. */
Sebastian Rasmussen92e2c4b2017-05-29 12:53:30 -0500284 size_t len = strlen(s) + 1;
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600285 lang = (hb_language_t) hb_malloc(len);
Behdad Esfahbod7dba3062017-06-01 11:44:42 -0400286 if (likely (lang))
287 {
288 memcpy((unsigned char *) lang, s, len);
289 for (unsigned char *p = (unsigned char *) lang; *p; p++)
290 *p = canon_map[*p];
291 }
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400292
293 return *this;
294 }
295
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600296 void fini () { hb_free ((void *) lang); }
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400297};
298
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400299
Behdad Esfahbodbb48bf52021-07-08 10:53:45 -0600300/* Thread-safe lockfree language list */
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400301
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700302static hb_atomic_ptr_t <hb_language_item_t> langs;
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400303
Behdad Esfahboded116322021-09-14 07:09:54 -0400304static inline void
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330305free_langs ()
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400306{
Behdad Esfahbod5aa2c6e2018-03-28 15:33:51 -0700307retry:
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500308 hb_language_item_t *first_lang = langs;
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700309 if (unlikely (!langs.cmpexch (first_lang, nullptr)))
Behdad Esfahbod5aa2c6e2018-03-28 15:33:51 -0700310 goto retry;
311
312 while (first_lang) {
313 hb_language_item_t *next = first_lang->next;
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400314 first_lang->fini ();
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600315 hb_free (first_lang);
Behdad Esfahbod5aa2c6e2018-03-28 15:33:51 -0700316 first_lang = next;
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400317 }
318}
319
320static hb_language_item_t *
321lang_find_or_insert (const char *key)
322{
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400323retry:
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500324 hb_language_item_t *first_lang = langs;
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400325
326 for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
327 if (*lang == key)
328 return lang;
329
330 /* Not found; allocate one. */
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600331 hb_language_item_t *lang = (hb_language_item_t *) hb_calloc (1, sizeof (hb_language_item_t));
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400332 if (unlikely (!lang))
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200333 return nullptr;
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400334 lang->next = first_lang;
335 *lang = key;
Behdad Esfahbod7dba3062017-06-01 11:44:42 -0400336 if (unlikely (!lang->lang))
337 {
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600338 hb_free (lang);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200339 return nullptr;
Behdad Esfahbod7dba3062017-06-01 11:44:42 -0400340 }
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400341
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700342 if (unlikely (!langs.cmpexch (first_lang, lang)))
343 {
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400344 lang->fini ();
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -0600345 hb_free (lang);
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400346 goto retry;
347 }
348
Behdad Esfahbod04aed572012-06-05 18:30:19 -0400349 if (!first_lang)
Behdad Esfahboded116322021-09-14 07:09:54 -0400350 hb_atexit (free_langs); /* First person registers atexit() callback. */
Behdad Esfahbod093171c2012-06-05 18:00:45 -0400351
352 return lang;
353}
354
Behdad Esfahbodb8d61832011-05-05 15:14:04 -0400355
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400356/**
357 * hb_language_from_string:
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400358 * @str: (array length=len) (element-type uint8_t): a string representing
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200359 * a BCP 47 language tag
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400360 * @len: length of the @str, or -1 if it is %NULL-terminated.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400361 *
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200362 * Converts @str representing a BCP 47 language tag to the corresponding
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400363 * #hb_language_t.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400364 *
Khaled Hosny04f89e82015-04-10 17:49:01 +0200365 * Return value: (transfer none):
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200366 * The #hb_language_t corresponding to the BCP 47 language tag.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400367 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430368 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400369 **/
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400370hb_language_t
Behdad Esfahbod4c9fe882011-08-26 09:18:53 +0200371hb_language_from_string (const char *str, int len)
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400372{
Behdad Esfahbod4c9fe882011-08-26 09:18:53 +0200373 if (!str || !len || !*str)
Behdad Esfahbod1a64f6e2011-05-13 22:55:32 -0400374 return HB_LANGUAGE_INVALID;
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400375
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200376 hb_language_item_t *item = nullptr;
Behdad Esfahbod48360ec2013-09-26 16:48:42 -0400377 if (len >= 0)
378 {
Behdad Esfahboddac86022014-06-03 17:57:00 -0400379 /* NUL-terminate it. */
Behdad Esfahbodf3159ba2015-09-29 14:34:56 +0100380 char strbuf[64];
Behdad Esfahbod41248cc2019-05-07 20:54:31 -0700381 len = hb_min (len, (int) sizeof (strbuf) - 1);
Behdad Esfahboddac86022014-06-03 17:57:00 -0400382 memcpy (strbuf, str, len);
Behdad Esfahbod4c9fe882011-08-26 09:18:53 +0200383 strbuf[len] = '\0';
Behdad Esfahbodf3159ba2015-09-29 14:34:56 +0100384 item = lang_find_or_insert (strbuf);
Behdad Esfahbod4c9fe882011-08-26 09:18:53 +0200385 }
Behdad Esfahbodf3159ba2015-09-29 14:34:56 +0100386 else
387 item = lang_find_or_insert (str);
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400388
Behdad Esfahbod1a64f6e2011-05-13 22:55:32 -0400389 return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400390}
391
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400392/**
393 * hb_language_to_string:
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100394 * @language: The #hb_language_t to convert
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400395 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100396 * Converts an #hb_language_t to a string.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400397 *
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400398 * Return value: (transfer none):
399 * A %NULL-terminated string representing the @language. Must not be freed by
400 * the caller.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400401 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430402 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400403 **/
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400404const char *
405hb_language_to_string (hb_language_t language)
406{
Ebrahim Byagowie6909ee2019-09-18 22:12:25 +0430407 if (unlikely (!language)) return nullptr;
Ebrahim Byagowid8af9ee2019-09-18 00:47:55 +0430408
Behdad Esfahbod3cbdf702011-04-15 12:32:06 -0400409 return language->s;
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400410}
411
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400412/**
413 * hb_language_get_default:
414 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100415 * Fetch the default language from current locale.
Ebrahim Byagowi70d36542018-03-30 05:00:28 +0430416 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100417 * <note>Note that the first time this function is called, it calls
Behdad Esfahbodba0f0f12018-09-30 03:49:52 -0400418 * "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying
419 * setlocale function is, in many implementations, NOT threadsafe. To avoid
420 * problems, call this function once before multiple threads can call it.
421 * This function is only used from hb_buffer_guess_segment_properties() by
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100422 * HarfBuzz itself.</note>
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400423 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100424 * Return value: (transfer none): The default language of the locale as
425 * an #hb_language_t
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400426 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430427 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400428 **/
Behdad Esfahbod34fb5522011-05-06 00:04:28 -0400429hb_language_t
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330430hb_language_get_default ()
Behdad Esfahbod34fb5522011-05-06 00:04:28 -0400431{
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700432 static hb_atomic_ptr_t <hb_language_t> default_language;
Behdad Esfahbod34fb5522011-05-06 00:04:28 -0400433
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500434 hb_language_t language = default_language;
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700435 if (unlikely (language == HB_LANGUAGE_INVALID))
436 {
Behdad Esfahbodb97e4f72022-01-15 17:47:51 -0700437 language = hb_language_from_string (hb_setlocale (LC_CTYPE, nullptr), -1);
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700438 (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language);
Behdad Esfahbod34fb5522011-05-06 00:04:28 -0400439 }
440
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700441 return language;
Behdad Esfahbod34fb5522011-05-06 00:04:28 -0400442}
443
Behdad Esfahbod8e4bb3c2011-04-11 17:55:58 -0400444
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400445/* hb_script_t */
446
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400447/**
448 * hb_script_from_iso15924_tag:
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200449 * @tag: an #hb_tag_t representing an ISO 15924 tag.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400450 *
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200451 * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400452 *
Ebrahim Byagowi70d36542018-03-30 05:00:28 +0430453 * Return value:
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200454 * An #hb_script_t corresponding to the ISO 15924 tag.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400455 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430456 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400457 **/
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400458hb_script_t
459hb_script_from_iso15924_tag (hb_tag_t tag)
460{
Behdad Esfahbodf144a8e2011-04-20 02:54:42 -0400461 if (unlikely (tag == HB_TAG_NONE))
462 return HB_SCRIPT_INVALID;
463
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400464 /* Be lenient, adjust case (one capital letter followed by three small letters) */
Behdad Esfahbod76271002014-07-11 14:54:42 -0400465 tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400466
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400467 switch (tag) {
Behdad Esfahbodd02985e2011-05-02 12:35:14 -0400468
469 /* These graduated from the 'Q' private-area codes, but
470 * the old code is still aliased by Unicode, and the Qaai
471 * one in use by ICU. */
472 case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
473 case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
474
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +0430475 /* Script variants from https://unicode.org/iso15924/ */
David Corbett3bd43bd2020-11-16 21:55:02 -0500476 case HB_TAG('A','r','a','n'): return HB_SCRIPT_ARABIC;
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400477 case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
David Corbett3bd43bd2020-11-16 21:55:02 -0500478 case HB_TAG('G','e','o','k'): return HB_SCRIPT_GEORGIAN;
479 case HB_TAG('H','a','n','s'): return HB_SCRIPT_HAN;
480 case HB_TAG('H','a','n','t'): return HB_SCRIPT_HAN;
481 case HB_TAG('J','a','m','o'): return HB_SCRIPT_HANGUL;
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400482 case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
483 case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
484 case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
485 case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
486 case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
487 }
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400488
489 /* If it looks right, just use the tag as a script */
Behdad Esfahbod76271002014-07-11 14:54:42 -0400490 if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400491 return (hb_script_t) tag;
492
493 /* Otherwise, return unknown */
494 return HB_SCRIPT_UNKNOWN;
495}
496
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400497/**
498 * hb_script_from_string:
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400499 * @str: (array length=len) (element-type uint8_t): a string representing an
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200500 * ISO 15924 tag.
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400501 * @len: length of the @str, or -1 if it is %NULL-terminated.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400502 *
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200503 * Converts a string @str representing an ISO 15924 script tag to a
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400504 * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
505 * hb_script_from_iso15924_tag().
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400506 *
Ebrahim Byagowi70d36542018-03-30 05:00:28 +0430507 * Return value:
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200508 * An #hb_script_t corresponding to the ISO 15924 tag.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400509 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430510 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400511 **/
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400512hb_script_t
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400513hb_script_from_string (const char *str, int len)
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400514{
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400515 return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400516}
517
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400518/**
519 * hb_script_to_iso15924_tag:
David Corbett5daeff32019-04-17 09:11:44 -0400520 * @script: an #hb_script_t to convert.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400521 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100522 * Converts an #hb_script_t to a corresponding ISO 15924 script tag.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400523 *
Khaled Hosny8ab797c2015-12-29 17:42:16 +0400524 * Return value:
Evgeniy Reiznerb618e0a2019-12-15 16:26:50 +0200525 * An #hb_tag_t representing an ISO 15924 script tag.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400526 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430527 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400528 **/
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400529hb_tag_t
530hb_script_to_iso15924_tag (hb_script_t script)
531{
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400532 return (hb_tag_t) script;
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400533}
534
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400535/**
536 * hb_script_get_horizontal_direction:
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100537 * @script: The #hb_script_t to query
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400538 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100539 * Fetches the #hb_direction_t of a script when it is
540 * set horizontally. All right-to-left scripts will return
541 * #HB_DIRECTION_RTL. All left-to-right scripts will return
Khaled Hosny8586f152020-12-24 22:23:47 +0200542 * #HB_DIRECTION_LTR. Scripts that can be written either
543 * horizontally or vertically will return #HB_DIRECTION_INVALID.
544 * Unknown scripts will return #HB_DIRECTION_LTR.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400545 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100546 * Return value: The horizontal #hb_direction_t of @script
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400547 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430548 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400549 **/
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400550hb_direction_t
551hb_script_get_horizontal_direction (hb_script_t script)
552{
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +0430553 /* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400554 switch ((hb_tag_t) script)
555 {
Behdad Esfahbodfa2673c2012-03-07 15:52:02 -0500556 /* Unicode-1.1 additions */
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400557 case HB_SCRIPT_ARABIC:
558 case HB_SCRIPT_HEBREW:
Behdad Esfahbodfa2673c2012-03-07 15:52:02 -0500559
560 /* Unicode-3.0 additions */
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400561 case HB_SCRIPT_SYRIAC:
562 case HB_SCRIPT_THAANA:
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400563
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400564 /* Unicode-4.0 additions */
565 case HB_SCRIPT_CYPRIOT:
566
Behdad Esfahbod50e810c2012-03-07 12:49:08 -0500567 /* Unicode-4.1 additions */
568 case HB_SCRIPT_KHAROSHTHI:
569
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400570 /* Unicode-5.0 additions */
571 case HB_SCRIPT_PHOENICIAN:
572 case HB_SCRIPT_NKO:
573
Behdad Esfahbod50e810c2012-03-07 12:49:08 -0500574 /* Unicode-5.1 additions */
575 case HB_SCRIPT_LYDIAN:
576
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400577 /* Unicode-5.2 additions */
578 case HB_SCRIPT_AVESTAN:
579 case HB_SCRIPT_IMPERIAL_ARAMAIC:
580 case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
581 case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
582 case HB_SCRIPT_OLD_SOUTH_ARABIAN:
583 case HB_SCRIPT_OLD_TURKIC:
584 case HB_SCRIPT_SAMARITAN:
585
586 /* Unicode-6.0 additions */
587 case HB_SCRIPT_MANDAIC:
588
Behdad Esfahbodfa2673c2012-03-07 15:52:02 -0500589 /* Unicode-6.1 additions */
590 case HB_SCRIPT_MEROITIC_CURSIVE:
591 case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
592
Behdad Esfahboda4a78992014-04-28 15:06:42 -0700593 /* Unicode-7.0 additions */
594 case HB_SCRIPT_MANICHAEAN:
595 case HB_SCRIPT_MENDE_KIKAKUI:
596 case HB_SCRIPT_NABATAEAN:
597 case HB_SCRIPT_OLD_NORTH_ARABIAN:
598 case HB_SCRIPT_PALMYRENE:
599 case HB_SCRIPT_PSALTER_PAHLAVI:
600
Behdad Esfahbod64a27262015-07-15 01:36:39 +0100601 /* Unicode-8.0 additions */
Cosimo Lupoc8f2a4f2018-01-18 22:49:40 +0100602 case HB_SCRIPT_HATRAN:
Behdad Esfahbod64a27262015-07-15 01:36:39 +0100603
Behdad Esfahbod691086f2016-05-06 12:08:18 +0100604 /* Unicode-9.0 additions */
605 case HB_SCRIPT_ADLAM:
606
Behdad Esfahbod060e6b42018-06-05 17:31:46 -0700607 /* Unicode-11.0 additions */
608 case HB_SCRIPT_HANIFI_ROHINGYA:
609 case HB_SCRIPT_OLD_SOGDIAN:
610 case HB_SCRIPT_SOGDIAN:
611
David Corbett665483c2020-04-01 17:28:12 -0400612 /* Unicode-12.0 additions */
613 case HB_SCRIPT_ELYMAIC:
614
David Corbettfd748fa2020-03-15 15:59:31 -0400615 /* Unicode-13.0 additions */
616 case HB_SCRIPT_CHORASMIAN:
617 case HB_SCRIPT_YEZIDI:
618
David Corbett7b05eec2021-09-14 17:51:11 -0400619 /* Unicode-14.0 additions */
620 case HB_SCRIPT_OLD_UYGHUR:
621
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400622 return HB_DIRECTION_RTL;
Behdad Esfahbodf673cfb2018-05-07 13:58:32 -0700623
624
625 /* https://github.com/harfbuzz/harfbuzz/issues/1000 */
David Corbettd8d1e7d2018-09-17 11:09:51 -0400626 case HB_SCRIPT_OLD_HUNGARIAN:
Behdad Esfahbodf673cfb2018-05-07 13:58:32 -0700627 case HB_SCRIPT_OLD_ITALIC:
David Corbett46d8f0d2018-07-06 15:47:03 -0400628 case HB_SCRIPT_RUNIC:
Behdad Esfahbodf673cfb2018-05-07 13:58:32 -0700629
630 return HB_DIRECTION_INVALID;
Behdad Esfahbod62879ee2011-04-18 23:40:21 -0400631 }
632
633 return HB_DIRECTION_LTR;
Behdad Esfahbod00bec2c2011-04-15 19:16:54 -0400634}
635
636
Behdad Esfahbodc78f4482011-05-05 21:31:04 -0400637/* hb_version */
638
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -0700639
640/**
641 * SECTION:hb-version
Behdad Esfahbodcf5fa572018-10-27 04:50:38 -0700642 * @title: hb-version
Behdad Esfahbod00cf4e52018-10-27 04:07:33 -0700643 * @short_description: Information about the version of HarfBuzz in use
644 * @include: hb.h
645 *
646 * These functions and macros allow accessing version of the HarfBuzz
647 * library used at compile- as well as run-time, and to direct code
648 * conditionally based on those versions, again, at compile- or run-time.
649 **/
650
651
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400652/**
653 * hb_version:
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100654 * @major: (out): Library major version component
655 * @minor: (out): Library minor version component
656 * @micro: (out): Library micro version component
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400657 *
658 * Returns library version as three integer components.
659 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430660 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400661 **/
Behdad Esfahbodc78f4482011-05-05 21:31:04 -0400662void
663hb_version (unsigned int *major,
664 unsigned int *minor,
665 unsigned int *micro)
666{
667 *major = HB_VERSION_MAJOR;
668 *minor = HB_VERSION_MINOR;
669 *micro = HB_VERSION_MICRO;
670}
671
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400672/**
673 * hb_version_string:
674 *
675 * Returns library version as a string with three components.
676 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100677 * Return value: Library version string
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400678 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430679 * Since: 0.9.2
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400680 **/
Behdad Esfahbodc78f4482011-05-05 21:31:04 -0400681const char *
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330682hb_version_string ()
Behdad Esfahbodc78f4482011-05-05 21:31:04 -0400683{
684 return HB_VERSION_STRING;
685}
686
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400687/**
Behdad Esfahbod2b051c62014-06-20 14:09:57 -0400688 * hb_version_atleast:
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100689 * @major: Library major version component
690 * @minor: Library minor version component
691 * @micro: Library micro version component
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400692 *
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100693 * Tests the library version against a minimum value,
694 * as three integer components.
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400695 *
Khaled Hosnya8e72ee2020-12-30 23:08:40 +0200696 * Return value: %true if the library is equal to or greater than
697 * the test value, %false otherwise
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400698 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200699 * Since: 0.9.30
Behdad Esfahbod70303cf2013-09-06 17:35:57 -0400700 **/
Behdad Esfahbodc78f4482011-05-05 21:31:04 -0400701hb_bool_t
Behdad Esfahbod2b051c62014-06-20 14:09:57 -0400702hb_version_atleast (unsigned int major,
703 unsigned int minor,
704 unsigned int micro)
Behdad Esfahbodc78f4482011-05-05 21:31:04 -0400705{
Behdad Esfahbod2b051c62014-06-20 14:09:57 -0400706 return HB_VERSION_ATLEAST (major, minor, micro);
Behdad Esfahbodc78f4482011-05-05 21:31:04 -0400707}
Behdad Esfahbod72364102017-01-20 20:16:53 -0800708
709
Behdad Esfahbodb3c07142017-01-20 20:30:03 -0800710
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -0800711/* hb_feature_t and hb_variation_t */
Behdad Esfahbod72364102017-01-20 20:16:53 -0800712
713static bool
714parse_space (const char **pp, const char *end)
715{
716 while (*pp < end && ISSPACE (**pp))
717 (*pp)++;
718 return true;
719}
720
721static bool
722parse_char (const char **pp, const char *end, char c)
723{
724 parse_space (pp, end);
725
726 if (*pp == end || **pp != c)
727 return false;
728
729 (*pp)++;
730 return true;
731}
732
733static bool
734parse_uint (const char **pp, const char *end, unsigned int *pv)
735{
Ebrahim Byagowib5e68052019-09-03 15:23:40 +0430736 /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
737 * such that -1 turns into "big number"... */
Ebrahim Byagowi43372fb2019-09-03 01:02:40 +0430738 int v;
Ebrahim Byagowib5e68052019-09-03 15:23:40 +0430739 if (unlikely (!hb_parse_int (pp, end, &v))) return false;
Behdad Esfahbod72364102017-01-20 20:16:53 -0800740
741 *pv = v;
Behdad Esfahbod72364102017-01-20 20:16:53 -0800742 return true;
743}
744
745static bool
Ebrahim Byagowi3b0e47c2017-06-19 14:47:09 +0430746parse_uint32 (const char **pp, const char *end, uint32_t *pv)
747{
Ebrahim Byagowib5e68052019-09-03 15:23:40 +0430748 /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
749 * such that -1 turns into "big number"... */
Ebrahim Byagowi43372fb2019-09-03 01:02:40 +0430750 int v;
Ebrahim Byagowib5e68052019-09-03 15:23:40 +0430751 if (unlikely (!hb_parse_int (pp, end, &v))) return false;
Ebrahim Byagowi3b0e47c2017-06-19 14:47:09 +0430752
753 *pv = v;
Behdad Esfahbodb3c07142017-01-20 20:30:03 -0800754 return true;
755}
756
757static bool
Ebrahim Byagowi3b0e47c2017-06-19 14:47:09 +0430758parse_bool (const char **pp, const char *end, uint32_t *pv)
Behdad Esfahbod72364102017-01-20 20:16:53 -0800759{
760 parse_space (pp, end);
761
762 const char *p = *pp;
763 while (*pp < end && ISALPHA(**pp))
764 (*pp)++;
765
766 /* CSS allows on/off as aliases 1/0. */
David Corbett45adc182019-02-18 22:30:40 -0500767 if (*pp - p == 2
768 && TOLOWER (p[0]) == 'o'
769 && TOLOWER (p[1]) == 'n')
Behdad Esfahbod72364102017-01-20 20:16:53 -0800770 *pv = 1;
David Corbett45adc182019-02-18 22:30:40 -0500771 else if (*pp - p == 3
772 && TOLOWER (p[0]) == 'o'
773 && TOLOWER (p[1]) == 'f'
774 && TOLOWER (p[2]) == 'f')
Behdad Esfahbod72364102017-01-20 20:16:53 -0800775 *pv = 0;
776 else
777 return false;
778
779 return true;
780}
781
Behdad Esfahbodb3c07142017-01-20 20:30:03 -0800782/* hb_feature_t */
783
Behdad Esfahbod72364102017-01-20 20:16:53 -0800784static bool
785parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
786{
787 if (parse_char (pp, end, '-'))
788 feature->value = 0;
789 else {
790 parse_char (pp, end, '+');
791 feature->value = 1;
792 }
793
794 return true;
795}
796
797static bool
Behdad Esfahbodb3c07142017-01-20 20:30:03 -0800798parse_tag (const char **pp, const char *end, hb_tag_t *tag)
Behdad Esfahbod72364102017-01-20 20:16:53 -0800799{
800 parse_space (pp, end);
801
802 char quote = 0;
803
804 if (*pp < end && (**pp == '\'' || **pp == '"'))
805 {
806 quote = **pp;
807 (*pp)++;
808 }
809
810 const char *p = *pp;
Martin Hosken39607dc2018-08-09 15:16:32 +0700811 while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
Behdad Esfahbod72364102017-01-20 20:16:53 -0800812 (*pp)++;
813
814 if (p == *pp || *pp - p > 4)
815 return false;
816
Behdad Esfahbodb3c07142017-01-20 20:30:03 -0800817 *tag = hb_tag_from_string (p, *pp - p);
Behdad Esfahbod72364102017-01-20 20:16:53 -0800818
819 if (quote)
820 {
821 /* CSS expects exactly four bytes. And we only allow quotations for
822 * CSS compatibility. So, enforce the length. */
823 if (*pp - p != 4)
824 return false;
825 if (*pp == end || **pp != quote)
826 return false;
827 (*pp)++;
828 }
829
830 return true;
831}
832
833static bool
834parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
835{
836 parse_space (pp, end);
837
838 bool has_start;
839
Behdad Esfahbodbecd84a2018-09-11 01:26:18 +0200840 feature->start = HB_FEATURE_GLOBAL_START;
841 feature->end = HB_FEATURE_GLOBAL_END;
Behdad Esfahbod72364102017-01-20 20:16:53 -0800842
843 if (!parse_char (pp, end, '['))
844 return true;
845
846 has_start = parse_uint (pp, end, &feature->start);
847
Behdad Esfahbod88694362018-10-23 03:07:48 -0700848 if (parse_char (pp, end, ':') || parse_char (pp, end, ';')) {
Behdad Esfahbod72364102017-01-20 20:16:53 -0800849 parse_uint (pp, end, &feature->end);
850 } else {
851 if (has_start)
852 feature->end = feature->start + 1;
853 }
854
855 return parse_char (pp, end, ']');
856}
857
858static bool
859parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
860{
861 bool had_equal = parse_char (pp, end, '=');
Ebrahim Byagowi3b0e47c2017-06-19 14:47:09 +0430862 bool had_value = parse_uint32 (pp, end, &feature->value) ||
Ebrahim Byagowia0b4ac42019-08-24 17:57:14 +0430863 parse_bool (pp, end, &feature->value);
Behdad Esfahbod72364102017-01-20 20:16:53 -0800864 /* CSS doesn't use equal-sign between tag and value.
865 * If there was an equal-sign, then there *must* be a value.
Bruce Mitchener90218fa2018-01-31 20:44:45 +0700866 * A value without an equal-sign is ok, but not required. */
Behdad Esfahbod72364102017-01-20 20:16:53 -0800867 return !had_equal || had_value;
868}
869
Behdad Esfahbod72364102017-01-20 20:16:53 -0800870static bool
871parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
872{
873 return parse_feature_value_prefix (pp, end, feature) &&
Behdad Esfahbodb3c07142017-01-20 20:30:03 -0800874 parse_tag (pp, end, &feature->tag) &&
Behdad Esfahbod72364102017-01-20 20:16:53 -0800875 parse_feature_indices (pp, end, feature) &&
876 parse_feature_value_postfix (pp, end, feature) &&
877 parse_space (pp, end) &&
878 *pp == end;
879}
880
881/**
882 * hb_feature_from_string:
883 * @str: (array length=len) (element-type uint8_t): a string to parse
884 * @len: length of @str, or -1 if string is %NULL terminated
885 * @feature: (out): the #hb_feature_t to initialize with the parsed values
886 *
887 * Parses a string into a #hb_feature_t.
888 *
Khaled Hosny6bd4c082019-02-19 02:23:58 +0200889 * The format for specifying feature strings follows. All valid CSS
David Corbett45adc182019-02-18 22:30:40 -0500890 * font-feature-settings values other than 'normal' and the global values are
891 * also accepted, though not documented below. CSS string escapes are not
892 * supported.
Khaled Hosny6bd4c082019-02-19 02:23:58 +0200893 *
894 * The range indices refer to the positions between Unicode characters. The
895 * position before the first character is always 0.
896 *
897 * The format is Python-esque. Here is how it all works:
898 *
899 * <informaltable pgwide='1' align='left' frame='none'>
900 * <tgroup cols='5'>
901 * <thead>
902 * <row><entry>Syntax</entry> <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
903 * </thead>
904 * <tbody>
905 * <row><entry>Setting value:</entry></row>
906 * <row><entry>kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
907 * <row><entry>+kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
908 * <row><entry>-kern</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row>
909 * <row><entry>kern=0</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row>
910 * <row><entry>kern=1</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
911 * <row><entry>aalt=2</entry> <entry>2</entry> <entry>0</entry> <entry>∞</entry> <entry>Choose 2nd alternate</entry></row>
912 * <row><entry>Setting index:</entry></row>
913 * <row><entry>kern[]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
914 * <row><entry>kern[:]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
915 * <row><entry>kern[5:]</entry> <entry>1</entry> <entry>5</entry> <entry>∞</entry> <entry>Turn feature on, partial</entry></row>
916 * <row><entry>kern[:5]</entry> <entry>1</entry> <entry>0</entry> <entry>5</entry> <entry>Turn feature on, partial</entry></row>
917 * <row><entry>kern[3:5]</entry> <entry>1</entry> <entry>3</entry> <entry>5</entry> <entry>Turn feature on, range</entry></row>
918 * <row><entry>kern[3]</entry> <entry>1</entry> <entry>3</entry> <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
919 * <row><entry>Mixing it all:</entry></row>
920 * <row><entry>aalt[3:5]=2</entry> <entry>2</entry> <entry>3</entry> <entry>5</entry> <entry>Turn 2nd alternate on for range</entry></row>
921 * </tbody>
922 * </tgroup>
923 * </informaltable>
Behdad Esfahbod72364102017-01-20 20:16:53 -0800924 *
925 * Return value:
Nathan Willis4cdb12a2019-04-21 20:31:09 +0100926 * %true if @str is successfully parsed, %false otherwise
Behdad Esfahbod72364102017-01-20 20:16:53 -0800927 *
928 * Since: 0.9.5
929 **/
930hb_bool_t
931hb_feature_from_string (const char *str, int len,
932 hb_feature_t *feature)
933{
934 hb_feature_t feat;
935
936 if (len < 0)
937 len = strlen (str);
938
939 if (likely (parse_one_feature (&str, str + len, &feat)))
940 {
941 if (feature)
942 *feature = feat;
943 return true;
944 }
945
946 if (feature)
947 memset (feature, 0, sizeof (*feature));
948 return false;
949}
950
951/**
952 * hb_feature_to_string:
953 * @feature: an #hb_feature_t to convert
954 * @buf: (array length=size) (out): output string
955 * @size: the allocated size of @buf
956 *
957 * Converts a #hb_feature_t into a %NULL-terminated string in the format
958 * understood by hb_feature_from_string(). The client in responsible for
959 * allocating big enough size for @buf, 128 bytes is more than enough.
960 *
961 * Since: 0.9.5
962 **/
963void
964hb_feature_to_string (hb_feature_t *feature,
965 char *buf, unsigned int size)
966{
967 if (unlikely (!size)) return;
968
969 char s[128];
970 unsigned int len = 0;
971 if (feature->value == 0)
972 s[len++] = '-';
973 hb_tag_to_string (feature->tag, s + len);
974 len += 4;
975 while (len && s[len - 1] == ' ')
976 len--;
Evgeniy Reiznerb79ceac2019-12-15 16:50:01 +0200977 if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END)
Behdad Esfahbod72364102017-01-20 20:16:53 -0800978 {
979 s[len++] = '[';
980 if (feature->start)
Behdad Esfahbod41248cc2019-05-07 20:54:31 -0700981 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
Behdad Esfahbod72364102017-01-20 20:16:53 -0800982 if (feature->end != feature->start + 1) {
983 s[len++] = ':';
Evgeniy Reiznerb79ceac2019-12-15 16:50:01 +0200984 if (feature->end != HB_FEATURE_GLOBAL_END)
Behdad Esfahbod41248cc2019-05-07 20:54:31 -0700985 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
Behdad Esfahbod72364102017-01-20 20:16:53 -0800986 }
987 s[len++] = ']';
988 }
989 if (feature->value > 1)
990 {
991 s[len++] = '=';
Behdad Esfahbod41248cc2019-05-07 20:54:31 -0700992 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
Behdad Esfahbod72364102017-01-20 20:16:53 -0800993 }
994 assert (len < ARRAY_LENGTH (s));
Behdad Esfahbod41248cc2019-05-07 20:54:31 -0700995 len = hb_min (len, size - 1);
Behdad Esfahbod72364102017-01-20 20:16:53 -0800996 memcpy (buf, s, len);
997 buf[len] = '\0';
998}
Behdad Esfahbodb3c07142017-01-20 20:30:03 -0800999
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001000/* hb_variation_t */
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001001
1002static bool
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001003parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001004{
1005 parse_char (pp, end, '='); /* Optional. */
Ebrahim Byagowi57f88e12019-09-04 01:20:50 +04301006 double v;
1007 if (unlikely (!hb_parse_double (pp, end, &v))) return false;
1008
1009 variation->value = v;
1010 return true;
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001011}
1012
1013static bool
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001014parse_one_variation (const char **pp, const char *end, hb_variation_t *variation)
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001015{
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001016 return parse_tag (pp, end, &variation->tag) &&
1017 parse_variation_value (pp, end, variation) &&
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001018 parse_space (pp, end) &&
1019 *pp == end;
1020}
1021
Behdad Esfahbodd2f249e2017-01-22 17:42:33 -08001022/**
1023 * hb_variation_from_string:
Khaled Hosny9b602e82020-12-30 23:28:54 +02001024 * @str: (array length=len) (element-type uint8_t): a string to parse
1025 * @len: length of @str, or -1 if string is %NULL terminated
1026 * @variation: (out): the #hb_variation_t to initialize with the parsed values
1027 *
1028 * Parses a string into a #hb_variation_t.
1029 *
1030 * The format for specifying variation settings follows. All valid CSS
1031 * font-variation-settings values other than 'normal' and 'inherited' are also
1032 * accepted, though, not documented below.
1033 *
1034 * The format is a tag, optionally followed by an equals sign, followed by a
1035 * number. For example `wght=500`, or `slnt=-7.5`.
1036 *
1037 * Return value:
1038 * %true if @str is successfully parsed, %false otherwise
Behdad Esfahbodd2f249e2017-01-22 17:42:33 -08001039 *
1040 * Since: 1.4.2
1041 */
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001042hb_bool_t
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001043hb_variation_from_string (const char *str, int len,
1044 hb_variation_t *variation)
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001045{
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001046 hb_variation_t var;
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001047
1048 if (len < 0)
1049 len = strlen (str);
1050
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001051 if (likely (parse_one_variation (&str, str + len, &var)))
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001052 {
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001053 if (variation)
1054 *variation = var;
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001055 return true;
1056 }
1057
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001058 if (variation)
1059 memset (variation, 0, sizeof (*variation));
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001060 return false;
1061}
1062
Behdad Esfahbod13643932022-01-12 10:54:28 -07001063#ifndef HB_NO_SETLOCALE
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001064
1065static inline void free_static_C_locale ();
1066
Behdad Esfahbod13643932022-01-12 10:54:28 -07001067static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>,
Behdad Esfahbod68937232022-02-11 13:16:25 -06001068 hb_C_locale_lazy_loader_t>
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001069{
Behdad Esfahbod13643932022-01-12 10:54:28 -07001070 static hb_locale_t create ()
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001071 {
Behdad Esfahbod13643932022-01-12 10:54:28 -07001072 hb_locale_t l = newlocale (LC_ALL_MASK, "C", NULL);
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001073 if (!l)
1074 return l;
1075
1076 hb_atexit (free_static_C_locale);
1077
1078 return l;
1079 }
Behdad Esfahbod13643932022-01-12 10:54:28 -07001080 static void destroy (hb_locale_t l)
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001081 {
1082 freelocale (l);
1083 }
Behdad Esfahbod13643932022-01-12 10:54:28 -07001084 static hb_locale_t get_null ()
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001085 {
Behdad Esfahbod13643932022-01-12 10:54:28 -07001086 return (hb_locale_t) 0;
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001087 }
1088} static_C_locale;
1089
1090static inline
1091void free_static_C_locale ()
1092{
1093 static_C_locale.free_instance ();
1094}
1095
Behdad Esfahbod13643932022-01-12 10:54:28 -07001096static hb_locale_t
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001097get_C_locale ()
1098{
1099 return static_C_locale.get_unconst ();
1100}
1101
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001102#endif
1103
Behdad Esfahbodd2f249e2017-01-22 17:42:33 -08001104/**
1105 * hb_variation_to_string:
Khaled Hosny9b602e82020-12-30 23:28:54 +02001106 * @variation: an #hb_variation_t to convert
1107 * @buf: (array length=size) (out): output string
1108 * @size: the allocated size of @buf
1109 *
1110 * Converts an #hb_variation_t into a %NULL-terminated string in the format
1111 * understood by hb_variation_from_string(). The client in responsible for
1112 * allocating big enough size for @buf, 128 bytes is more than enough.
Behdad Esfahbodd2f249e2017-01-22 17:42:33 -08001113 *
1114 * Since: 1.4.2
1115 */
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001116void
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001117hb_variation_to_string (hb_variation_t *variation,
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001118 char *buf, unsigned int size)
1119{
1120 if (unlikely (!size)) return;
1121
1122 char s[128];
1123 unsigned int len = 0;
Behdad Esfahbodbb1e1922017-01-21 17:41:37 -08001124 hb_tag_to_string (variation->tag, s + len);
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001125 len += 4;
1126 while (len && s[len - 1] == ' ')
1127 len--;
1128 s[len++] = '=';
Behdad Esfahboda45a6302022-01-08 15:47:33 -08001129
Behdad Esfahbod13643932022-01-12 10:54:28 -07001130 hb_locale_t oldlocale HB_UNUSED;
Behdad Esfahbodb97e4f72022-01-15 17:47:51 -07001131 oldlocale = hb_uselocale (get_C_locale ());
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001132 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
Behdad Esfahbodb97e4f72022-01-15 17:47:51 -07001133 (void) hb_uselocale (oldlocale);
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001134
1135 assert (len < ARRAY_LENGTH (s));
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001136 len = hb_min (len, size - 1);
Behdad Esfahbodb3c07142017-01-20 20:30:03 -08001137 memcpy (buf, s, len);
1138 buf[len] = '\0';
1139}
Behdad Esfahbode22a48a2018-07-23 13:24:26 -07001140
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001141/**
1142 * hb_color_get_alpha:
Khaled Hosny9b602e82020-12-30 23:28:54 +02001143 * @color: an #hb_color_t we are interested in its channels.
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001144 *
Khaled Hosny4bfa0b32020-12-31 16:30:05 +02001145 * Fetches the alpha channel of the given @color.
1146 *
1147 * Return value: Alpha channel value
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001148 *
Behdad Esfahbod1da08912019-05-24 15:41:34 -04001149 * Since: 2.1.0
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001150 */
1151uint8_t
1152(hb_color_get_alpha) (hb_color_t color)
1153{
1154 return hb_color_get_alpha (color);
1155}
1156
1157/**
1158 * hb_color_get_red:
Khaled Hosny9b602e82020-12-30 23:28:54 +02001159 * @color: an #hb_color_t we are interested in its channels.
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001160 *
Khaled Hosny4bfa0b32020-12-31 16:30:05 +02001161 * Fetches the red channel of the given @color.
1162 *
1163 * Return value: Red channel value
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001164 *
Behdad Esfahbod1da08912019-05-24 15:41:34 -04001165 * Since: 2.1.0
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001166 */
1167uint8_t
1168(hb_color_get_red) (hb_color_t color)
1169{
1170 return hb_color_get_red (color);
1171}
1172
1173/**
1174 * hb_color_get_green:
Khaled Hosny9b602e82020-12-30 23:28:54 +02001175 * @color: an #hb_color_t we are interested in its channels.
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001176 *
Khaled Hosny4bfa0b32020-12-31 16:30:05 +02001177 * Fetches the green channel of the given @color.
1178 *
1179 * Return value: Green channel value
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001180 *
Behdad Esfahbod1da08912019-05-24 15:41:34 -04001181 * Since: 2.1.0
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001182 */
1183uint8_t
1184(hb_color_get_green) (hb_color_t color)
1185{
1186 return hb_color_get_green (color);
1187}
1188
1189/**
1190 * hb_color_get_blue:
Khaled Hosny9b602e82020-12-30 23:28:54 +02001191 * @color: an #hb_color_t we are interested in its channels.
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001192 *
Khaled Hosny4bfa0b32020-12-31 16:30:05 +02001193 * Fetches the blue channel of the given @color.
1194 *
1195 * Return value: Blue channel value
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001196 *
Behdad Esfahbod1da08912019-05-24 15:41:34 -04001197 * Since: 2.1.0
Ebrahim Byagowi9542bdd2019-04-29 14:52:28 -07001198 */
1199uint8_t
1200(hb_color_get_blue) (hb_color_t color)
1201{
1202 return hb_color_get_blue (color);
1203}
1204
1205
Behdad Esfahbode22a48a2018-07-23 13:24:26 -07001206/* If there is no visibility control, then hb-static.cc will NOT
1207 * define anything. Instead, we get it to define one set in here
1208 * only, so only libharfbuzz.so defines them, not other libs. */
1209#ifdef HB_NO_VISIBILITY
1210#undef HB_NO_VISIBILITY
1211#include "hb-static.cc"
1212#define HB_NO_VISIBILITY 1
1213#endif