#include "hb.hh"
#include "hb-machinery.hh"
+#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE))
+#define HB_NO_SETLOCALE 1
+#endif
+
+#ifndef HB_NO_SETLOCALE
+
#include <locale.h>
+#ifdef HAVE_XLOCALE_H
+#include <xlocale.h> // Needed on BSD/OS X for uselocale
+#endif
+
+#ifdef WIN32
+#define hb_locale_t _locale_t
+#else
+#define hb_locale_t locale_t
+#endif
+#define hb_setlocale setlocale
+#define hb_uselocale uselocale
+
+#else
+
+#define hb_locale_t void *
+#define hb_setlocale(Category, Locale) "C"
+#define hb_uselocale(Locale) ((hb_locale_t) 0)
-#ifdef HB_NO_SETLOCALE
-#define setlocale(Category, Locale) "C"
#endif
/**
/**
* hb_tag_from_string:
- * @str: (array length=len) (element-type uint8_t):
- * @len:
+ * @str: (array length=len) (element-type uint8_t): String to convert
+ * @len: Length of @str, or -1 if it is %NULL-terminated
*
+ * Converts a string into an #hb_tag_t. Valid tags
+ * are four characters. Shorter input strings will be
+ * padded with spaces. Longer input strings will be
+ * truncated.
*
- *
- * Return value:
+ * Return value: The #hb_tag_t corresponding to @str
*
* Since: 0.9.2
**/
/**
* hb_tag_to_string:
- * @tag:
- * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
- *
+ * @tag: #hb_tag_t to convert
+ * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string
*
+ * Converts an #hb_tag_t to a string and returns it in @buf.
+ * Strings will be four characters long.
*
* Since: 0.9.5
**/
/**
* hb_direction_from_string:
- * @str: (array length=len) (element-type uint8_t):
- * @len:
+ * @str: (array length=len) (element-type uint8_t): String to convert
+ * @len: Length of @str, or -1 if it is %NULL-terminated
*
+ * Converts a string to an #hb_direction_t.
*
+ * Matching is loose and applies only to the first letter. For
+ * examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR.
*
- * Return value:
+ * Unmatched strings will return #HB_DIRECTION_INVALID.
+ *
+ * Return value: The #hb_direction_t matching @str
*
* Since: 0.9.2
**/
/**
* hb_direction_to_string:
- * @direction:
- *
+ * @direction: The #hb_direction_t to convert
*
+ * Converts an #hb_direction_t to a string.
*
- * Return value: (transfer none):
+ * Return value: (transfer none): The string corresponding to @direction
*
* Since: 0.9.2
**/
bool operator == (const char *s) const
{ return lang_equal (lang, s); }
- hb_language_item_t & operator = (const char *s) {
- /* If a custom allocated is used calling strdup() pairs
- badly with a call to the custom free() in fini() below.
- Therefore don't call strdup(), implement its behavior.
- */
+ hb_language_item_t & operator = (const char *s)
+ {
+ /* We can't call strdup(), because we allow custom allocators. */
size_t len = strlen(s) + 1;
- lang = (hb_language_t) malloc(len);
+ lang = (hb_language_t) hb_malloc(len);
if (likely (lang))
{
memcpy((unsigned char *) lang, s, len);
return *this;
}
- void fini () { free ((void *) lang); }
+ void fini () { hb_free ((void *) lang); }
};
-/* Thread-safe lock-free language list */
+/* Thread-safe lockfree language list */
static hb_atomic_ptr_t <hb_language_item_t> langs;
-#if HB_USE_ATEXIT
-static void
+static inline void
free_langs ()
{
retry:
while (first_lang) {
hb_language_item_t *next = first_lang->next;
first_lang->fini ();
- free (first_lang);
+ hb_free (first_lang);
first_lang = next;
}
}
-#endif
static hb_language_item_t *
lang_find_or_insert (const char *key)
return lang;
/* Not found; allocate one. */
- hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
+ hb_language_item_t *lang = (hb_language_item_t *) hb_calloc (1, sizeof (hb_language_item_t));
if (unlikely (!lang))
return nullptr;
lang->next = first_lang;
*lang = key;
if (unlikely (!lang->lang))
{
- free (lang);
+ hb_free (lang);
return nullptr;
}
if (unlikely (!langs.cmpexch (first_lang, lang)))
{
lang->fini ();
- free (lang);
+ hb_free (lang);
goto retry;
}
-#if HB_USE_ATEXIT
if (!first_lang)
- atexit (free_langs); /* First person registers atexit() callback. */
-#endif
+ hb_atexit (free_langs); /* First person registers atexit() callback. */
return lang;
}
/**
* hb_language_to_string:
- * @language: an #hb_language_t to convert.
+ * @language: The #hb_language_t to convert
*
- * See hb_language_from_string().
+ * Converts an #hb_language_t to a string.
*
* Return value: (transfer none):
* A %NULL-terminated string representing the @language. Must not be freed by
/**
* hb_language_get_default:
*
- * Get default language from current locale.
+ * Fetch the default language from current locale.
*
- * Note that the first time this function is called, it calls
+ * <note>Note that the first time this function is called, it calls
* "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying
* setlocale function is, in many implementations, NOT threadsafe. To avoid
* problems, call this function once before multiple threads can call it.
* This function is only used from hb_buffer_guess_segment_properties() by
- * HarfBuzz itself.
+ * HarfBuzz itself.</note>
*
- * Return value: (transfer none):
+ * Return value: (transfer none): The default language of the locale as
+ * an #hb_language_t
*
* Since: 0.9.2
**/
hb_language_t language = default_language;
if (unlikely (language == HB_LANGUAGE_INVALID))
{
- language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
+ language = hb_language_from_string (hb_setlocale (LC_CTYPE, nullptr), -1);
(void) default_language.cmpexch (HB_LANGUAGE_INVALID, language);
}
case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
/* Script variants from https://unicode.org/iso15924/ */
+ case HB_TAG('A','r','a','n'): return HB_SCRIPT_ARABIC;
case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
+ case HB_TAG('G','e','o','k'): return HB_SCRIPT_GEORGIAN;
+ case HB_TAG('H','a','n','s'): return HB_SCRIPT_HAN;
+ case HB_TAG('H','a','n','t'): return HB_SCRIPT_HAN;
+ case HB_TAG('J','a','m','o'): return HB_SCRIPT_HANGUL;
case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
* hb_script_to_iso15924_tag:
* @script: an #hb_script_t to convert.
*
- * See hb_script_from_iso15924_tag().
+ * Converts an #hb_script_t to a corresponding ISO 15924 script tag.
*
* Return value:
* An #hb_tag_t representing an ISO 15924 script tag.
/**
* hb_script_get_horizontal_direction:
- * @script:
+ * @script: The #hb_script_t to query
*
+ * Fetches the #hb_direction_t of a script when it is
+ * set horizontally. All right-to-left scripts will return
+ * #HB_DIRECTION_RTL. All left-to-right scripts will return
+ * #HB_DIRECTION_LTR. Scripts that can be written either
+ * horizontally or vertically will return #HB_DIRECTION_INVALID.
+ * Unknown scripts will return #HB_DIRECTION_LTR.
*
- *
- * Return value:
+ * Return value: The horizontal #hb_direction_t of @script
*
* Since: 0.9.2
**/
case HB_SCRIPT_CHORASMIAN:
case HB_SCRIPT_YEZIDI:
+ /* Unicode-14.0 additions */
+ case HB_SCRIPT_OLD_UYGHUR:
+
return HB_DIRECTION_RTL;
/**
* hb_version:
- * @major: (out): Library major version component.
- * @minor: (out): Library minor version component.
- * @micro: (out): Library micro version component.
+ * @major: (out): Library major version component
+ * @minor: (out): Library minor version component
+ * @micro: (out): Library micro version component
*
* Returns library version as three integer components.
*
*
* Returns library version as a string with three components.
*
- * Return value: library version string.
+ * Return value: Library version string
*
* Since: 0.9.2
**/
/**
* hb_version_atleast:
- * @major:
- * @minor:
- * @micro:
+ * @major: Library major version component
+ * @minor: Library minor version component
+ * @micro: Library micro version component
*
+ * Tests the library version against a minimum value,
+ * as three integer components.
*
- *
- * Return value:
+ * Return value: %true if the library is equal to or greater than
+ * the test value, %false otherwise
*
* Since: 0.9.30
**/
* </informaltable>
*
* Return value:
- * %true if @str is successfully parsed, %false otherwise.
+ * %true if @str is successfully parsed, %false otherwise
*
* Since: 0.9.5
**/
/**
* hb_variation_from_string:
+ * @str: (array length=len) (element-type uint8_t): a string to parse
+ * @len: length of @str, or -1 if string is %NULL terminated
+ * @variation: (out): the #hb_variation_t to initialize with the parsed values
+ *
+ * Parses a string into a #hb_variation_t.
+ *
+ * The format for specifying variation settings follows. All valid CSS
+ * font-variation-settings values other than 'normal' and 'inherited' are also
+ * accepted, though, not documented below.
+ *
+ * The format is a tag, optionally followed by an equals sign, followed by a
+ * number. For example `wght=500`, or `slnt=-7.5`.
+ *
+ * Return value:
+ * %true if @str is successfully parsed, %false otherwise
*
* Since: 1.4.2
*/
return false;
}
+#ifndef HB_NO_SETLOCALE
+
+static inline void free_static_C_locale ();
+
+static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>,
+ hb_C_locale_lazy_loader_t>
+{
+ static hb_locale_t create ()
+ {
+ hb_locale_t l = newlocale (LC_ALL_MASK, "C", NULL);
+ if (!l)
+ return l;
+
+ hb_atexit (free_static_C_locale);
+
+ return l;
+ }
+ static void destroy (hb_locale_t l)
+ {
+ freelocale (l);
+ }
+ static hb_locale_t get_null ()
+ {
+ return (hb_locale_t) 0;
+ }
+} static_C_locale;
+
+static inline
+void free_static_C_locale ()
+{
+ static_C_locale.free_instance ();
+}
+
+static hb_locale_t
+get_C_locale ()
+{
+ return static_C_locale.get_unconst ();
+}
+
+#endif
+
/**
* hb_variation_to_string:
+ * @variation: an #hb_variation_t to convert
+ * @buf: (array length=size) (out): output string
+ * @size: the allocated size of @buf
+ *
+ * Converts an #hb_variation_t into a %NULL-terminated string in the format
+ * understood by hb_variation_from_string(). The client in responsible for
+ * allocating big enough size for @buf, 128 bytes is more than enough.
*
* Since: 1.4.2
*/
while (len && s[len - 1] == ' ')
len--;
s[len++] = '=';
+
+ hb_locale_t oldlocale HB_UNUSED;
+ oldlocale = hb_uselocale (get_C_locale ());
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
+ (void) hb_uselocale (oldlocale);
assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1);
/**
* hb_color_get_alpha:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
+ *
+ * Fetches the alpha channel of the given @color.
*
- * Return value: Alpha channel value of the given color
+ * Return value: Alpha channel value
*
* Since: 2.1.0
*/
/**
* hb_color_get_red:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
*
- * Return value: Red channel value of the given color
+ * Fetches the red channel of the given @color.
+ *
+ * Return value: Red channel value
*
* Since: 2.1.0
*/
/**
* hb_color_get_green:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
+ *
+ * Fetches the green channel of the given @color.
*
- * Return value: Green channel value of the given color
+ * Return value: Green channel value
*
* Since: 2.1.0
*/
/**
* hb_color_get_blue:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
+ *
+ * Fetches the blue channel of the given @color.
*
- * Return value: Blue channel value of the given color
+ * Return value: Blue channel value
*
* Since: 2.1.0
*/