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-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-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 @@
   struct GSUB;
   struct GPOS;
   struct MATH;
+  struct fvar;
+  struct avar;
 }
 
 struct hb_ot_layout_lookup_accelerator_t
@@ -158,7 +160,11 @@
   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 @@
   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_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