[GX] Hook up feature variations

Shape-plan caching is not implemented.
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index 507581b..e857dfa 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -288,7 +288,9 @@
 hb_coretext_shaper_shape_plan_data_t *
 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
 					     const hb_feature_t *user_features HB_UNUSED,
-					     unsigned int        num_user_features HB_UNUSED)
+					     unsigned int        num_user_features HB_UNUSED,
+					     const int          *coords HB_UNUSED,
+					     unsigned int        num_coords HB_UNUSED)
 {
   return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
@@ -1280,7 +1282,9 @@
 hb_coretext_aat_shaper_shape_plan_data_t *
 _hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
 					     const hb_feature_t *user_features HB_UNUSED,
-					     unsigned int        num_user_features HB_UNUSED)
+					     unsigned int        num_user_features HB_UNUSED,
+					     const int          *coords HB_UNUSED,
+					     unsigned int        num_coords HB_UNUSED)
 {
   return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index 76482ac..d26b298 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -258,8 +258,10 @@
 
 hb_directwrite_shaper_shape_plan_data_t *
 _hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
-               const hb_feature_t *user_features HB_UNUSED,
-               unsigned int        num_user_features HB_UNUSED)
+					       const hb_feature_t *user_features HB_UNUSED,
+					       unsigned int        num_user_features HB_UNUSED,
+					       const int          *coords HB_UNUSED,
+					       unsigned int        num_coords HB_UNUSED)
 {
   return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index e2ad240..ac6d4b0 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -73,7 +73,9 @@
 hb_fallback_shaper_shape_plan_data_t *
 _hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
 					    const hb_feature_t *user_features HB_UNUSED,
-					    unsigned int        num_user_features HB_UNUSED)
+					    unsigned int        num_user_features HB_UNUSED,
+					    const int          *coords HB_UNUSED,
+					    unsigned int        num_coords HB_UNUSED)
 {
   return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
diff --git a/src/hb-font.cc b/src/hb-font.cc
index f12dfb5..2935c4b 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1253,8 +1253,7 @@
   hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
 
-  if (font->coords)
-    free (font->coords);
+  free (font->coords);
 
   free (font);
 }
@@ -1561,8 +1560,7 @@
   if (unlikely (coords_length && !copy))
     return;
 
-  if (font->coords)
-    free (font->coords);
+  free (font->coords);
 
   if (coords_length)
     memcpy (copy, coords, coords_length * sizeof (coords[0]));
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index c32318d..a2d90db 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -195,7 +195,9 @@
 hb_graphite2_shaper_shape_plan_data_t *
 _hb_graphite2_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
 					     const hb_feature_t *user_features HB_UNUSED,
-					     unsigned int        num_user_features HB_UNUSED)
+					     unsigned int        num_user_features HB_UNUSED,
+					     const int          *coords HB_UNUSED,
+					     unsigned int        num_coords HB_UNUSED)
 {
   return (hb_graphite2_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index fc5ce66..0395c9c 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -176,7 +176,9 @@
   inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
   { add_pause (1, pause_func); }
 
-  HB_INTERNAL void compile (hb_ot_map_t &m);
+  HB_INTERNAL void compile (hb_ot_map_t  &m,
+			    const int    *coords,
+			    unsigned int  num_coords);
 
   inline void finish (void) {
     feature_infos.finish ();
@@ -188,12 +190,13 @@
 
   private:
 
-  HB_INTERNAL void add_lookups (hb_ot_map_t   &m,
-				hb_face_t     *face,
-				unsigned int   table_index,
-				unsigned int   feature_index,
-				hb_mask_t      mask,
-				bool           auto_zwj);
+  HB_INTERNAL void add_lookups (hb_ot_map_t  &m,
+				hb_face_t    *face,
+				unsigned int  table_index,
+				unsigned int  feature_index,
+				unsigned int  variations_index,
+				hb_mask_t     mask,
+				bool          auto_zwj);
 
   struct feature_info_t {
     hb_tag_t tag;
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 9cd3a44..9b331d5 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -83,6 +83,7 @@
 				  hb_face_t    *face,
 				  unsigned int  table_index,
 				  unsigned int  feature_index,
+				  unsigned int  variations_index,
 				  hb_mask_t     mask,
 				  bool          auto_zwj)
 {
@@ -95,11 +96,12 @@
   offset = 0;
   do {
     len = ARRAY_LENGTH (lookup_indices);
-    hb_ot_layout_feature_get_lookups (face,
-				      table_tags[table_index],
-				      feature_index,
-				      offset, &len,
-				      lookup_indices);
+    hb_ot_layout_feature_with_variations_get_lookups (face,
+						      table_tags[table_index],
+						      feature_index,
+						      variations_index,
+						      offset, &len,
+						      lookup_indices);
 
     for (unsigned int i = 0; i < len; i++)
     {
@@ -130,7 +132,9 @@
 }
 
 void
-hb_ot_map_builder_t::compile (hb_ot_map_t &m)
+hb_ot_map_builder_t::compile (hb_ot_map_t  &m,
+			      const int    *coords,
+			      unsigned int  num_coords)
 {
   m.global_mask = 1;
 
@@ -264,6 +268,13 @@
   {
     /* Collect lookup indices for features */
 
+    unsigned int variations_index;
+    hb_ot_layout_table_find_feature_variations (face,
+						table_tags[table_index],
+						coords,
+						num_coords,
+						&variations_index);
+
     unsigned int stage_index = 0;
     unsigned int last_num_lookups = 0;
     for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
@@ -272,6 +283,7 @@
 	  required_feature_stage[table_index] == stage)
 	add_lookups (m, face, table_index,
 		     required_feature_index[table_index],
+		     variations_index,
 		     1 /* mask */,
 		     true /* auto_zwj */);
 
@@ -279,6 +291,7 @@
         if (m.features[i].stage[table_index] == stage)
 	  add_lookups (m, face, table_index,
 		       m.features[i].index[table_index],
+		       variations_index,
 		       m.features[i].mask,
 		       m.features[i].auto_zwj);
 
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 54ac2c3..594e54c 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -77,11 +77,13 @@
 			 map (face, &props) {}
   ~hb_ot_shape_planner_t (void) { map.finish (); }
 
-  inline void compile (hb_ot_shape_plan_t &plan)
+  inline void compile (hb_ot_shape_plan_t &plan,
+		       const int          *coords,
+		       unsigned int        num_coords)
   {
     plan.props = props;
     plan.shaper = shaper;
-    map.compile (plan.map);
+    map.compile (plan.map, coords, num_coords);
 
     plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
     plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 7811cb7..6c78b47 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -163,7 +163,9 @@
 hb_ot_shaper_shape_plan_data_t *
 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
 				      const hb_feature_t *user_features,
-				      unsigned int        num_user_features)
+				      unsigned int        num_user_features,
+				      const int          *coords,
+				      unsigned int        num_coords)
 {
   hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
   if (unlikely (!plan))
@@ -173,9 +175,10 @@
 
   planner.shaper = hb_ot_shape_complex_categorize (&planner);
 
-  hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
+  hb_ot_shape_collect_features (&planner, &shape_plan->props,
+				user_features, num_user_features);
 
-  planner.compile (*plan);
+  planner.compile (*plan, coords, num_coords);
 
   if (plan->shaper->data_create) {
     plan->data = plan->shaper->data_create (plan);
diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan-private.hh
index 607da5e..aa0413a 100644
--- a/src/hb-shape-plan-private.hh
+++ b/src/hb-shape-plan-private.hh
@@ -47,12 +47,17 @@
   hb_feature_t *user_features;
   unsigned int num_user_features;
 
+  int *coords;
+  unsigned int num_coords;
+
   struct hb_shaper_data_t shaper_data;
 };
 
 #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \
-	, const hb_feature_t            *user_features \
-	, unsigned int                   num_user_features
+	, const hb_feature_t *user_features \
+	, unsigned int        num_user_features \
+	, const int          *coords \
+	, unsigned int        num_coords
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 87231fb..600faae 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -46,11 +46,14 @@
 hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
 		    const hb_feature_t *user_features,
 		    unsigned int        num_user_features,
+		    const int          *coords,
+		    unsigned int        num_coords,
 		    const char * const *shaper_list)
 {
   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
-		  "num_features=%d shaper_list=%p",
+		  "num_features=%d num_coords=%d shaper_list=%p",
 		  num_user_features,
+		  num_coords,
 		  shaper_list);
 
   const hb_shaper_pair_t *shapers = _hb_shapers_get ();
@@ -59,7 +62,9 @@
 	HB_STMT_START { \
 	  if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
 	    HB_SHAPER_DATA (shaper, shape_plan) = \
-	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
+	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \
+							       user_features, num_user_features, \
+							       coords, num_coords); \
 	    shape_plan->shaper_func = _hb_##shaper##_shape; \
 	    shape_plan->shaper_name = #shaper; \
 	    return; \
@@ -115,14 +120,31 @@
 		      unsigned int                   num_user_features,
 		      const char * const            *shaper_list)
 {
+  return hb_shape_plan_create2 (face, props,
+				user_features, num_user_features,
+				NULL, 0,
+				shaper_list);
+}
+
+hb_shape_plan_t *
+hb_shape_plan_create2 (hb_face_t                     *face,
+		       const hb_segment_properties_t *props,
+		       const hb_feature_t            *user_features,
+		       unsigned int                   num_user_features,
+		       const int                     *orig_coords,
+		       unsigned int                   num_coords,
+		       const char * const            *shaper_list)
+{
   DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
-		  "face=%p num_features=%d shaper_list=%p",
+		  "face=%p num_features=%d num_coords=%d shaper_list=%p",
 		  face,
 		  num_user_features,
+		  num_coords,
 		  shaper_list);
 
   hb_shape_plan_t *shape_plan;
   hb_feature_t *features = NULL;
+  int *coords = NULL;
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
@@ -130,7 +152,14 @@
     return hb_shape_plan_get_empty ();
   if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
     return hb_shape_plan_get_empty ();
-  if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
+  if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int))))
+  {
+    free (features);
+    return hb_shape_plan_get_empty ();
+  }
+  if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
+  {
+    free (coords);
     free (features);
     return hb_shape_plan_get_empty ();
   }
@@ -145,8 +174,15 @@
   shape_plan->user_features = features;
   if (num_user_features)
     memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
+  shape_plan->num_coords = num_coords;
+  shape_plan->coords = coords;
+  if (num_coords)
+    memcpy (coords, orig_coords, num_coords * sizeof (int));
 
-  hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
+  hb_shape_plan_plan (shape_plan,
+		      user_features, num_user_features,
+		      coords, num_coords,
+		      shaper_list);
 
   return shape_plan;
 }
@@ -176,6 +212,9 @@
     NULL, /* user_features */
     0,    /* num_user_featurs */
 
+    NULL, /* coords */
+    0,    /* num_coords */
+
     {
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
 #include "hb-shaper-list.hh"
@@ -220,6 +259,7 @@
 #undef HB_SHAPER_IMPLEMENT
 
   free (shape_plan->user_features);
+  free (shape_plan->coords);
 
   free (shape_plan);
 }
@@ -351,6 +391,8 @@
   const char * const            *shaper_list;
   const hb_feature_t            *user_features;
   unsigned int                   num_user_features;
+  const int                     *coords;
+  unsigned int                   num_coords;
   hb_shape_func_t               *shaper_func;
 };
 
@@ -358,12 +400,26 @@
 hb_shape_plan_user_features_match (const hb_shape_plan_t          *shape_plan,
 				   const hb_shape_plan_proposal_t *proposal)
 {
-  if (proposal->num_user_features != shape_plan->num_user_features) return false;
+  if (proposal->num_user_features != shape_plan->num_user_features)
+    return false;
   for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
     if (proposal->user_features[i].tag   != shape_plan->user_features[i].tag   ||
         proposal->user_features[i].value != shape_plan->user_features[i].value ||
         proposal->user_features[i].start != shape_plan->user_features[i].start ||
-        proposal->user_features[i].end   != shape_plan->user_features[i].end) return false;
+        proposal->user_features[i].end   != shape_plan->user_features[i].end)
+      return false;
+  return true;
+}
+
+static inline hb_bool_t
+hb_shape_plan_coords_match (const hb_shape_plan_t          *shape_plan,
+			    const hb_shape_plan_proposal_t *proposal)
+{
+  if (proposal->num_coords != shape_plan->num_coords)
+    return false;
+  for (unsigned int i = 0, n = proposal->num_coords; i < n; i++)
+    if (proposal->coords[i] != shape_plan->coords[i])
+      return false;
   return true;
 }
 
@@ -373,6 +429,7 @@
 {
   return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
 	 hb_shape_plan_user_features_match (shape_plan, proposal) &&
+	 hb_shape_plan_coords_match (shape_plan, proposal) &&
 	 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
 	  (shape_plan->shaper_func == proposal->shaper_func));
 }
@@ -389,6 +446,13 @@
   return false;
 }
 
+static inline hb_bool_t
+hb_coords_present (const int *coords,
+		   unsigned int num_coords)
+{
+  return num_coords != 0;
+}
+
 /**
  * hb_shape_plan_create_cached:
  * @face: 
@@ -410,6 +474,21 @@
 			     unsigned int                   num_user_features,
 			     const char * const            *shaper_list)
 {
+  return hb_shape_plan_create_cached2 (face, props,
+				       user_features, num_user_features,
+				       NULL, 0,
+				       shaper_list);
+}
+
+hb_shape_plan_t *
+hb_shape_plan_create_cached2 (hb_face_t                     *face,
+			      const hb_segment_properties_t *props,
+			      const hb_feature_t            *user_features,
+			      unsigned int                   num_user_features,
+			      const int                     *coords,
+			      unsigned int                   num_coords,
+			      const char * const            *shaper_list)
+{
   DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
 		  "face=%p num_features=%d shaper_list=%p",
 		  face,
@@ -456,16 +535,21 @@
 
   /* Not found. */
 
-  hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
+						       user_features, num_user_features,
+						       coords, num_coords,
+						       shaper_list);
 
   /* Don't add to the cache if face is inert. */
   if (unlikely (hb_object_is_inert (face)))
     return shape_plan;
 
   /* Don't add the plan to the cache if there were user features with non-global ranges */
-
   if (hb_non_global_user_features_present (user_features, num_user_features))
     return shape_plan;
+  /* Don't add the plan to the cache if there were variation coordinates XXX Fix me. */
+  if (hb_coords_present (coords, num_coords))
+    return shape_plan;
 
   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
   if (unlikely (!node))
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
index aa5e0c7..b62ae7c 100644
--- a/src/hb-shape-plan.h
+++ b/src/hb-shape-plan.h
@@ -53,6 +53,25 @@
 			     const char * const            *shaper_list);
 
 HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_create2 (hb_face_t                     *face,
+		       const hb_segment_properties_t *props,
+		       const hb_feature_t            *user_features,
+		       unsigned int                   num_user_features,
+		       const int                     *coords,
+		       unsigned int                   num_coords,
+		       const char * const            *shaper_list);
+
+HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_create_cached2 (hb_face_t                     *face,
+			      const hb_segment_properties_t *props,
+			      const hb_feature_t            *user_features,
+			      unsigned int                   num_user_features,
+			      const int                     *coords,
+			      unsigned int                   num_coords,
+			      const char * const            *shaper_list);
+
+
+HB_EXTERN hb_shape_plan_t *
 hb_shape_plan_get_empty (void);
 
 HB_EXTERN hb_shape_plan_t *
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 41a4fc5..706f144 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -373,7 +373,10 @@
 	       unsigned int        num_features,
 	       const char * const *shaper_list)
 {
-  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props,
+							      features, num_features,
+							      font->coords, font->num_coords,
+							      shaper_list);
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
   hb_shape_plan_destroy (shape_plan);
 
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 07007a6..6e4db01 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -587,7 +587,9 @@
 hb_uniscribe_shaper_shape_plan_data_t *
 _hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
 					     const hb_feature_t *user_features HB_UNUSED,
-					     unsigned int        num_user_features HB_UNUSED)
+					     unsigned int        num_user_features HB_UNUSED,
+					     const int          *coords HB_UNUSED,
+					     unsigned int        num_coords HB_UNUSED)
 {
   return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }