Index: third_party/harfbuzz-ng/src/hb-shape.cc |
diff --git a/third_party/harfbuzz-ng/src/hb-shape.cc b/third_party/harfbuzz-ng/src/hb-shape.cc |
index c1b752405e1fdc55b8b4515b7e218e130ff90736..74747f88b89f7cf719c3a391eb895684156035d5 100644 |
--- a/third_party/harfbuzz-ng/src/hb-shape.cc |
+++ b/third_party/harfbuzz-ng/src/hb-shape.cc |
@@ -34,15 +34,15 @@ |
#include "hb-font-private.hh" |
-static void |
+static bool |
parse_space (const char **pp, const char *end) |
{ |
- char c; |
- while (*pp < end && (c = **pp, ISSPACE (c))) |
+ while (*pp < end && ISSPACE (**pp)) |
(*pp)++; |
+ return true; |
} |
-static hb_bool_t |
+static bool |
parse_char (const char **pp, const char *end, char c) |
{ |
parse_space (pp, end); |
@@ -54,7 +54,7 @@ parse_char (const char **pp, const char *end, char c) |
return true; |
} |
-static hb_bool_t |
+static bool |
parse_uint (const char **pp, const char *end, unsigned int *pv) |
{ |
char buf[32]; |
@@ -78,7 +78,27 @@ parse_uint (const char **pp, const char *end, unsigned int *pv) |
return true; |
} |
-static hb_bool_t |
+static bool |
+parse_bool (const char **pp, const char *end, unsigned int *pv) |
+{ |
+ parse_space (pp, end); |
+ |
+ const char *p = *pp; |
+ while (*pp < end && ISALPHA(**pp)) |
+ (*pp)++; |
+ |
+ /* CSS allows on/off as aliases 1/0. */ |
+ if (*pp - p == 2 || 0 == strncmp (p, "on", 2)) |
+ *pv = 1; |
+ else if (*pp - p == 3 || 0 == strncmp (p, "off", 2)) |
+ *pv = 0; |
+ else |
+ return false; |
+ |
+ return true; |
+} |
+ |
+static bool |
parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature) |
{ |
if (parse_char (pp, end, '-')) |
@@ -91,32 +111,48 @@ parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feat |
return true; |
} |
-static hb_bool_t |
+static bool |
parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature) |
{ |
- const char *p = *pp; |
- char c; |
- |
parse_space (pp, end); |
-#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9')) |
- while (*pp < end && (c = **pp, ISALNUM(c))) |
+ char quote = 0; |
+ |
+ if (*pp < end && (**pp == '\'' || **pp == '"')) |
+ { |
+ quote = **pp; |
+ (*pp)++; |
+ } |
+ |
+ const char *p = *pp; |
+ while (*pp < end && ISALNUM(**pp)) |
(*pp)++; |
-#undef ISALNUM |
- if (p == *pp) |
+ if (p == *pp || *pp - p > 4) |
return false; |
feature->tag = hb_tag_from_string (p, *pp - p); |
+ |
+ if (quote) |
+ { |
+ /* CSS expects exactly four bytes. And we only allow quotations for |
+ * CSS compatibility. So, enforce the length. */ |
+ if (*pp - p != 4) |
+ return false; |
+ if (*pp == end || **pp != quote) |
+ return false; |
+ (*pp)++; |
+ } |
+ |
return true; |
} |
-static hb_bool_t |
+static bool |
parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature) |
{ |
parse_space (pp, end); |
- hb_bool_t has_start; |
+ bool has_start; |
feature->start = 0; |
feature->end = (unsigned int) -1; |
@@ -136,20 +172,27 @@ parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature) |
return parse_char (pp, end, ']'); |
} |
-static hb_bool_t |
+static bool |
parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature) |
{ |
- return !parse_char (pp, end, '=') || parse_uint (pp, end, &feature->value); |
+ bool had_equal = parse_char (pp, end, '='); |
+ bool had_value = parse_uint (pp, end, &feature->value) || |
+ parse_bool (pp, end, &feature->value); |
+ /* CSS doesn't use equal-sign between tag and value. |
+ * If there was an equal-sign, then there *must* be a value. |
+ * A value without an eqaul-sign is ok, but not required. */ |
+ return !had_equal || had_value; |
} |
-static hb_bool_t |
+static bool |
parse_one_feature (const char **pp, const char *end, hb_feature_t *feature) |
{ |
return parse_feature_value_prefix (pp, end, feature) && |
parse_feature_tag (pp, end, feature) && |
parse_feature_indices (pp, end, feature) && |
parse_feature_value_postfix (pp, end, feature) && |
+ parse_space (pp, end) && |
*pp == end; |
} |
@@ -157,7 +200,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature) |
* hb_feature_from_string: |
* @str: (array length=len): |
* @len: |
- * @feature: (out): |
+ * @feature: (out) (allow-none): |
* |
* |
* |
@@ -169,10 +212,21 @@ hb_bool_t |
hb_feature_from_string (const char *str, int len, |
hb_feature_t *feature) |
{ |
+ hb_feature_t feat; |
+ |
if (len < 0) |
len = strlen (str); |
- return parse_one_feature (&str, str + len, feature); |
+ if (likely (parse_one_feature (&str, str + len, &feat))) |
+ { |
+ if (feature) |
+ *feature = feat; |
+ return true; |
+ } |
+ |
+ if (feature) |
+ memset (feature, 0, sizeof (*feature)); |
+ return false; |
} |
/** |
@@ -203,18 +257,18 @@ hb_feature_to_string (hb_feature_t *feature, |
{ |
s[len++] = '['; |
if (feature->start) |
- len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start)); |
+ len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start)); |
if (feature->end != feature->start + 1) { |
s[len++] = ':'; |
if (feature->end != (unsigned int) -1) |
- len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end)); |
+ len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end)); |
} |
s[len++] = ']'; |
} |
if (feature->value > 1) |
{ |
s[len++] = '='; |
- len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value)); |
+ len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value)); |
} |
assert (len < ARRAY_LENGTH (s)); |
len = MIN (len, size - 1); |
@@ -266,7 +320,7 @@ retry: |
goto retry; |
} |
-#ifdef HAVE_ATEXIT |
+#ifdef HB_USE_ATEXIT |
atexit (free_static_shaper_list); /* First person registers atexit() callback. */ |
#endif |
} |