diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 4a5c06cd6..832e32f8d 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -900,6 +900,8 @@ hb_subset_input_pin_axis_location hb_subset_input_pin_axis_to_default hb_subset_input_get_axis_range hb_subset_input_set_axis_range +hb_subset_axis_range_from_string +hb_subset_axis_range_to_string hb_subset_or_fail hb_subset_plan_create_or_fail hb_subset_plan_reference diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index b874949df..1261ec899 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -534,7 +534,6 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input, * * Note: input min value can not be bigger than input max value. If the input * default value is not within the new min/max range, it'll be clamped. - * Note: currently it supports gvar and cvar tables only. * * Return value: `true` if success, `false` otherwise * @@ -597,6 +596,144 @@ hb_subset_input_get_axis_range (hb_subset_input_t *input, *axis_max_value = triple->maximum; return true; } + +/** + * hb_subset_axis_range_from_string: + * @str: a string to parse + * @len: length of @str, or -1 if str is NULL terminated + * @axis_min_value: (out): the axis min value to initialize with the parsed value + * @axis_max_value: (out): the axis max value to initialize with the parsed value + * @axis_def_value: (out): the axis default value to initialize with the parse + * value + * + * Parses a string into a subset axis range(min, def, max). + * Axis positions string is in the format of min:def:max or min:max + * When parsing axis positions, empty values as meaning the existing value for that part + * E.g: :300:500 + * Specifies min = existing, def = 300, max = 500 + * In the output axis_range, if a value should be set to it's default value, + * then it will be set to NaN + * + * Return value: + * `true` if @str is successfully parsed, `false` otherwise + * + * XSince: REPLACEME + */ +HB_EXTERN hb_bool_t +hb_subset_axis_range_from_string (const char *str, int len, + float *axis_min_value, + float *axis_max_value, + float *axis_def_value) +{ + if (len < 0) + len = strlen (str); + + const char *end = str + len; + const char* part = strpbrk (str, ":"); + if (!part) + { + // Single value. + if (strcmp (str, "drop") == 0) + { + *axis_min_value = NAN; + *axis_def_value = NAN; + *axis_max_value = NAN; + return true; + } + + double v; + if (!hb_parse_double (&str, end, &v)) return false; + + *axis_min_value = v; + *axis_def_value = v; + *axis_max_value = v; + return true; + } + + float values[3]; + int count = 0; + for (int i = 0; i < 3; i++) { + count++; + if (!*str || part == str) + { + values[i] = NAN; + + if (part == NULL) break; + str = part + 1; + part = strpbrk (str, ":"); + continue; + } + + double v; + if (!hb_parse_double (&str, part, &v)) return false; + values[i] = v; + + if (part == NULL) break; + str = part + 1; + part = strpbrk (str, ":"); + } + + if (count == 2) + { + *axis_min_value = values[0]; + *axis_def_value = NAN; + *axis_max_value = values[1]; + return true; + } + else if (count == 3) + { + *axis_min_value = values[0]; + *axis_def_value = values[1]; + *axis_max_value = values[2]; + return true; + } + return false; +} + +/** + * hb_subset_axis_range_to_string: + * @input: a #hb_subset_input_t object. + * @axis_tag: an axis to convert + * @buf: (array length=size) (out caller-allocates): output string + * @size: the allocated size of @buf + * + * Converts an axis range into a `NULL`-terminated string in the format + * understood by hb_subset_axis_range_from_string(). The client in responsible for + * allocating big enough size for @buf, 128 bytes is more than enough. + * + * XSince: REPLACEME + */ +HB_EXTERN void +hb_subset_axis_range_to_string (hb_subset_input_t *input, + hb_tag_t axis_tag, + char *buf, unsigned size) +{ + if (unlikely (!size)) return; + Triple* triple; + if (!input->axes_location.has(axis_tag, &triple)) { + return; + } + + char s[128]; + unsigned len = 0; + + hb_locale_t clocale HB_UNUSED; + hb_locale_t oldlocale HB_UNUSED; + oldlocale = hb_uselocale (clocale = newlocale (LC_ALL_MASK, "C", NULL)); + len += hb_max (0, snprintf (s, ARRAY_LENGTH (s) - len, "%g", (double) triple->minimum)); + s[len++] = ':'; + + len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) triple->middle)); + s[len++] = ':'; + + len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) triple->maximum)); + (void) hb_uselocale (((void) freelocale (clocale), oldlocale)); + + assert (len < ARRAY_LENGTH (s)); + len = hb_min (len, size - 1); + hb_memcpy (buf, s, len); + buf[len] = '\0'; +} #endif /** diff --git a/src/hb-subset.h b/src/hb-subset.h index 365c21a63..71276c7a6 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -203,6 +203,18 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input, float axis_max_value, float axis_def_value); +HB_EXTERN hb_bool_t +hb_subset_axis_range_from_string (const char *str, int len, + float *axis_min_value, + float *axis_max_value, + float *axis_def_value); + +HB_EXTERN void +hb_subset_axis_range_to_string (hb_subset_input_t *input, + hb_tag_t axis_tag, + char *buf, + unsigned size); + #ifdef HB_EXPERIMENTAL_API HB_EXTERN hb_bool_t hb_subset_input_override_name_table (hb_subset_input_t *input, diff --git a/util/helper-subset.hh b/util/helper-subset.hh index a050d713d..91d5f7b54 100644 --- a/util/helper-subset.hh +++ b/util/helper-subset.hh @@ -34,92 +34,6 @@ #ifndef HB_NO_VAR -// Parses an axis position string and sets min, default, and max to -// the requested values. If a value should be set to it's default value -// then it will be set to NaN. -static gboolean -parse_axis_position(const char* s, - float* min, - float* def, - float* max, - gboolean* drop, - GError **error) -{ - const char* part = strpbrk(s, ":"); - *drop = false; - if (!part) { - // Single value. - if (strcmp (s, "drop") == 0) - { - *min = NAN; - *def = NAN; - *max = NAN; - *drop = true; - return true; - } - - errno = 0; - char *p; - float axis_value = strtof (s, &p); - if (errno || s == p) - { - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Failed parsing axis value at: '%s'", s); - return false; - } - - *min = axis_value; - *def = axis_value; - *max = axis_value; - return true; - } - - - float values[3]; - int count = 0; - for (int i = 0; i < 3; i++) { - errno = 0; - count++; - if (!*s || part == s) { - values[i] = NAN; - - if (part == NULL) break; - s = part + 1; - part = strpbrk(s, ":"); - continue; - } - - char *pend; - values[i] = strtof (s, &pend); - if (errno || s == pend || (part && pend != part)) - { - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Failed parsing axis value at: '%s'", s); - return false; - } - - if (part == NULL) break; - s = pend + 1; - part = strpbrk(s, ":"); - } - - if (count == 2) { - *min = values[0]; - *def = NAN; - *max = values[1]; - return true; - } else if (count == 3) { - *min = values[0]; - *def = values[1]; - *max = values[2]; - return true; - } - - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Failed parsing axis value at: '%s'", s); - return false; -} - static gboolean parse_instancing_spec (const char *arg, hb_face_t* face, @@ -168,13 +82,7 @@ parse_instancing_spec (const char *arg, return false; } - gboolean drop; - float min, def, max; - if (!parse_axis_position(s, &min, &def, &max, &drop, error)) - return false; - - if (drop) - { + if (strcmp (s, "drop") == 0) { if (!hb_subset_input_pin_axis_to_default (input, face, axis_tag)) @@ -185,18 +93,9 @@ parse_instancing_spec (const char *arg, } continue; } - - if (min == def && def == max) { - if (!hb_subset_input_pin_axis_location (input, - face, axis_tag, - def)) - { - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag)); - return false; - } - continue; - } + float min, def, max; + if (!hb_subset_axis_range_from_string(s, -1, &min, &max, &def)) + return false; if (!hb_subset_input_set_axis_range (input, face, axis_tag, @@ -207,10 +106,6 @@ parse_instancing_spec (const char *arg, return false; } continue; - - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Partial instancing is not supported."); - return false; } return true;