2 * Copyright © 2009,2010 Red Hat, Inc.
3 * Copyright © 2011,2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
30 #include "hb-machinery.hh"
32 #if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE))
33 #define HB_NO_SETLOCALE 1
36 #ifndef HB_NO_SETLOCALE
40 #include <xlocale.h> // Needed on BSD/OS X for uselocale
44 #define hb_locale_t _locale_t
46 #define hb_locale_t locale_t
48 #define hb_setlocale setlocale
49 #define hb_uselocale uselocale
53 #define hb_locale_t void *
54 #define hb_setlocale(Category, Locale) "C"
55 #define hb_uselocale(Locale) ((hb_locale_t) 0)
62 * @short_description: Common data types
65 * Common data types used across HarfBuzz are defined here.
71 hb_atomic_int_t _hb_options;
78 u.opts.initialized = true;
80 const char *c = getenv ("HB_OPTIONS");
85 const char *p = strchr (c, ':');
89 #define OPTION(name, symbol) \
90 if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
92 OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
101 /* This is idempotent and threadsafe. */
102 _hb_options.set_relaxed (u.i);
109 * hb_tag_from_string:
110 * @str: (array length=len) (element-type uint8_t): String to convert
111 * @len: Length of @str, or -1 if it is %NULL-terminated
113 * Converts a string into an #hb_tag_t. Valid tags
114 * are four characters. Shorter input strings will be
115 * padded with spaces. Longer input strings will be
118 * Return value: The #hb_tag_t corresponding to @str
123 hb_tag_from_string (const char *str, int len)
128 if (!str || !len || !*str)
131 if (len < 0 || len > 4)
133 for (i = 0; i < (unsigned) len && str[i]; i++)
138 return HB_TAG (tag[0], tag[1], tag[2], tag[3]);
143 * @tag: #hb_tag_t to convert
144 * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string
146 * Converts an #hb_tag_t to a string and returns it in @buf.
147 * Strings will be four characters long.
152 hb_tag_to_string (hb_tag_t tag, char *buf)
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);
163 const char direction_strings[][4] = {
171 * hb_direction_from_string:
172 * @str: (array length=len) (element-type uint8_t): String to convert
173 * @len: Length of @str, or -1 if it is %NULL-terminated
175 * Converts a string to an #hb_direction_t.
177 * Matching is loose and applies only to the first letter. For
178 * examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR.
180 * Unmatched strings will return #HB_DIRECTION_INVALID.
182 * Return value: The #hb_direction_t matching @str
187 hb_direction_from_string (const char *str, int len)
189 if (unlikely (!str || !len || !*str))
190 return HB_DIRECTION_INVALID;
192 /* Lets match loosely: just match the first letter, such that
193 * all of "ltr", "left-to-right", etc work!
195 char c = TOLOWER (str[0]);
196 for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
197 if (c == direction_strings[i][0])
198 return (hb_direction_t) (HB_DIRECTION_LTR + i);
200 return HB_DIRECTION_INVALID;
204 * hb_direction_to_string:
205 * @direction: The #hb_direction_t to convert
207 * Converts an #hb_direction_t to a string.
209 * Return value: (transfer none): The string corresponding to @direction
214 hb_direction_to_string (hb_direction_t direction)
216 if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
217 < ARRAY_LENGTH (direction_strings)))
218 return direction_strings[direction - HB_DIRECTION_LTR];
226 struct hb_language_impl_t {
230 static const char canon_map[256] = {
231 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0,
234 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
235 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
236 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-',
237 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
238 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
242 lang_equal (hb_language_t v1,
245 const unsigned char *p1 = (const unsigned char *) v1;
246 const unsigned char *p2 = (const unsigned char *) v2;
248 while (*p1 && *p1 == canon_map[*p2]) {
253 return *p1 == canon_map[*p2];
258 lang_hash (const void *key)
260 const unsigned char *p = key;
262 while (canon_map[*p])
264 h = (h << 5) - h + canon_map[*p];
273 struct hb_language_item_t {
275 struct hb_language_item_t *next;
278 bool operator == (const char *s) const
279 { return lang_equal (lang, s); }
281 hb_language_item_t & operator = (const char *s)
283 /* We can't call strdup(), because we allow custom allocators. */
284 size_t len = strlen(s) + 1;
285 lang = (hb_language_t) hb_malloc(len);
288 memcpy((unsigned char *) lang, s, len);
289 for (unsigned char *p = (unsigned char *) lang; *p; p++)
296 void fini () { hb_free ((void *) lang); }
300 /* Thread-safe lockfree language list */
302 static hb_atomic_ptr_t <hb_language_item_t> langs;
308 hb_language_item_t *first_lang = langs;
309 if (unlikely (!langs.cmpexch (first_lang, nullptr)))
313 hb_language_item_t *next = first_lang->next;
315 hb_free (first_lang);
320 static hb_language_item_t *
321 lang_find_or_insert (const char *key)
324 hb_language_item_t *first_lang = langs;
326 for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
330 /* Not found; allocate one. */
331 hb_language_item_t *lang = (hb_language_item_t *) hb_calloc (1, sizeof (hb_language_item_t));
332 if (unlikely (!lang))
334 lang->next = first_lang;
336 if (unlikely (!lang->lang))
342 if (unlikely (!langs.cmpexch (first_lang, lang)))
350 hb_atexit (free_langs); /* First person registers atexit() callback. */
357 * hb_language_from_string:
358 * @str: (array length=len) (element-type uint8_t): a string representing
359 * a BCP 47 language tag
360 * @len: length of the @str, or -1 if it is %NULL-terminated.
362 * Converts @str representing a BCP 47 language tag to the corresponding
365 * Return value: (transfer none):
366 * The #hb_language_t corresponding to the BCP 47 language tag.
371 hb_language_from_string (const char *str, int len)
373 if (!str || !len || !*str)
374 return HB_LANGUAGE_INVALID;
376 hb_language_item_t *item = nullptr;
379 /* NUL-terminate it. */
381 len = hb_min (len, (int) sizeof (strbuf) - 1);
382 memcpy (strbuf, str, len);
384 item = lang_find_or_insert (strbuf);
387 item = lang_find_or_insert (str);
389 return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
393 * hb_language_to_string:
394 * @language: The #hb_language_t to convert
396 * Converts an #hb_language_t to a string.
398 * Return value: (transfer none):
399 * A %NULL-terminated string representing the @language. Must not be freed by
405 hb_language_to_string (hb_language_t language)
407 if (unlikely (!language)) return nullptr;
413 * hb_language_get_default:
415 * Fetch the default language from current locale.
417 * <note>Note that the first time this function is called, it calls
418 * "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying
419 * setlocale function is, in many implementations, NOT threadsafe. To avoid
420 * problems, call this function once before multiple threads can call it.
421 * This function is only used from hb_buffer_guess_segment_properties() by
422 * HarfBuzz itself.</note>
424 * Return value: (transfer none): The default language of the locale as
430 hb_language_get_default ()
432 static hb_atomic_ptr_t <hb_language_t> default_language;
434 hb_language_t language = default_language;
435 if (unlikely (language == HB_LANGUAGE_INVALID))
437 language = hb_language_from_string (hb_setlocale (LC_CTYPE, nullptr), -1);
438 (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language);
448 * hb_script_from_iso15924_tag:
449 * @tag: an #hb_tag_t representing an ISO 15924 tag.
451 * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
454 * An #hb_script_t corresponding to the ISO 15924 tag.
459 hb_script_from_iso15924_tag (hb_tag_t tag)
461 if (unlikely (tag == HB_TAG_NONE))
462 return HB_SCRIPT_INVALID;
464 /* Be lenient, adjust case (one capital letter followed by three small letters) */
465 tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
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;
475 /* Script variants from https://unicode.org/iso15924/ */
476 case HB_TAG('A','r','a','n'): return HB_SCRIPT_ARABIC;
477 case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
478 case HB_TAG('G','e','o','k'): return HB_SCRIPT_GEORGIAN;
479 case HB_TAG('H','a','n','s'): return HB_SCRIPT_HAN;
480 case HB_TAG('H','a','n','t'): return HB_SCRIPT_HAN;
481 case HB_TAG('J','a','m','o'): return HB_SCRIPT_HANGUL;
482 case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
483 case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
484 case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
485 case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
486 case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
489 /* If it looks right, just use the tag as a script */
490 if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
491 return (hb_script_t) tag;
493 /* Otherwise, return unknown */
494 return HB_SCRIPT_UNKNOWN;
498 * hb_script_from_string:
499 * @str: (array length=len) (element-type uint8_t): a string representing an
501 * @len: length of the @str, or -1 if it is %NULL-terminated.
503 * Converts a string @str representing an ISO 15924 script tag to a
504 * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
505 * hb_script_from_iso15924_tag().
508 * An #hb_script_t corresponding to the ISO 15924 tag.
513 hb_script_from_string (const char *str, int len)
515 return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
519 * hb_script_to_iso15924_tag:
520 * @script: an #hb_script_t to convert.
522 * Converts an #hb_script_t to a corresponding ISO 15924 script tag.
525 * An #hb_tag_t representing an ISO 15924 script tag.
530 hb_script_to_iso15924_tag (hb_script_t script)
532 return (hb_tag_t) script;
536 * hb_script_get_horizontal_direction:
537 * @script: The #hb_script_t to query
539 * Fetches the #hb_direction_t of a script when it is
540 * set horizontally. All right-to-left scripts will return
541 * #HB_DIRECTION_RTL. All left-to-right scripts will return
542 * #HB_DIRECTION_LTR. Scripts that can be written either
543 * horizontally or vertically will return #HB_DIRECTION_INVALID.
544 * Unknown scripts will return #HB_DIRECTION_LTR.
546 * Return value: The horizontal #hb_direction_t of @script
551 hb_script_get_horizontal_direction (hb_script_t script)
553 /* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
554 switch ((hb_tag_t) script)
556 /* Unicode-1.1 additions */
557 case HB_SCRIPT_ARABIC:
558 case HB_SCRIPT_HEBREW:
560 /* Unicode-3.0 additions */
561 case HB_SCRIPT_SYRIAC:
562 case HB_SCRIPT_THAANA:
564 /* Unicode-4.0 additions */
565 case HB_SCRIPT_CYPRIOT:
567 /* Unicode-4.1 additions */
568 case HB_SCRIPT_KHAROSHTHI:
570 /* Unicode-5.0 additions */
571 case HB_SCRIPT_PHOENICIAN:
574 /* Unicode-5.1 additions */
575 case HB_SCRIPT_LYDIAN:
577 /* Unicode-5.2 additions */
578 case HB_SCRIPT_AVESTAN:
579 case HB_SCRIPT_IMPERIAL_ARAMAIC:
580 case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
581 case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
582 case HB_SCRIPT_OLD_SOUTH_ARABIAN:
583 case HB_SCRIPT_OLD_TURKIC:
584 case HB_SCRIPT_SAMARITAN:
586 /* Unicode-6.0 additions */
587 case HB_SCRIPT_MANDAIC:
589 /* Unicode-6.1 additions */
590 case HB_SCRIPT_MEROITIC_CURSIVE:
591 case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
593 /* Unicode-7.0 additions */
594 case HB_SCRIPT_MANICHAEAN:
595 case HB_SCRIPT_MENDE_KIKAKUI:
596 case HB_SCRIPT_NABATAEAN:
597 case HB_SCRIPT_OLD_NORTH_ARABIAN:
598 case HB_SCRIPT_PALMYRENE:
599 case HB_SCRIPT_PSALTER_PAHLAVI:
601 /* Unicode-8.0 additions */
602 case HB_SCRIPT_HATRAN:
604 /* Unicode-9.0 additions */
605 case HB_SCRIPT_ADLAM:
607 /* Unicode-11.0 additions */
608 case HB_SCRIPT_HANIFI_ROHINGYA:
609 case HB_SCRIPT_OLD_SOGDIAN:
610 case HB_SCRIPT_SOGDIAN:
612 /* Unicode-12.0 additions */
613 case HB_SCRIPT_ELYMAIC:
615 /* Unicode-13.0 additions */
616 case HB_SCRIPT_CHORASMIAN:
617 case HB_SCRIPT_YEZIDI:
619 /* Unicode-14.0 additions */
620 case HB_SCRIPT_OLD_UYGHUR:
622 return HB_DIRECTION_RTL;
625 /* https://github.com/harfbuzz/harfbuzz/issues/1000 */
626 case HB_SCRIPT_OLD_HUNGARIAN:
627 case HB_SCRIPT_OLD_ITALIC:
628 case HB_SCRIPT_RUNIC:
630 return HB_DIRECTION_INVALID;
633 return HB_DIRECTION_LTR;
643 * @short_description: Information about the version of HarfBuzz in use
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.
654 * @major: (out): Library major version component
655 * @minor: (out): Library minor version component
656 * @micro: (out): Library micro version component
658 * Returns library version as three integer components.
663 hb_version (unsigned int *major,
667 *major = HB_VERSION_MAJOR;
668 *minor = HB_VERSION_MINOR;
669 *micro = HB_VERSION_MICRO;
675 * Returns library version as a string with three components.
677 * Return value: Library version string
684 return HB_VERSION_STRING;
688 * hb_version_atleast:
689 * @major: Library major version component
690 * @minor: Library minor version component
691 * @micro: Library micro version component
693 * Tests the library version against a minimum value,
694 * as three integer components.
696 * Return value: %true if the library is equal to or greater than
697 * the test value, %false otherwise
702 hb_version_atleast (unsigned int major,
706 return HB_VERSION_ATLEAST (major, minor, micro);
711 /* hb_feature_t and hb_variation_t */
714 parse_space (const char **pp, const char *end)
716 while (*pp < end && ISSPACE (**pp))
722 parse_char (const char **pp, const char *end, char c)
724 parse_space (pp, end);
726 if (*pp == end || **pp != c)
734 parse_uint (const char **pp, const char *end, unsigned int *pv)
736 /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
737 * such that -1 turns into "big number"... */
739 if (unlikely (!hb_parse_int (pp, end, &v))) return false;
746 parse_uint32 (const char **pp, const char *end, uint32_t *pv)
748 /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
749 * such that -1 turns into "big number"... */
751 if (unlikely (!hb_parse_int (pp, end, &v))) return false;
758 parse_bool (const char **pp, const char *end, uint32_t *pv)
760 parse_space (pp, end);
763 while (*pp < end && ISALPHA(**pp))
766 /* CSS allows on/off as aliases 1/0. */
768 && TOLOWER (p[0]) == 'o'
769 && TOLOWER (p[1]) == 'n')
771 else if (*pp - p == 3
772 && TOLOWER (p[0]) == 'o'
773 && TOLOWER (p[1]) == 'f'
774 && TOLOWER (p[2]) == 'f')
785 parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
787 if (parse_char (pp, end, '-'))
790 parse_char (pp, end, '+');
798 parse_tag (const char **pp, const char *end, hb_tag_t *tag)
800 parse_space (pp, end);
804 if (*pp < end && (**pp == '\'' || **pp == '"'))
811 while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
814 if (p == *pp || *pp - p > 4)
817 *tag = hb_tag_from_string (p, *pp - p);
821 /* CSS expects exactly four bytes. And we only allow quotations for
822 * CSS compatibility. So, enforce the length. */
825 if (*pp == end || **pp != quote)
834 parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
836 parse_space (pp, end);
840 feature->start = HB_FEATURE_GLOBAL_START;
841 feature->end = HB_FEATURE_GLOBAL_END;
843 if (!parse_char (pp, end, '['))
846 has_start = parse_uint (pp, end, &feature->start);
848 if (parse_char (pp, end, ':') || parse_char (pp, end, ';')) {
849 parse_uint (pp, end, &feature->end);
852 feature->end = feature->start + 1;
855 return parse_char (pp, end, ']');
859 parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
861 bool had_equal = parse_char (pp, end, '=');
862 bool had_value = parse_uint32 (pp, end, &feature->value) ||
863 parse_bool (pp, end, &feature->value);
864 /* CSS doesn't use equal-sign between tag and value.
865 * If there was an equal-sign, then there *must* be a value.
866 * A value without an equal-sign is ok, but not required. */
867 return !had_equal || had_value;
871 parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
873 return parse_feature_value_prefix (pp, end, feature) &&
874 parse_tag (pp, end, &feature->tag) &&
875 parse_feature_indices (pp, end, feature) &&
876 parse_feature_value_postfix (pp, end, feature) &&
877 parse_space (pp, end) &&
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
887 * Parses a string into a #hb_feature_t.
889 * The format for specifying feature strings follows. All valid CSS
890 * font-feature-settings values other than 'normal' and the global values are
891 * also accepted, though not documented below. CSS string escapes are not
894 * The range indices refer to the positions between Unicode characters. The
895 * position before the first character is always 0.
897 * The format is Python-esque. Here is how it all works:
899 * <informaltable pgwide='1' align='left' frame='none'>
902 * <row><entry>Syntax</entry> <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
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>
926 * %true if @str is successfully parsed, %false otherwise
931 hb_feature_from_string (const char *str, int len,
932 hb_feature_t *feature)
939 if (likely (parse_one_feature (&str, str + len, &feat)))
947 memset (feature, 0, sizeof (*feature));
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
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.
964 hb_feature_to_string (hb_feature_t *feature,
965 char *buf, unsigned int size)
967 if (unlikely (!size)) return;
970 unsigned int len = 0;
971 if (feature->value == 0)
973 hb_tag_to_string (feature->tag, s + len);
975 while (len && s[len - 1] == ' ')
977 if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END)
981 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
982 if (feature->end != feature->start + 1) {
984 if (feature->end != HB_FEATURE_GLOBAL_END)
985 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
989 if (feature->value > 1)
992 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
994 assert (len < ARRAY_LENGTH (s));
995 len = hb_min (len, size - 1);
996 memcpy (buf, s, len);
1000 /* hb_variation_t */
1003 parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
1005 parse_char (pp, end, '='); /* Optional. */
1007 if (unlikely (!hb_parse_double (pp, end, &v))) return false;
1009 variation->value = v;
1014 parse_one_variation (const char **pp, const char *end, hb_variation_t *variation)
1016 return parse_tag (pp, end, &variation->tag) &&
1017 parse_variation_value (pp, end, variation) &&
1018 parse_space (pp, end) &&
1023 * hb_variation_from_string:
1024 * @str: (array length=len) (element-type uint8_t): a string to parse
1025 * @len: length of @str, or -1 if string is %NULL terminated
1026 * @variation: (out): the #hb_variation_t to initialize with the parsed values
1028 * Parses a string into a #hb_variation_t.
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.
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`.
1038 * %true if @str is successfully parsed, %false otherwise
1043 hb_variation_from_string (const char *str, int len,
1044 hb_variation_t *variation)
1051 if (likely (parse_one_variation (&str, str + len, &var)))
1059 memset (variation, 0, sizeof (*variation));
1063 #ifndef HB_NO_SETLOCALE
1065 static inline void free_static_C_locale ();
1067 static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>,
1068 hb_C_locale_lazy_loader_t>
1070 static hb_locale_t create ()
1072 hb_locale_t l = newlocale (LC_ALL_MASK, "C", NULL);
1076 hb_atexit (free_static_C_locale);
1080 static void destroy (hb_locale_t l)
1084 static hb_locale_t get_null ()
1086 return (hb_locale_t) 0;
1091 void free_static_C_locale ()
1093 static_C_locale.free_instance ();
1099 return static_C_locale.get_unconst ();
1105 * hb_variation_to_string:
1106 * @variation: an #hb_variation_t to convert
1107 * @buf: (array length=size) (out): output string
1108 * @size: the allocated size of @buf
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.
1117 hb_variation_to_string (hb_variation_t *variation,
1118 char *buf, unsigned int size)
1120 if (unlikely (!size)) return;
1123 unsigned int len = 0;
1124 hb_tag_to_string (variation->tag, s + len);
1126 while (len && s[len - 1] == ' ')
1130 hb_locale_t oldlocale HB_UNUSED;
1131 oldlocale = hb_uselocale (get_C_locale ());
1132 len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
1133 (void) hb_uselocale (oldlocale);
1135 assert (len < ARRAY_LENGTH (s));
1136 len = hb_min (len, size - 1);
1137 memcpy (buf, s, len);
1142 * hb_color_get_alpha:
1143 * @color: an #hb_color_t we are interested in its channels.
1145 * Fetches the alpha channel of the given @color.
1147 * Return value: Alpha channel value
1152 (hb_color_get_alpha) (hb_color_t color)
1154 return hb_color_get_alpha (color);
1159 * @color: an #hb_color_t we are interested in its channels.
1161 * Fetches the red channel of the given @color.
1163 * Return value: Red channel value
1168 (hb_color_get_red) (hb_color_t color)
1170 return hb_color_get_red (color);
1174 * hb_color_get_green:
1175 * @color: an #hb_color_t we are interested in its channels.
1177 * Fetches the green channel of the given @color.
1179 * Return value: Green channel value
1184 (hb_color_get_green) (hb_color_t color)
1186 return hb_color_get_green (color);
1190 * hb_color_get_blue:
1191 * @color: an #hb_color_t we are interested in its channels.
1193 * Fetches the blue channel of the given @color.
1195 * Return value: Blue channel value
1200 (hb_color_get_blue) (hb_color_t color)
1202 return hb_color_get_blue (color);
1206 /* If there is no visibility control, then hb-static.cc will NOT
1207 * define anything. Instead, we get it to define one set in here
1208 * only, so only libharfbuzz.so defines them, not other libs. */
1209 #ifdef HB_NO_VISIBILITY
1210 #undef HB_NO_VISIBILITY
1211 #include "hb-static.cc"
1212 #define HB_NO_VISIBILITY 1