Add hb_feature_to/from_string()
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 1301ab2..33a514d 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -58,6 +58,15 @@
return HB_TAG_CHAR4 (tag);
}
+void
+hb_tag_to_string (hb_tag_t tag, char *buf)
+{
+ buf[0] = (char) (uint8_t) (tag >> 24);
+ buf[1] = (char) (uint8_t) (tag >> 16);
+ buf[2] = (char) (uint8_t) (tag >> 8);
+ buf[3] = (char) (uint8_t) (tag >> 0);
+}
+
/* hb_direction_t */
diff --git a/src/hb-common.h b/src/hb-common.h
index 920bd32..cc221d3 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -95,10 +95,14 @@
#define HB_TAG_NONE HB_TAG(0,0,0,0)
-/* len=-1 means str is NUL-terminated */
+/* len=-1 means str is NUL-terminated. */
hb_tag_t
hb_tag_from_string (const char *str, int len);
+/* buf should have 4 bytes. */
+void
+hb_tag_to_string (hb_tag_t tag, char *buf);
+
/* hb_direction_t */
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 5aa587b..6619c19 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -1,5 +1,6 @@
/*
* Copyright © 2009 Red Hat, Inc.
+ * Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
@@ -32,6 +34,172 @@
#include "hb-font-private.hh"
+static void
+parse_space (const char **pp, const char *end)
+{
+ char c;
+#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v')
+ while (*pp < end && (c = **pp, ISSPACE (c)))
+ (*pp)++;
+#undef ISSPACE
+}
+
+static hb_bool_t
+parse_char (const char **pp, const char *end, char c)
+{
+ parse_space (pp, end);
+
+ if (*pp == end || **pp != c)
+ return false;
+
+ (*pp)++;
+ return true;
+}
+
+static hb_bool_t
+parse_uint (const char **pp, const char *end, unsigned int *pv)
+{
+ char buf[32];
+ strncpy (buf, *pp, end - *pp);
+ buf[ARRAY_LENGTH (buf) - 1] = '\0';
+
+ char *p = buf;
+ char *pend = p;
+ unsigned int v;
+
+ v = strtol (p, &pend, 0);
+
+ if (p == pend)
+ return false;
+
+ *pv = v;
+ *pp += pend - p;
+ return true;
+}
+
+static hb_bool_t
+parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
+{
+ if (parse_char (pp, end, '-'))
+ feature->value = 0;
+ else {
+ parse_char (pp, end, '+');
+ feature->value = 1;
+ }
+
+ return true;
+}
+
+static hb_bool_t
+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)))
+ (*pp)++;
+#undef ISALNUM
+
+ if (p == *pp)
+ return false;
+
+ feature->tag = hb_tag_from_string (p, *pp - p);
+ return true;
+}
+
+static hb_bool_t
+parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
+{
+ parse_space (pp, end);
+
+ hb_bool_t has_start;
+
+ feature->start = 0;
+ feature->end = (unsigned int) -1;
+
+ if (!parse_char (pp, end, '['))
+ return true;
+
+ has_start = parse_uint (pp, end, &feature->start);
+
+ if (parse_char (pp, end, ':')) {
+ parse_uint (pp, end, &feature->end);
+ } else {
+ if (has_start)
+ feature->end = feature->start + 1;
+ }
+
+ return parse_char (pp, end, ']');
+}
+
+static hb_bool_t
+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);
+}
+
+
+static hb_bool_t
+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) &&
+ *pp == end;
+}
+
+hb_bool_t
+hb_feature_from_string (const char *str, int len,
+ hb_feature_t *feature)
+{
+ if (len < 0)
+ len = strlen (str);
+
+ return parse_one_feature (&str, str + len, feature);
+}
+
+void
+hb_feature_to_string (hb_feature_t *feature,
+ char *buf, unsigned int size)
+{
+ if (unlikely (!size)) return;
+
+ char s[128];
+ unsigned int len = 0;
+ if (feature->value == 0)
+ s[len++] = '-';
+ hb_tag_to_string (feature->tag, s + len);
+ len += 4;
+ while (len && s[len - 1] == ' ')
+ len--;
+ if (feature->start != 0 || feature->start != (unsigned int) -1)
+ {
+ s[len++] = '[';
+ if (feature->start)
+ len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start);
+ if (feature->end != feature->start + 1) {
+ s[len++] = ':';
+ if (feature->end != (unsigned int) -1)
+ len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end);
+ }
+ s[len++] = ']';
+ }
+ if (feature->value > 1)
+ {
+ s[len++] = '=';
+ len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value);
+ }
+ assert (len < ARRAY_LENGTH (s));
+ len = MIN (len, size - 1);
+ memcpy (buf, s, len);
+ s[len] = '\0';
+}
+
+
static const char **static_shaper_list;
static
diff --git a/src/hb-shape.h b/src/hb-shape.h
index 84bf3e7..90a188d 100644
--- a/src/hb-shape.h
+++ b/src/hb-shape.h
@@ -1,5 +1,6 @@
/*
* Copyright © 2009 Red Hat, Inc.
+ * Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
@@ -45,6 +47,17 @@
unsigned int end;
} hb_feature_t;
+/* len=-1 means str is NUL-terminated */
+hb_bool_t
+hb_feature_from_string (const char *str, int len,
+ hb_feature_t *feature);
+
+/* something like 128 bytes is more than enough.
+ * nul-terminates. */
+void
+hb_feature_to_string (hb_feature_t *feature,
+ char *buf, unsigned int size);
+
void
hb_shape (hb_font_t *font,