[HarfBuzz] harfbuzz: Branch 'master' - 13 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Sat Jan 21 04:36:10 UTC 2017


 src/Makefile.am             |    2 
 src/Makefile.sources        |    3 
 src/hb-common.cc            |  334 ++++++++++++++++++++++++++++++++++++++++++++
 src/hb-common.h             |   31 ++++
 src/hb-font.cc              |    4 
 src/hb-ft.cc                |    2 
 src/hb-ot-layout-private.hh |    6 
 src/hb-ot-layout.cc         |    4 
 src/hb-ot-math.cc           |    7 
 src/hb-ot-var-fvar-table.hh |  208 +++++++++++++++++++++++++++
 src/hb-ot-var.cc            |  100 +++++++++++++
 src/hb-ot-var.h             |   96 ++++++++++++
 src/hb-ot.h                 |    1 
 src/hb-shape.cc             |  248 --------------------------------
 src/hb-shape.h              |   16 --
 test/api/test-ot-math.c     |   32 +++-
 16 files changed, 812 insertions(+), 282 deletions(-)

New commits:
commit b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jan 20 20:30:03 2017 -0800

    [var] Add hb_var_coord_t and parsing routines

diff --git a/src/hb-common.cc b/src/hb-common.cc
index 04d9fb0..25c979c 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -607,7 +607,8 @@ hb_version_atleast (unsigned int major,
 }
 
 
-/* hb_feature_t */
+
+/* hb_feature_t and hb_var_coord_t */
 
 static bool
 parse_space (const char **pp, const char *end)
@@ -654,6 +655,28 @@ parse_uint (const char **pp, const char *end, unsigned int *pv)
 }
 
 static bool
+parse_float (const char **pp, const char *end, float *pv)
+{
+  char buf[32];
+  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
+  strncpy (buf, *pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  float v;
+
+  errno = 0;
+  v = strtof (p, &pend);
+  if (errno || p == pend)
+    return false;
+
+  *pv = v;
+  *pp += pend - p;
+  return true;
+}
+
+static bool
 parse_bool (const char **pp, const char *end, unsigned int *pv)
 {
   parse_space (pp, end);
@@ -673,6 +696,8 @@ parse_bool (const char **pp, const char *end, unsigned int *pv)
   return true;
 }
 
+/* hb_feature_t */
+
 static bool
 parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
 {
@@ -687,7 +712,7 @@ parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feat
 }
 
 static bool
-parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
+parse_tag (const char **pp, const char *end, hb_tag_t *tag)
 {
   parse_space (pp, end);
 
@@ -706,7 +731,7 @@ parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
   if (p == *pp || *pp - p > 4)
     return false;
 
-  feature->tag = hb_tag_from_string (p, *pp - p);
+  *tag = hb_tag_from_string (p, *pp - p);
 
   if (quote)
   {
@@ -759,12 +784,11 @@ parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *fea
   return !had_equal || had_value;
 }
 
-
 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_tag (pp, end, &feature->tag) &&
 	 parse_feature_indices (pp, end, feature) &&
 	 parse_feature_value_postfix (pp, end, feature) &&
 	 parse_space (pp, end) &&
@@ -855,3 +879,63 @@ hb_feature_to_string (hb_feature_t *feature,
   memcpy (buf, s, len);
   buf[len] = '\0';
 }
+
+/* hb_var_coord_t */
+
+static bool
+parse_var_coord_value (const char **pp, const char *end, hb_var_coord_t *var_coord)
+{
+  parse_char (pp, end, '='); /* Optional. */
+  return parse_float (pp, end, &var_coord->value);
+}
+
+static bool
+parse_one_var_coord (const char **pp, const char *end, hb_var_coord_t *var_coord)
+{
+  return parse_tag (pp, end, &var_coord->tag) &&
+	 parse_var_coord_value (pp, end, var_coord) &&
+	 parse_space (pp, end) &&
+	 *pp == end;
+}
+
+hb_bool_t
+hb_var_coord_from_string (const char *str, int len,
+			  hb_var_coord_t *var_coord)
+{
+  hb_var_coord_t coord;
+
+  if (len < 0)
+    len = strlen (str);
+
+  if (likely (parse_one_var_coord (&str, str + len, &coord)))
+  {
+    if (var_coord)
+      *var_coord = coord;
+    return true;
+  }
+
+  if (var_coord)
+    memset (var_coord, 0, sizeof (*var_coord));
+  return false;
+}
+
+void
+hb_var_coord_to_string (hb_var_coord_t *var_coord,
+			char *buf, unsigned int size)
+{
+  if (unlikely (!size)) return;
+
+  char s[128];
+  unsigned int len = 0;
+  hb_tag_to_string (var_coord->tag, s + len);
+  len += 4;
+  while (len && s[len - 1] == ' ')
+    len--;
+  s[len++] = '=';
+  len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", var_coord->value));
+
+  assert (len < ARRAY_LENGTH (s));
+  len = MIN (len, size - 1);
+  memcpy (buf, s, len);
+  buf[len] = '\0';
+}
diff --git a/src/hb-common.h b/src/hb-common.h
index dd72a9d..e483fb8 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -362,7 +362,7 @@ typedef struct hb_user_data_key_t {
 typedef void (*hb_destroy_func_t) (void *user_data);
 
 
-/* Font features. */
+/* Font features and variations. */
 
 typedef struct hb_feature_t {
   hb_tag_t      tag;
@@ -379,6 +379,19 @@ HB_EXTERN void
 hb_feature_to_string (hb_feature_t *feature,
 		      char *buf, unsigned int size);
 
+typedef struct hb_var_coord_t {
+  hb_tag_t tag;
+  float    value;
+} hb_var_coord_t;
+
+HB_EXTERN hb_bool_t
+hb_var_coord_from_string (const char *str, int len,
+			  hb_var_coord_t *var_coord);
+
+HB_EXTERN void
+hb_var_coord_to_string (hb_var_coord_t *var_coord,
+			char *buf, unsigned int size);
+
 
 HB_END_DECLS
 
commit 72364103bc9d910d19f23a3764d045af79d076d5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jan 20 20:16:53 2017 -0800

    Move code around

diff --git a/src/hb-common.cc b/src/hb-common.cc
index 3564e43..04d9fb0 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -605,3 +605,253 @@ hb_version_atleast (unsigned int major,
 {
   return HB_VERSION_ATLEAST (major, minor, micro);
 }
+
+
+/* hb_feature_t */
+
+static bool
+parse_space (const char **pp, const char *end)
+{
+  while (*pp < end && ISSPACE (**pp))
+    (*pp)++;
+  return true;
+}
+
+static bool
+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 bool
+parse_uint (const char **pp, const char *end, unsigned int *pv)
+{
+  char buf[32];
+  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
+  strncpy (buf, *pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  unsigned int v;
+
+  /* Intentionally use strtol instead of strtoul, such that
+   * -1 turns into "big number"... */
+  errno = 0;
+  v = strtol (p, &pend, 0);
+  if (errno || p == pend)
+    return false;
+
+  *pv = v;
+  *pp += pend - p;
+  return true;
+}
+
+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, '-'))
+    feature->value = 0;
+  else {
+    parse_char (pp, end, '+');
+    feature->value = 1;
+  }
+
+  return true;
+}
+
+static bool
+parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
+{
+  parse_space (pp, end);
+
+  char quote = 0;
+
+  if (*pp < end && (**pp == '\'' || **pp == '"'))
+  {
+    quote = **pp;
+    (*pp)++;
+  }
+
+  const char *p = *pp;
+  while (*pp < end && ISALNUM(**pp))
+    (*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 bool
+parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
+{
+  parse_space (pp, end);
+
+  bool 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 bool
+parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
+{
+  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 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;
+}
+
+/**
+ * hb_feature_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
+ * @feature: (out): the #hb_feature_t to initialize with the parsed values
+ *
+ * Parses a string into a #hb_feature_t.
+ *
+ * TODO: document the syntax here.
+ *
+ * Return value:
+ * %true if @str is successfully parsed, %false otherwise.
+ *
+ * Since: 0.9.5
+ **/
+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);
+
+  if (likely (parse_one_feature (&str, str + len, &feat)))
+  {
+    if (feature)
+      *feature = feat;
+    return true;
+  }
+
+  if (feature)
+    memset (feature, 0, sizeof (*feature));
+  return false;
+}
+
+/**
+ * hb_feature_to_string:
+ * @feature: an #hb_feature_t to convert
+ * @buf: (array length=size) (out): output string
+ * @size: the allocated size of @buf
+ *
+ * Converts a #hb_feature_t into a %NULL-terminated string in the format
+ * understood by hb_feature_from_string(). The client in responsible for
+ * allocating big enough size for @buf, 128 bytes is more than enough.
+ *
+ * Since: 0.9.5
+ **/
+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->end != (unsigned int) -1)
+  {
+    s[len++] = '[';
+    if (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, "%u", feature->end));
+    }
+    s[len++] = ']';
+  }
+  if (feature->value > 1)
+  {
+    s[len++] = '=';
+    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
+  }
+  assert (len < ARRAY_LENGTH (s));
+  len = MIN (len, size - 1);
+  memcpy (buf, s, len);
+  buf[len] = '\0';
+}
diff --git a/src/hb-common.h b/src/hb-common.h
index 2cbee76..dd72a9d 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -362,6 +362,24 @@ typedef struct hb_user_data_key_t {
 typedef void (*hb_destroy_func_t) (void *user_data);
 
 
+/* Font features. */
+
+typedef struct hb_feature_t {
+  hb_tag_t      tag;
+  uint32_t      value;
+  unsigned int  start;
+  unsigned int  end;
+} hb_feature_t;
+
+HB_EXTERN hb_bool_t
+hb_feature_from_string (const char *str, int len,
+			hb_feature_t *feature);
+
+HB_EXTERN void
+hb_feature_to_string (hb_feature_t *feature,
+		      char *buf, unsigned int size);
+
+
 HB_END_DECLS
 
 #endif /* HB_COMMON_H */
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 706f144..f57cad9 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -45,254 +45,6 @@
  * contains the output glyphs and their positions.
  **/
 
-static bool
-parse_space (const char **pp, const char *end)
-{
-  while (*pp < end && ISSPACE (**pp))
-    (*pp)++;
-  return true;
-}
-
-static bool
-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 bool
-parse_uint (const char **pp, const char *end, unsigned int *pv)
-{
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
-  strncpy (buf, *pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  unsigned int v;
-
-  /* Intentionally use strtol instead of strtoul, such that
-   * -1 turns into "big number"... */
-  errno = 0;
-  v = strtol (p, &pend, 0);
-  if (errno || p == pend)
-    return false;
-
-  *pv = v;
-  *pp += pend - p;
-  return true;
-}
-
-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, '-'))
-    feature->value = 0;
-  else {
-    parse_char (pp, end, '+');
-    feature->value = 1;
-  }
-
-  return true;
-}
-
-static bool
-parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
-{
-  parse_space (pp, end);
-
-  char quote = 0;
-
-  if (*pp < end && (**pp == '\'' || **pp == '"'))
-  {
-    quote = **pp;
-    (*pp)++;
-  }
-
-  const char *p = *pp;
-  while (*pp < end && ISALNUM(**pp))
-    (*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 bool
-parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
-{
-  parse_space (pp, end);
-
-  bool 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 bool
-parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
-{
-  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 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;
-}
-
-/**
- * hb_feature_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
- * @feature: (out): the #hb_feature_t to initialize with the parsed values
- *
- * Parses a string into a #hb_feature_t.
- *
- * TODO: document the syntax here.
- *
- * Return value:
- * %true if @str is successfully parsed, %false otherwise.
- *
- * Since: 0.9.5
- **/
-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);
-
-  if (likely (parse_one_feature (&str, str + len, &feat)))
-  {
-    if (feature)
-      *feature = feat;
-    return true;
-  }
-
-  if (feature)
-    memset (feature, 0, sizeof (*feature));
-  return false;
-}
-
-/**
- * hb_feature_to_string:
- * @feature: an #hb_feature_t to convert
- * @buf: (array length=size) (out): output string
- * @size: the allocated size of @buf
- *
- * Converts a #hb_feature_t into a %NULL-terminated string in the format
- * understood by hb_feature_from_string(). The client in responsible for
- * allocating big enough size for @buf, 128 bytes is more than enough.
- *
- * Since: 0.9.5
- **/
-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->end != (unsigned int) -1)
-  {
-    s[len++] = '[';
-    if (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, "%u", feature->end));
-    }
-    s[len++] = ']';
-  }
-  if (feature->value > 1)
-  {
-    s[len++] = '=';
-    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
-  }
-  assert (len < ARRAY_LENGTH (s));
-  len = MIN (len, size - 1);
-  memcpy (buf, s, len);
-  buf[len] = '\0';
-}
-
-
 static const char **static_shaper_list;
 
 #ifdef HB_USE_ATEXIT
diff --git a/src/hb-shape.h b/src/hb-shape.h
index 53bb845..39507ff 100644
--- a/src/hb-shape.h
+++ b/src/hb-shape.h
@@ -40,22 +40,6 @@
 HB_BEGIN_DECLS
 
 
-typedef struct hb_feature_t {
-  hb_tag_t      tag;
-  uint32_t      value;
-  unsigned int  start;
-  unsigned int  end;
-} hb_feature_t;
-
-HB_EXTERN hb_bool_t
-hb_feature_from_string (const char *str, int len,
-			hb_feature_t *feature);
-
-HB_EXTERN void
-hb_feature_to_string (hb_feature_t *feature,
-		      char *buf, unsigned int size);
-
-
 HB_EXTERN void
 hb_shape (hb_font_t           *font,
 	  hb_buffer_t         *buffer,
commit 785982bf830723552270db5649abcb9f9f0b46b1
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jan 20 19:57:27 2017 -0800

    [var] Flesh out some more

diff --git a/src/Makefile.am b/src/Makefile.am
index 8cfe4ac..d7420a0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -299,6 +299,8 @@ test_buffer_serialize_SOURCES = test-buffer-serialize.cc
 test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
 test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
 
+check: harfbuzz.def # For check-defs.sh
+
 dist_check_SCRIPTS = \
 	check-c-linkage-decls.sh \
 	check-defs.sh \
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 39015b3..cb88de8 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -99,15 +99,49 @@ struct fvar
 				  axisCount * axisSize + instanceCount * instanceSize));
   }
 
-  inline const AxisRecord * get_axes (void) const
-  { return &StructAtOffset<AxisRecord> (this, things); }
-
-  inline const InstanceRecord * get_instances (void) const
-  { return &StructAtOffset<InstanceRecord> (get_axes () + axisCount, 0); }
-
   inline unsigned int get_axis_count (void) const
   { return axisCount; }
 
+  inline bool get_axis (unsigned int index, hb_ot_var_axis_t *info) const
+  {
+    if (unlikely (index >= axisCount))
+      return false;
+
+    if (info)
+    {
+      const AxisRecord &axis = get_axes ()[index];
+      info->tag = axis.axisTag;
+      info->name_id =  axis.axisNameID;
+      info->default_value = axis.defaultValue / 65536.;
+      /* Ensure order, to simplify client math. */
+      info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.);
+      info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.);
+    }
+
+    return true;
+  }
+
+  inline unsigned int get_axis_infos (unsigned int      start_offset,
+				      unsigned int     *axes_count /* IN/OUT */,
+				      hb_ot_var_axis_t *axes_array /* OUT */) const
+  {
+    if (axes_count)
+    {
+      unsigned int count = axisCount;
+      start_offset = MIN (start_offset, count);
+
+      count -= start_offset;
+      axes_array += start_offset;
+
+      count = MIN (count, *axes_count);
+      *axes_count = count;
+
+      for (unsigned int i = 0; i < count; i++)
+	get_axis (start_offset + i, axes_array + i);
+    }
+    return axisCount;
+  }
+
   inline bool find_axis (hb_tag_t tag, unsigned int *index, hb_ot_var_axis_t *info) const
   {
     const AxisRecord *axes = get_axes ();
@@ -117,27 +151,17 @@ struct fvar
       {
         if (index)
 	  *index = i;
-	if (info)
-	{
-	  const AxisRecord &axis = axes[i];
-	  info->tag = axis.axisTag;
-	  info->name_id =  axis.axisNameID;
-	  info->default_value = axis.defaultValue / 65536.;
-	  /* Ensure order, to simplify client math. */
-	  info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.);
-	  info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.);
-	}
-        return true;
+	return get_axis (i, info);
       }
     if (index)
       *index = HB_OT_VAR_NO_AXIS_INDEX;
     return false;
   }
 
-  inline int normalize_axis_value (hb_tag_t tag, float v, unsigned int *axis_index) const
+  inline int normalize_axis_value (unsigned int axis_index, float v) const
   {
     hb_ot_var_axis_t axis;
-    if (!find_axis (tag, axis_index, &axis))
+    if (!get_axis (axis_index, &axis))
       return 0;
 
     v = MAX (MIN (v, axis.max_value), axis.min_value); /* Clamp. */
@@ -152,6 +176,13 @@ struct fvar
   }
 
   protected:
+  inline const AxisRecord * get_axes (void) const
+  { return &StructAtOffset<AxisRecord> (this, things); }
+
+  inline const InstanceRecord * get_instances (void) const
+  { return &StructAtOffset<InstanceRecord> (get_axes () + axisCount, 0); }
+
+  protected:
   FixedVersion<>version;	/* Version of the fvar table
 				 * initially set to 0x00010000u */
   Offset<>	things;		/* Offset in bytes from the beginning of the table
diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc
index c9dcb1f..d1e9725 100644
--- a/src/hb-ot-var.cc
+++ b/src/hb-ot-var.cc
@@ -43,7 +43,7 @@ _get_fvar (hb_face_t *face)
 }
 
 /*
- * OT::fvar
+ * fvar/avar
  */
 
 /**
@@ -51,6 +51,7 @@ _get_fvar (hb_face_t *face)
  * @face: #hb_face_t to test
  *
  * This function allows to verify the presence of OpenType variation data on the face.
+ * Alternatively, use hb_ot_var_get_axis_count().
  *
  * Return value: true if face has a `fvar' table and false otherwise
  *
@@ -61,3 +62,39 @@ hb_ot_var_has_data (hb_face_t *face)
 {
   return &_get_fvar (face) != &OT::Null(OT::fvar);
 }
+
+unsigned int
+hb_ot_var_get_axis_count (hb_face_t *face)
+{
+  const OT::fvar &fvar = _get_fvar (face);
+  return fvar.get_axis_count ();
+}
+
+unsigned int
+hb_ot_var_get_axes (hb_face_t        *face,
+		    unsigned int      start_offset,
+		    unsigned int     *axes_count /* IN/OUT */,
+		    hb_ot_var_axis_t *axes_array /* OUT */)
+{
+  const OT::fvar &fvar = _get_fvar (face);
+  return fvar.get_axis_infos (start_offset, axes_count, axes_array);
+}
+
+HB_EXTERN hb_bool_t
+hb_ot_var_find_axis (hb_face_t        *face,
+		     hb_tag_t          axis_tag,
+		     unsigned int     *axis_index,
+		     hb_ot_var_axis_t *axis_info)
+{
+  const OT::fvar &fvar = _get_fvar (face);
+  return fvar.find_axis (axis_tag, axis_index, axis_info);
+}
+
+HB_EXTERN int
+hb_ot_var_normalize_axis_value (hb_face_t    *face,
+				unsigned int  axis_index,
+				float         v)
+{
+  const OT::fvar &fvar = _get_fvar (face);
+  return fvar.normalize_axis_value (axis_index, v);
+}
diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h
index fd7a5aa..4023b29 100644
--- a/src/hb-ot-var.h
+++ b/src/hb-ot-var.h
@@ -62,7 +62,14 @@ hb_ot_var_has_data (hb_face_t *face);
 
 #define HB_OT_VAR_NO_AXIS_INDEX		0xFFFFFFFFu
 
-#if 0
+HB_EXTERN unsigned int
+hb_ot_var_get_axis_count (hb_face_t *face);
+
+HB_EXTERN unsigned int
+hb_ot_var_get_axes (hb_face_t        *face,
+		    unsigned int      start_offset,
+		    unsigned int     *axes_count /* IN/OUT */,
+		    hb_ot_var_axis_t *axes_array /* OUT */);
 
 HB_EXTERN hb_bool_t
 hb_ot_var_find_axis (hb_face_t        *face,
@@ -70,13 +77,13 @@ hb_ot_var_find_axis (hb_face_t        *face,
 		     unsigned int     *axis_index,
 		     hb_ot_var_axis_t *axis_info);
 
-HB_EXTERN unsigned int
-Xhb_ot_var_get_axes (hb_face_t        *face,
-		    unsigned int      start_offset,
-		    unsigned int     *axes_count /* IN/OUT */,
-		    hb_ot_var_axis_t *axes_array /* OUT */);
 
-/* TODO Add "find_axis", etc API? Are they needed at all? */
+HB_EXTERN int
+hb_ot_var_normalize_axis_value (hb_face_t    *face,
+				unsigned int  axis_index,
+				float         v);
+
+#if 0
 
 HB_EXTERN unsigned int
 Xhb_ot_var_get_named_instances (hb_face_t        *face, ... );
commit 422c0c36c80145a2d993f80d5c7d3265e3d8357a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jan 20 19:14:54 2017 -0800

    [var] Flesh out a bit

diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 8461741..39015b3 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -63,7 +63,7 @@ struct AxisRecord
     return_trace (c->check_struct (this));
   }
 
-  protected:
+  public:
   Tag		axisTag;	/* Tag identifying the design variation for the axis. */
   Fixed		minValue;	/* The minimum coordinate value for the axis. */
   Fixed		defaultValue;	/* The default coordinate value for the axis. */
@@ -89,23 +89,67 @@ struct fvar
   {
     TRACE_SANITIZE (this);
     return_trace (version.sanitize (c) &&
-		  likely (version.major == 1) /*&&
-		  mathConstants.sanitize (c, this) &&
-		  mathGlyphInfo.sanitize (c, this) &&
-		  mathVariants.sanitize (c, this)*/);
+		  likely (version.major == 1) &&
+		  c->check_struct (this) &&
+		  instanceSize >= axisCount * 4 + 4 &&
+		  axisSize <= 1024 && /* Arbitrary, just to simplify overflow checks. */
+		  instanceSize <= 1024 && /* Arbitrary, just to simplify overflow checks. */
+		  c->check_range (this, things) &&
+		  c->check_range (&StructAtOffset<char> (this, things),
+				  axisCount * axisSize + instanceCount * instanceSize));
   }
 
-#if 0
-  inline hb_position_t get_constant (hb_ot_math_constant_t  constant,
-				     hb_font_t		   *font) const
-  { return (this+mathConstants).get_value (constant, font); }
+  inline const AxisRecord * get_axes (void) const
+  { return &StructAtOffset<AxisRecord> (this, things); }
+
+  inline const InstanceRecord * get_instances (void) const
+  { return &StructAtOffset<InstanceRecord> (get_axes () + axisCount, 0); }
+
+  inline unsigned int get_axis_count (void) const
+  { return axisCount; }
 
-  inline const MathGlyphInfo &get_math_glyph_info (void) const
-  { return this+mathGlyphInfo; }
+  inline bool find_axis (hb_tag_t tag, unsigned int *index, hb_ot_var_axis_t *info) const
+  {
+    const AxisRecord *axes = get_axes ();
+    unsigned int count = get_axis_count ();
+    for (unsigned int i = 0; i < count; i++)
+      if (axes[i].axisTag == tag)
+      {
+        if (index)
+	  *index = i;
+	if (info)
+	{
+	  const AxisRecord &axis = axes[i];
+	  info->tag = axis.axisTag;
+	  info->name_id =  axis.axisNameID;
+	  info->default_value = axis.defaultValue / 65536.;
+	  /* Ensure order, to simplify client math. */
+	  info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.);
+	  info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.);
+	}
+        return true;
+      }
+    if (index)
+      *index = HB_OT_VAR_NO_AXIS_INDEX;
+    return false;
+  }
 
-  inline const MathVariants &get_math_variants (void) const
-  { return this+mathVariants; }
-#endif
+  inline int normalize_axis_value (hb_tag_t tag, float v, unsigned int *axis_index) const
+  {
+    hb_ot_var_axis_t axis;
+    if (!find_axis (tag, axis_index, &axis))
+      return 0;
+
+    v = MAX (MIN (v, axis.max_value), axis.min_value); /* Clamp. */
+
+    if (v == axis.default_value)
+      return 0;
+    else if (v < axis.default_value)
+      v = (v - axis.default_value) / (axis.default_value - axis.min_value);
+    else
+      v = (v - axis.default_value) / (axis.max_value - axis.default_value);
+    return (int) (v * 16384. + (v >= 0. ? .5 : -.5));
+  }
 
   protected:
   FixedVersion<>version;	/* Version of the fvar table
diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h
index 9d73bed..fd7a5aa 100644
--- a/src/hb-ot-var.h
+++ b/src/hb-ot-var.h
@@ -53,15 +53,23 @@ typedef struct hb_ot_var_axis_t {
   hb_tag_t tag;
   unsigned int name_id;
   float min_value;
-  float def_value;
+  float default_value;
   float max_value;
 } hb_ot_var_axis_t;
 
 HB_EXTERN hb_bool_t
 hb_ot_var_has_data (hb_face_t *face);
 
+#define HB_OT_VAR_NO_AXIS_INDEX		0xFFFFFFFFu
+
 #if 0
 
+HB_EXTERN hb_bool_t
+hb_ot_var_find_axis (hb_face_t        *face,
+		     hb_tag_t          axis_tag,
+		     unsigned int     *axis_index,
+		     hb_ot_var_axis_t *axis_info);
+
 HB_EXTERN unsigned int
 Xhb_ot_var_get_axes (hb_face_t        *face,
 		    unsigned int      start_offset,
commit b8376b10904e1772b8d34d852d1100ca7e2185e2
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jan 20 18:19:28 2017 -0800

    Minor

diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index f127066..d5f8d52 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -625,7 +625,7 @@ hb_ft_font_create (FT_Face           ft_face,
     int hbCoords[mm_var->num_axis];
     if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, coords))
     {
-      for (int i = 0; i < mm_var->num_axis; ++i)
+      for (unsigned int i = 0; i < mm_var->num_axis; ++i)
 	hbCoords[i] = coords[i] >> 2;
 
       hb_font_set_var_coords_normalized (font, hbCoords, mm_var->num_axis);
commit f2e73d37e77ccea8b948d1ecf5f11e7a699386dc
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jan 20 17:42:18 2017 -0800

    [var] Remove over-optimization

diff --git a/src/hb-font.cc b/src/hb-font.cc
index 2935c4b..b91a35b 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1552,10 +1552,6 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
   if (font->immutable)
     return;
 
-  /* Skip tail zero entries. */
-  while (coords_length && !coords[coords_length - 1])
-    coords_length--;
-
   int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : NULL;
   if (unlikely (coords_length && !copy))
     return;
commit 469926cc45760cb681d44e5757b18b9bdd736189
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jan 20 17:40:46 2017 -0800

    [var] Change double to float in API

diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h
index 679feb9..9d73bed 100644
--- a/src/hb-ot-var.h
+++ b/src/hb-ot-var.h
@@ -52,9 +52,9 @@ HB_BEGIN_DECLS
 typedef struct hb_ot_var_axis_t {
   hb_tag_t tag;
   unsigned int name_id;
-  double min_value;
-  double def_value;
-  double max_value;
+  float min_value;
+  float def_value;
+  float max_value;
 } hb_ot_var_axis_t;
 
 HB_EXTERN hb_bool_t
commit 55d42fd667b9c34a1109bb850bf2ea7322c01040
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jan 19 19:35:48 2017 -0800

    Start adding hb-ot-var.h and implementation
    
    Supports enumerating variation axes, normalizing values, etc.

diff --git a/src/Makefile.sources b/src/Makefile.sources
index b75ec0c..279bc46 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -108,6 +108,8 @@ HB_OT_sources = \
 	hb-ot-shape-fallback-private.hh \
 	hb-ot-shape-fallback.cc \
 	hb-ot-shape-private.hh \
+	hb-ot-var.cc \
+	hb-ot-var-fvar-table.hh \
 	$(NULL)
 
 HB_OT_headers = \
@@ -117,6 +119,7 @@ HB_OT_headers = \
 	hb-ot-math.h \
 	hb-ot-shape.h \
 	hb-ot-tag.h \
+	hb-ot-var.h \
 	$(NULL)
 
 # Optional Sources and Headers with external deps
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index 1c398e9..8c348be 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -126,6 +126,8 @@ namespace OT {
   struct GSUB;
   struct GPOS;
   struct MATH;
+  struct fvar;
+  struct avar;
 }
 
 struct hb_ot_layout_lookup_accelerator_t
@@ -158,7 +160,11 @@ struct hb_ot_layout_t
   const struct OT::GDEF *gdef;
   const struct OT::GSUB *gsub;
   const struct OT::GPOS *gpos;
+
+  /* TODO Move the following out of this struct. */
   OT::hb_lazy_table_loader_t<struct OT::MATH> math;
+  OT::hb_lazy_table_loader_t<struct OT::fvar> fvar;
+  OT::hb_lazy_table_loader_t<struct OT::avar> avar;
 
   unsigned int gsub_lookup_count;
   unsigned int gpos_lookup_count;
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index d165402..d8d6284 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -61,6 +61,8 @@ _hb_ot_layout_create (hb_face_t *face)
   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
 
   layout->math.init (face);
+  layout->fvar.init (face);
+  layout->avar.init (face);
 
   {
     /*
@@ -181,6 +183,8 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
   hb_blob_destroy (layout->gpos_blob);
 
   layout->math.fini ();
+  layout->fvar.fini ();
+  layout->avar.fini ();
 
   free (layout);
 }
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
new file mode 100644
index 0000000..8461741
--- /dev/null
+++ b/src/hb-ot-var-fvar-table.hh
@@ -0,0 +1,133 @@
+/*
+ * Copyright © 2017  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_VAR_FVAR_TABLE_HH
+#define HB_OT_VAR_FVAR_TABLE_HH
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-var.h"
+
+namespace OT {
+
+
+struct InstanceRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  c->check_array (coordinates, coordinates[0].static_size, axis_count));
+  }
+
+  protected:
+  USHORT	subfamilyNameID;/* The name ID for entries in the 'name' table
+				 * that provide subfamily names for this instance. */
+  USHORT	reserved;	/* Reserved for future use — set to 0. */
+  Fixed		coordinates[VAR];/* The coordinates array for this instance. */
+  //USHORT	postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
+  //				  * table that provide PostScript names for this
+  //				  * instance. */
+
+  public:
+  DEFINE_SIZE_ARRAY (4, coordinates);
+};
+
+struct AxisRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  Tag		axisTag;	/* Tag identifying the design variation for the axis. */
+  Fixed		minValue;	/* The minimum coordinate value for the axis. */
+  Fixed		defaultValue;	/* The default coordinate value for the axis. */
+  Fixed		maxValue;	/* The maximum coordinate value for the axis. */
+  USHORT	reserved;	/* Reserved for future use — set to 0. */
+  USHORT	axisNameID;	/* The name ID for entries in the 'name' table that
+				 * provide a display name for this axis. */
+
+  public:
+  DEFINE_SIZE_STATIC (20);
+};
+
+
+/*
+ * fvar — Font Variations Table
+ */
+
+struct fvar
+{
+  static const hb_tag_t tableTag	= HB_OT_TAG_fvar;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  likely (version.major == 1) /*&&
+		  mathConstants.sanitize (c, this) &&
+		  mathGlyphInfo.sanitize (c, this) &&
+		  mathVariants.sanitize (c, this)*/);
+  }
+
+#if 0
+  inline hb_position_t get_constant (hb_ot_math_constant_t  constant,
+				     hb_font_t		   *font) const
+  { return (this+mathConstants).get_value (constant, font); }
+
+  inline const MathGlyphInfo &get_math_glyph_info (void) const
+  { return this+mathGlyphInfo; }
+
+  inline const MathVariants &get_math_variants (void) const
+  { return this+mathVariants; }
+#endif
+
+  protected:
+  FixedVersion<>version;	/* Version of the fvar table
+				 * initially set to 0x00010000u */
+  Offset<>	things;		/* Offset in bytes from the beginning of the table
+				 * to the start of the AxisRecord array. */
+  USHORT	reserved;	/* This field is permanently reserved. Set to 2. */
+  USHORT	axisCount;	/* The number of variation axes in the font (the
+				 * number of records in the axes array). */
+  USHORT	axisSize;	/* The size in bytes of each VariationAxisRecord —
+				 * set to 20 (0x0014) for this version. */
+  USHORT	instanceCount;	/* The number of named instances defined in the font
+				 * (the number of records in the instances array). */
+  USHORT	instanceSize;	/* The size in bytes of each InstanceRecord — set
+				 * to either axisCount * sizeof(Fixed) + 4, or to
+				 * axisCount * sizeof(Fixed) + 6. */
+
+  public:
+  DEFINE_SIZE_STATIC (16);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_VAR_FVAR_TABLE_HH */
diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc
new file mode 100644
index 0000000..c9dcb1f
--- /dev/null
+++ b/src/hb-ot-var.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2017  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-open-type-private.hh"
+
+#include "hb-ot-layout-private.hh"
+#include "hb-ot-var-fvar-table.hh"
+#include "hb-ot-var.h"
+
+HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
+
+static inline const OT::fvar&
+_get_fvar (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::fvar);
+
+  hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
+
+  return *(layout->fvar.get ());
+}
+
+/*
+ * OT::fvar
+ */
+
+/**
+ * hb_ot_var_has_data:
+ * @face: #hb_face_t to test
+ *
+ * This function allows to verify the presence of OpenType variation data on the face.
+ *
+ * Return value: true if face has a `fvar' table and false otherwise
+ *
+ * Since: 1.4.2
+ **/
+hb_bool_t
+hb_ot_var_has_data (hb_face_t *face)
+{
+  return &_get_fvar (face) != &OT::Null(OT::fvar);
+}
diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h
new file mode 100644
index 0000000..679feb9
--- /dev/null
+++ b/src/hb-ot-var.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2017  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_VAR_H
+#define HB_OT_VAR_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+
+#define HB_OT_TAG_fvar HB_TAG('f','v','a','r')
+#define HB_OT_TAG_avar HB_TAG('a','v','a','r')
+
+
+/*
+ * fvar / avar
+ */
+
+/**
+ * hb_ot_var_axis_t:
+ *
+ * Since: 1.4.2
+ */
+typedef struct hb_ot_var_axis_t {
+  hb_tag_t tag;
+  unsigned int name_id;
+  double min_value;
+  double def_value;
+  double max_value;
+} hb_ot_var_axis_t;
+
+HB_EXTERN hb_bool_t
+hb_ot_var_has_data (hb_face_t *face);
+
+#if 0
+
+HB_EXTERN unsigned int
+Xhb_ot_var_get_axes (hb_face_t        *face,
+		    unsigned int      start_offset,
+		    unsigned int     *axes_count /* IN/OUT */,
+		    hb_ot_var_axis_t *axes_array /* OUT */);
+
+/* TODO Add "find_axis", etc API? Are they needed at all? */
+
+HB_EXTERN unsigned int
+Xhb_ot_var_get_named_instances (hb_face_t        *face, ... );
+
+#endif
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_VAR_H */
diff --git a/src/hb-ot.h b/src/hb-ot.h
index 113e37b..2120a3e 100644
--- a/src/hb-ot.h
+++ b/src/hb-ot.h
@@ -35,6 +35,7 @@
 #include "hb-ot-math.h"
 #include "hb-ot-tag.h"
 #include "hb-ot-shape.h"
+#include "hb-ot-var.h"
 
 HB_BEGIN_DECLS
 
commit 272b5115325b785e92ff5500d4bfc3a67490b6f8
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jan 19 19:33:07 2017 -0800

    Minor

diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc
index 40414eb..ec8df2c 100644
--- a/src/hb-ot-math.cc
+++ b/src/hb-ot-math.cc
@@ -49,10 +49,9 @@ _get_math (hb_face_t *face)
  * @face: #hb_face_t to test
  *
  * This function allows to verify the presence of an OpenType MATH table on the
- * face. If so, such a table will be loaded into memory and sanitized. You can
- * then safely call other functions for math layout and shaping.
+ * face.
  *
- * Return value: #TRUE if face has a MATH table and #FALSE otherwise
+ * Return value: true if face has a MATH table, false otherwise
  *
  * Since: 1.3.3
  **/
@@ -124,7 +123,7 @@ hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
  * @font: a #hb_font_t to test
  * @glyph: a glyph index to test
  *
- * Return value: #TRUE if the glyph is an extended shape and #FALSE otherwise
+ * Return value: true if the glyph is an extended shape, false otherwise
  *
  * Since: 1.3.3
  **/
commit a8a5e81a52f56f5f8bf975dc4d9f79bede5d895b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jan 19 16:55:04 2017 -0800

    [test-ot-math] Add test with nil face/font

diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
index b9fcb65..0ca5566 100644
--- a/test/api/test-ot-math.c
+++ b/test/api/test-ot-math.c
@@ -97,6 +97,14 @@ test_has_data (void)
   g_assert(hb_ot_math_has_data (hb_face)); // MATH table available
   closeFont();
 
+  hb_face = hb_face_get_empty ();
+  hb_font = hb_font_create (hb_face);
+  g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available
+
+  hb_font = hb_font_get_empty ();
+  hb_face = hb_font_get_face (hb_font);
+  g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available
+
   cleanupFreeType();
 }
 
commit 331d07bd40a3d9ff30db5cdf85fdc4f10f0fcb99
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jan 19 16:51:36 2017 -0800

    Minor

diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
index e7a6fc8..b9fcb65 100644
--- a/test/api/test-ot-math.c
+++ b/test/api/test-ot-math.c
@@ -79,6 +79,9 @@ closeFont (void)
   hb_face_destroy (hb_face);
   hb_font_destroy (hb_font);
   FT_Done_Face (ft_face);
+  hb_face = NULL;
+  hb_font = NULL;
+  ft_face = NULL;
 }
 
 static void
commit b5ecf1bfa459a755e36bc4c7f545c7f803b7d016
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jan 19 16:50:29 2017 -0800

    Fix warnings

diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
index cfac109..e7a6fc8 100644
--- a/test/api/test-ot-math.c
+++ b/test/api/test-ot-math.c
@@ -401,6 +401,11 @@ static void
 test_get_glyph_variants (void)
 {
   hb_codepoint_t glyph;
+  hb_ot_math_glyph_variant_t variants[20];
+  unsigned variantsSize = sizeof (variants) / sizeof (variants[0]);
+  unsigned int count;
+  unsigned int offset = 0;
+
   initFreeType();
 
   openFont("fonts/MathTestFontEmpty.otf");
@@ -464,10 +469,6 @@ test_get_glyph_variants (void)
                                                  NULL), ==, 0);
 
   g_assert(hb_font_get_glyph_from_name (hb_font, "arrowleft", -1, &glyph));
-  hb_ot_math_glyph_variant_t variants[20];
-  unsigned variantsSize = sizeof (variants) / sizeof (variants[0]);
-  unsigned int count;
-  unsigned int offset = 0;
   do {
     count = variantsSize;
     hb_ot_math_get_glyph_variants (hb_font,
@@ -524,6 +525,11 @@ static void
 test_get_glyph_assembly (void)
 {
   hb_codepoint_t glyph;
+  hb_ot_math_glyph_part_t parts[20];
+  unsigned partsSize = sizeof (parts) / sizeof (parts[0]);
+  unsigned int count;
+  unsigned int offset = 0;
+
   initFreeType();
 
   openFont("fonts/MathTestFontEmpty.otf");
@@ -591,10 +597,6 @@ test_get_glyph_assembly (void)
                                                  NULL), ==, 0);
 
   g_assert(hb_font_get_glyph_from_name (hb_font, "arrowright", -1, &glyph));
-  hb_ot_math_glyph_part_t parts[20];
-  unsigned partsSize = sizeof (parts) / sizeof (parts[0]);
-  unsigned int count;
-  unsigned int offset = 0;
   do {
     count = partsSize;
     hb_ot_math_get_glyph_assembly (hb_font,
commit 2f2ceee1853649d1b2ad4315a38cd9c07659932a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jan 19 16:48:01 2017 -0800

    Minor

diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
index 049656a..cfac109 100644
--- a/test/api/test-ot-math.c
+++ b/test/api/test-ot-math.c
@@ -70,12 +70,13 @@ openFont(const char* fontFile)
   if ((ft_error = FT_Set_Char_Size (ft_face, 2000, 1000, 0, 0)))
     abort();
   hb_font = hb_ft_font_create (ft_face, NULL);
-  hb_face = hb_ft_face_create_cached(ft_face);
+  hb_face = hb_face_reference (hb_font_get_face (hb_font));
 }
 
 static inline void
 closeFont (void)
 {
+  hb_face_destroy (hb_face);
   hb_font_destroy (hb_font);
   FT_Done_Face (ft_face);
 }


More information about the HarfBuzz mailing list