[HarfBuzz] harfbuzz: Branch 'opentype-gx' - 11 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Sat Sep 10 11:52:49 UTC 2016


 src/hb-coretext.cc                   |    8 -
 src/hb-directwrite.cc                |    6 
 src/hb-fallback-shape.cc             |    4 
 src/hb-font-private.hh               |    3 
 src/hb-font.cc                       |   23 +--
 src/hb-graphite2.cc                  |    4 
 src/hb-ot-layout-common-private.hh   |  216 +++++++++++++++++++++++++++++++++--
 src/hb-ot-layout-gdef-table.hh       |   15 +-
 src/hb-ot-layout-gpos-table.hh       |    4 
 src/hb-ot-layout-gsub-table.hh       |    2 
 src/hb-ot-layout-gsubgpos-private.hh |   30 ++++
 src/hb-ot-layout.cc                  |   43 ++++++
 src/hb-ot-layout.h                   |   19 +++
 src/hb-ot-map-private.hh             |   18 +-
 src/hb-ot-map.cc                     |  111 ++++++++++-------
 src/hb-ot-shape-private.hh           |    6 
 src/hb-ot-shape.cc                   |    9 -
 src/hb-shape-plan-private.hh         |    9 +
 src/hb-shape-plan.cc                 |  102 +++++++++++++++-
 src/hb-shape-plan.h                  |   19 +++
 src/hb-shape.cc                      |    5 
 src/hb-uniscribe.cc                  |    4 
 22 files changed, 533 insertions(+), 127 deletions(-)

New commits:
commit 647bfafee88921845babc538b9f2880955c36df1
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 04:52:34 2016 -0700

    [GX] Make FeatureVariations actually work
    
    Yay!!!!

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index cdf43bf..971c95a 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1417,17 +1417,12 @@ struct ConditionSet
 
 struct FeatureTableSubstitutionRecord
 {
-  inline const Feature *find_substitute (unsigned int feature_index) const
-  {
-    if (featureIndex == feature_index)
-      return &(this+feature);
-    return NULL;
-  }
+  friend struct FeatureTableSubstitution;
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && feature.sanitize (c, this));
+    return_trace (c->check_struct (this) && feature.sanitize (c, base));
   }
 
   protected:
@@ -1444,9 +1439,9 @@ struct FeatureTableSubstitution
     unsigned int count = substitutions.len;
     for (unsigned int i = 0; i < count; i++)
     {
-      const Feature *feature = (this+substitutions.array[i]).find_substitute (feature_index);
-      if (feature)
-        return feature;
+      const FeatureTableSubstitutionRecord &record = substitutions.array[i];
+      if (record.featureIndex == feature_index)
+	return &(this+record.feature);
     }
     return NULL;
   }
@@ -1461,7 +1456,7 @@ struct FeatureTableSubstitution
 
   protected:
   FixedVersion<>	version;	/* Version--0x00010000u */
-  OffsetArrayOf<FeatureTableSubstitutionRecord, ULONG>
+  ArrayOf<FeatureTableSubstitutionRecord>
 			substitutions;
   public:
   DEFINE_SIZE_ARRAY (6, substitutions);
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index adea32f..b90af9c 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -2281,7 +2281,8 @@ struct GSUBGPOS
     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
 	version.to_int () >= 0x00010001u)
     {
-      const Feature *feature = (this+featureVars).find_substitute (variations_index, feature_index);
+      const Feature *feature = (this+featureVars).find_substitute (variations_index,
+								   feature_index);
       if (feature)
         return *feature;
     }
commit 4c482a134244e6fe9a1d37286cadc8b394636630
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 03:57:24 2016 -0700

    [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 @@ struct hb_coretext_shaper_shape_plan_data_t {};
 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 @@ struct hb_coretext_aat_shaper_shape_plan_data_t {};
 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 @@ struct hb_directwrite_shaper_shape_plan_data_t {};
 
 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 @@ struct hb_fallback_shaper_shape_plan_data_t {};
 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_font_destroy (hb_font_t *font)
   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 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
   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 @@ struct hb_graphite2_shaper_shape_plan_data_t {};
 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 @@ struct hb_ot_map_builder_t
   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 @@ struct hb_ot_map_builder_t
 
   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_ot_map_builder_t::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)
 {
@@ -95,11 +96,12 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t  &m,
   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::add_pause (unsigned int table_index, hb_ot_map_t::paus
 }
 
 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 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
   {
     /* 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 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
 	  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 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
         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 @@ struct hb_ot_shape_planner_t
 			 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_font_data_destroy (hb_ot_shaper_font_data_t *data)
 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 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
 
   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 @@ struct hb_shape_plan_t
   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 @@ static void
 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_shape_plan_plan (hb_shape_plan_t    *shape_plan,
 	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 @@ hb_shape_plan_create (hb_face_t                     *face,
 		      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 @@ hb_shape_plan_create (hb_face_t                     *face,
     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 @@ hb_shape_plan_create (hb_face_t                     *face,
   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 @@ hb_shape_plan_get_empty (void)
     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 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
 #undef HB_SHAPER_IMPLEMENT
 
   free (shape_plan->user_features);
+  free (shape_plan->coords);
 
   free (shape_plan);
 }
@@ -351,6 +391,8 @@ struct hb_shape_plan_proposal_t
   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 @@ static inline hb_bool_t
 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 @@ hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
 {
   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 @@ hb_non_global_user_features_present (const hb_feature_t *user_features,
   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 @@ hb_shape_plan_create_cached (hb_face_t                     *face,
 			     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 @@ retry:
 
   /* 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 @@ hb_shape_plan_create_cached (hb_face_t                     *face,
 			     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 @@ hb_shape_full (hb_font_t          *font,
 	       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 @@ struct hb_uniscribe_shaper_shape_plan_data_t {};
 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;
 }
commit cd1311aa217777b1f05ca4c1ade5f6230d69ff65
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 03:53:11 2016 -0700

    [GX] Add hb_ot_layout_feature_with_variations_get_lookups()

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index e67a514..cdf43bf 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1417,6 +1417,13 @@ struct ConditionSet
 
 struct FeatureTableSubstitutionRecord
 {
+  inline const Feature *find_substitute (unsigned int feature_index) const
+  {
+    if (featureIndex == feature_index)
+      return &(this+feature);
+    return NULL;
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1432,6 +1439,18 @@ struct FeatureTableSubstitutionRecord
 
 struct FeatureTableSubstitution
 {
+  inline const Feature *find_substitute (unsigned int feature_index) const
+  {
+    unsigned int count = substitutions.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      const Feature *feature = (this+substitutions.array[i]).find_substitute (feature_index);
+      if (feature)
+        return feature;
+    }
+    return NULL;
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1470,6 +1489,8 @@ struct FeatureVariationRecord
 
 struct FeatureVariations
 {
+  static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;
+
   inline bool find_index (const int *coords, unsigned int coord_len,
 			  unsigned int *index) const
   {
@@ -1483,10 +1504,17 @@ struct FeatureVariations
 	return true;
       }
     }
-    *index = 0xFFFFFFFF;
+    *index = NOT_FOUND_INDEX;
     return false;
   }
 
+  inline const Feature *find_substitute (unsigned int variations_index,
+					 unsigned int feature_index) const
+  {
+    const FeatureVariationRecord &record = varRecords[variations_index];
+    return (this+record.substitutions).find_substitute (feature_index);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index e20777a..adea32f 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -2275,6 +2275,18 @@ struct GSUBGPOS
 				     unsigned int *index) const
   { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
 	   .find_index (coords, num_coords, index); }
+  inline const Feature& get_feature_variation (unsigned int feature_index,
+					       unsigned int variations_index) const
+  {
+    if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
+	version.to_int () >= 0x00010001u)
+    {
+      const Feature *feature = (this+featureVars).find_substitute (variations_index, feature_index);
+      if (feature)
+        return *feature;
+    }
+    return get_feature (feature_index);
+  }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index d2a738d..5375e58 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -552,10 +552,13 @@ hb_ot_layout_feature_get_lookups (hb_face_t    *face,
 				  unsigned int *lookup_count /* IN/OUT */,
 				  unsigned int *lookup_indexes /* OUT */)
 {
-  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
-  const OT::Feature &f = g.get_feature (feature_index);
-
-  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
+  return hb_ot_layout_feature_with_variations_get_lookups (face,
+							   table_tag,
+							   feature_index,
+							   HB_OT_LAYOUT_NO_VARIATIONS_INDEX,
+							   start_offset,
+							   lookup_count,
+							   lookup_indexes);
 }
 
 /**
@@ -820,6 +823,23 @@ hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
   return g.find_variations_index (coords, num_coords, variations_index);
 }
 
+unsigned int
+hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
+						  hb_tag_t      table_tag,
+						  unsigned int  feature_index,
+						  unsigned int  variations_index,
+						  unsigned int  start_offset,
+						  unsigned int *lookup_count /* IN/OUT */,
+						  unsigned int *lookup_indexes /* OUT */)
+{
+  ASSERT_STATIC (OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+  const OT::Feature &f = g.get_feature_variation (feature_index, variations_index);
+
+  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
+}
+
 
 /*
  * OT::GSUB
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index 2e3db8c..9861f0f 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -246,6 +246,15 @@ hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
 					    unsigned int  num_coords,
 					    unsigned int *variations_index /* out */);
 
+HB_EXTERN unsigned int
+hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
+						  hb_tag_t      table_tag,
+						  unsigned int  feature_index,
+						  unsigned int  variations_index,
+						  unsigned int  start_offset,
+						  unsigned int *lookup_count /* IN/OUT */,
+						  unsigned int *lookup_indexes /* OUT */);
+
 
 /*
  * GSUB
commit 056f610416ba29fb7185daea837a0871bb3cce3f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 03:32:39 2016 -0700

    [GX] Add hb_ot_layout_table_find_feature_variations()

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 3c574af..e67a514 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1342,7 +1342,7 @@ struct ConditionFormat1
   friend struct Condition;
 
   private:
-  inline bool evaluate (int *coords, unsigned int coord_len) const
+  inline bool evaluate (const int *coords, unsigned int coord_len) const
   {
     int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
     return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
@@ -1365,7 +1365,7 @@ struct ConditionFormat1
 
 struct Condition
 {
-  inline bool evaluate (int *coords, unsigned int coord_len) const
+  inline bool evaluate (const int *coords, unsigned int coord_len) const
   {
     switch (u.format) {
     case 1: return u.format1.evaluate (coords, coord_len);
@@ -1394,7 +1394,7 @@ struct Condition
 
 struct ConditionSet
 {
-  inline bool evaluate (int *coords, unsigned int coord_len) const
+  inline bool evaluate (const int *coords, unsigned int coord_len) const
   {
     unsigned int count = conditions.len;
     for (unsigned int i = 0; i < count; i++)
@@ -1470,17 +1470,21 @@ struct FeatureVariationRecord
 
 struct FeatureVariations
 {
-  inline const FeatureTableSubstitution &
-	       get_substitutions (int *coords, unsigned int coord_len) const
+  inline bool find_index (const int *coords, unsigned int coord_len,
+			  unsigned int *index) const
   {
     unsigned int count = varRecords.len;
     for (unsigned int i = 0; i < count; i++)
     {
       const FeatureVariationRecord &record = varRecords.array[i];
       if ((this+record.conditions).evaluate (coords, coord_len))
-        return (this+record.substitutions);
+      {
+	*index = i;
+	return true;
+      }
     }
-    return Null(FeatureTableSubstitution);
+    *index = 0xFFFFFFFF;
+    return false;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 490b91e..e20777a 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -2271,10 +2271,10 @@ struct GSUBGPOS
   inline const Lookup& get_lookup (unsigned int i) const
   { return (this+lookupList)[i]; }
 
-  inline const FeatureTableSubstitution &
-	       get_feature_substitutions (int *coords, unsigned int coord_len) const
+  inline bool find_variations_index (const int *coords, unsigned int num_coords,
+				     unsigned int *index) const
   { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
-	   .get_substitutions (coords, coord_len); }
+	   .find_index (coords, num_coords, index); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 5cb1491..d2a738d 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -806,6 +806,21 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
 }
 
 
+/* Variations support */
+
+hb_bool_t
+hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
+					    hb_tag_t      table_tag,
+					    const int    *coords,
+					    unsigned int  num_coords,
+					    unsigned int *variations_index /* out */)
+{
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+  return g.find_variations_index (coords, num_coords, variations_index);
+}
+
+
 /*
  * OT::GSUB
  */
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index eb23d45..2e3db8c 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -95,6 +95,7 @@ hb_ot_layout_get_ligature_carets (hb_font_t      *font,
 #define HB_OT_LAYOUT_NO_SCRIPT_INDEX		0xFFFFu
 #define HB_OT_LAYOUT_NO_FEATURE_INDEX		0xFFFFu
 #define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX	0xFFFFu
+#define HB_OT_LAYOUT_NO_VARIATIONS_INDEX	0xFFFFFFFFu
 
 HB_EXTERN unsigned int
 hb_ot_layout_table_get_script_tags (hb_face_t    *face,
@@ -236,6 +237,15 @@ Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t    *face,
 					 void         *user_data);
 #endif
 
+/* Variations support */
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
+					    hb_tag_t      table_tag,
+					    const int    *coords,
+					    unsigned int  num_coords,
+					    unsigned int *variations_index /* out */);
+
 
 /*
  * GSUB
commit 6ef4333a76ca60d9226acf24ccd2c2a03bc420f5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 02:44:20 2016 -0700

    Shuffle code around

diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index a45c2f9..9cd3a44 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -31,45 +31,13 @@
 #include "hb-ot-layout-private.hh"
 
 
-void
-hb_ot_map_builder_t::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)
+void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
 {
-  unsigned int lookup_indices[32];
-  unsigned int offset, len;
-  unsigned int table_lookup_count;
-
-  table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
-
-  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);
-
-    for (unsigned int i = 0; i < len; i++)
-    {
-      if (lookup_indices[i] >= table_lookup_count)
-	continue;
-      hb_ot_map_t::lookup_map_t *lookup = m.lookups[table_index].push ();
-      if (unlikely (!lookup))
-        return;
-      lookup->mask = mask;
-      lookup->index = lookup_indices[i];
-      lookup->auto_zwj = auto_zwj;
-    }
-
-    offset += len;
-  } while (len == ARRAY_LENGTH (lookup_indices));
+  for (unsigned int i = 0; i < lookups[table_index].len; i++)
+    hb_set_add (lookups_out, lookups[table_index][i].index);
 }
 
+
 hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
 					  const hb_segment_properties_t *props_)
 {
@@ -110,13 +78,46 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
   info->stage[1] = current_stage[1];
 }
 
-
-void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
+void
+hb_ot_map_builder_t::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)
 {
-  for (unsigned int i = 0; i < lookups[table_index].len; i++)
-    hb_set_add (lookups_out, lookups[table_index][i].index);
+  unsigned int lookup_indices[32];
+  unsigned int offset, len;
+  unsigned int table_lookup_count;
+
+  table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
+
+  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);
+
+    for (unsigned int i = 0; i < len; i++)
+    {
+      if (lookup_indices[i] >= table_lookup_count)
+	continue;
+      hb_ot_map_t::lookup_map_t *lookup = m.lookups[table_index].push ();
+      if (unlikely (!lookup))
+        return;
+      lookup->mask = mask;
+      lookup->index = lookup_indices[i];
+      lookup->auto_zwj = auto_zwj;
+    }
+
+    offset += len;
+  } while (len == ARRAY_LENGTH (lookup_indices));
 }
 
+
 void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
 {
   stage_info_t *s = stages[table_index].push ();
commit 6360a891ad5af97c7a347f0f73921d8ef46ea2c3
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 02:43:20 2016 -0700

    Move add_lookups from map to map-builder
    
    In prep for more changes.

diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 8692caa..fc5ce66 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -139,12 +139,6 @@ struct hb_ot_map_t
 
   private:
 
-  HB_INTERNAL void add_lookups (hb_face_t    *face,
-				unsigned int  table_index,
-				unsigned int  feature_index,
-				hb_mask_t     mask,
-				bool          auto_zwj);
-
   hb_mask_t global_mask;
 
   hb_prealloced_array_t<feature_map_t, 8> features;
@@ -182,7 +176,7 @@ struct hb_ot_map_builder_t
   inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
   { add_pause (1, pause_func); }
 
-  HB_INTERNAL void compile (struct hb_ot_map_t &m);
+  HB_INTERNAL void compile (hb_ot_map_t &m);
 
   inline void finish (void) {
     feature_infos.finish ();
@@ -194,6 +188,13 @@ struct hb_ot_map_builder_t
 
   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);
+
   struct feature_info_t {
     hb_tag_t tag;
     unsigned int seq; /* sequence#, used for stable sorting only */
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 17e3f40..a45c2f9 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -32,11 +32,12 @@
 
 
 void
-hb_ot_map_t::add_lookups (hb_face_t    *face,
-			  unsigned int  table_index,
-			  unsigned int  feature_index,
-			  hb_mask_t     mask,
-			  bool          auto_zwj)
+hb_ot_map_builder_t::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)
 {
   unsigned int lookup_indices[32];
   unsigned int offset, len;
@@ -57,7 +58,7 @@ hb_ot_map_t::add_lookups (hb_face_t    *face,
     {
       if (lookup_indices[i] >= table_lookup_count)
 	continue;
-      hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
+      hb_ot_map_t::lookup_map_t *lookup = m.lookups[table_index].push ();
       if (unlikely (!lookup))
         return;
       lookup->mask = mask;
@@ -268,17 +269,17 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
     {
       if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
 	  required_feature_stage[table_index] == stage)
-	m.add_lookups (face, table_index,
-		       required_feature_index[table_index],
-		       1 /* mask */,
-		       true /* auto_zwj */);
+	add_lookups (m, face, table_index,
+		     required_feature_index[table_index],
+		     1 /* mask */,
+		     true /* auto_zwj */);
 
       for (unsigned i = 0; i < m.features.len; i++)
         if (m.features[i].stage[table_index] == stage)
-	  m.add_lookups (face, table_index,
-			 m.features[i].index[table_index],
-			 m.features[i].mask,
-			 m.features[i].auto_zwj);
+	  add_lookups (m, face, table_index,
+		       m.features[i].index[table_index],
+		       m.features[i].mask,
+		       m.features[i].auto_zwj);
 
       /* Sort lookups and merge duplicates */
       if (last_num_lookups < m.lookups[table_index].len)
commit da7c1f02e2652fc24ef7d49bf49df10424985c9b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 02:11:05 2016 -0700

    [GX] Remove (partial) support for anisotropic variations
    
    It doesn't always work, not part of FreeType, and we were not going
    to expose it in the API anyway.  Can always be added later.

diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index a398954..c8231db 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -110,8 +110,7 @@ struct hb_font_t {
 
   /* Font variation coordinates. */
   unsigned int num_coords;
-  int *x_coords;
-  int *y_coords;
+  int *coords;
 
   hb_font_funcs_t   *klass;
   void              *user_data;
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 24ecb45..f12dfb5 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1197,8 +1197,7 @@ hb_font_get_empty (void)
     0, /* y_ppem */
 
     0, /* num_coords */
-    NULL, /* x_coords */
-    NULL, /* y_coords */
+    NULL, /* coords */
 
     const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
     NULL, /* user_data */
@@ -1254,10 +1253,8 @@ hb_font_destroy (hb_font_t *font)
   hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
 
-  if (font->x_coords)
-    free (font->x_coords);
-  if (font->y_coords && font->y_coords != font->x_coords)
-    free (font->y_coords);
+  if (font->coords)
+    free (font->coords);
 
   free (font);
 }
@@ -1564,15 +1561,13 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
   if (unlikely (coords_length && !copy))
     return;
 
-  if (font->x_coords)
-    free (font->x_coords);
-  if (font->y_coords && font->y_coords != font->x_coords)
-    free (font->y_coords);
+  if (font->coords)
+    free (font->coords);
 
   if (coords_length)
     memcpy (copy, coords, coords_length * sizeof (coords[0]));
 
-  font->x_coords = font->y_coords = copy;
+  font->coords = copy;
   font->num_coords = coords_length;
 }
 
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index fb99ec3..3c574af 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1584,10 +1584,10 @@ struct VariationDevice
   private:
 
   inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
-  { return font->em_scalef_x (get_delta (store, font->x_coords, font->num_coords)); }
+  { return font->em_scalef_x (get_delta (font, store)); }
 
   inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
-  { return font->em_scalef_y (get_delta (store, font->y_coords, font->num_coords)); }
+  { return font->em_scalef_y (get_delta (font, store)); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -1597,10 +1597,9 @@ struct VariationDevice
 
   private:
 
-  inline float get_delta (const VariationStore &store,
-			  int *coords, unsigned int coord_count) const
+  inline float get_delta (hb_font_t *font, const VariationStore &store) const
   {
-    return store.get_delta (outerIndex, innerIndex, coords, coord_count);
+    return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
   }
 
   protected:
commit d4f178c675519ef6d01fc52e2ab3f33e46f93c2a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 01:58:27 2016 -0700

    [GX] Handle setting var coords to NULL

diff --git a/src/hb-font.cc b/src/hb-font.cc
index cce4359..24ecb45 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1560,8 +1560,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
   while (coords_length && !coords[coords_length - 1])
     coords_length--;
 
-  int *copy = (int *) calloc (coords_length, sizeof (coords[0]));
-  if (unlikely (!copy))
+  int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : NULL;
+  if (unlikely (coords_length && !copy))
     return;
 
   if (font->x_coords)
@@ -1569,7 +1569,9 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
   if (font->y_coords && font->y_coords != font->x_coords)
     free (font->y_coords);
 
-  memcpy (copy, coords, coords_length * sizeof (coords[0]));
+  if (coords_length)
+    memcpy (copy, coords, coords_length * sizeof (coords[0]));
+
   font->x_coords = font->y_coords = copy;
   font->num_coords = coords_length;
 }
commit 0fa652f119024e40d879ee568941945639c07af6
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 01:24:28 2016 -0700

    [GX] Implement Feature Variations
    
    Not hooked up to shaper yet.

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 3f835f1..fb99ec3 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -507,7 +507,7 @@ struct Feature
   { return this+featureParams; }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<Feature>::sanitize_closure_t *closure) const
+			const Record<Feature>::sanitize_closure_t *closure = NULL) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
@@ -1333,6 +1333,172 @@ struct VariationStore
   DEFINE_SIZE_ARRAY (8, dataSets);
 };
 
+/*
+ * Feature Variations
+ */
+
+struct ConditionFormat1
+{
+  friend struct Condition;
+
+  private:
+  inline bool evaluate (int *coords, unsigned int coord_len) const
+  {
+    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
+    return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  USHORT	format;		/* Format identifier--format = 1 */
+  USHORT	axisIndex;
+  F2DOT14	filterRangeMinValue;
+  F2DOT14	filterRangeMaxValue;
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct Condition
+{
+  inline bool evaluate (int *coords, unsigned int coord_len) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.evaluate (coords, coord_len);
+    default:return false;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  USHORT		format;		/* Format identifier */
+  ConditionFormat1	format1;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+struct ConditionSet
+{
+  inline bool evaluate (int *coords, unsigned int coord_len) const
+  {
+    unsigned int count = conditions.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+conditions.array[i]).evaluate (coords, coord_len))
+        return false;
+    return true;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (conditions.sanitize (c, this));
+  }
+
+  protected:
+  OffsetArrayOf<Condition, ULONG> conditions;
+  public:
+  DEFINE_SIZE_ARRAY (2, conditions);
+};
+
+struct FeatureTableSubstitutionRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && feature.sanitize (c, this));
+  }
+
+  protected:
+  USHORT			featureIndex;
+  OffsetTo<Feature, ULONG>	feature;
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct FeatureTableSubstitution
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  likely (version.major == 1) &&
+		  substitutions.sanitize (c, this));
+  }
+
+  protected:
+  FixedVersion<>	version;	/* Version--0x00010000u */
+  OffsetArrayOf<FeatureTableSubstitutionRecord, ULONG>
+			substitutions;
+  public:
+  DEFINE_SIZE_ARRAY (6, substitutions);
+};
+
+struct FeatureVariationRecord
+{
+  friend struct FeatureVariations;
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (conditions.sanitize (c, base) &&
+		  substitutions.sanitize (c, base));
+  }
+
+  protected:
+  OffsetTo<ConditionSet, ULONG>
+			conditions;
+  OffsetTo<FeatureTableSubstitution, ULONG>
+			substitutions;
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct FeatureVariations
+{
+  inline const FeatureTableSubstitution &
+	       get_substitutions (int *coords, unsigned int coord_len) const
+  {
+    unsigned int count = varRecords.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      const FeatureVariationRecord &record = varRecords.array[i];
+      if ((this+record.conditions).evaluate (coords, coord_len))
+        return (this+record.substitutions);
+    }
+    return Null(FeatureTableSubstitution);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  likely (version.major == 1) &&
+		  varRecords.sanitize (c, this));
+  }
+
+  protected:
+  FixedVersion<>	version;	/* Version--0x00010000u */
+  ArrayOf<FeatureVariationRecord, ULONG>
+			varRecords;
+  public:
+  DEFINE_SIZE_ARRAY (8, varRecords);
+};
+
 
 /*
  * Device Tables
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index d85140e..b70cbb7 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -397,7 +397,6 @@ struct GDEF
 		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
   }
 
-
   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
    * glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
    * Not to be confused with lookup_props which is very similar. */
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 0ced5d0..5c9fc29 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1518,8 +1518,6 @@ struct GPOS : GSUBGPOS
     const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
     return_trace (list.sanitize (c, this));
   }
-  public:
-  DEFINE_SIZE_STATIC (10);
 };
 
 
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 22031f4..6658a2c 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1273,8 +1273,6 @@ struct GSUB : GSUBGPOS
     const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
     return_trace (list.sanitize (c, this));
   }
-  public:
-  DEFINE_SIZE_STATIC (10);
 };
 
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 5cb6ba7..490b91e 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -2271,6 +2271,11 @@ struct GSUBGPOS
   inline const Lookup& get_lookup (unsigned int i) const
   { return (this+lookupList)[i]; }
 
+  inline const FeatureTableSubstitution &
+	       get_feature_substitutions (int *coords, unsigned int coord_len) const
+  { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
+	   .get_substitutions (coords, coord_len); }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2278,7 +2283,8 @@ struct GSUBGPOS
 		  likely (version.major == 1) &&
 		  scriptList.sanitize (c, this) &&
 		  featureList.sanitize (c, this) &&
-		  lookupList.sanitize (c, this));
+		  lookupList.sanitize (c, this) &&
+		  (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
   }
 
   protected:
@@ -2290,8 +2296,13 @@ struct GSUBGPOS
 		featureList; 	/* FeatureList table */
   OffsetTo<LookupList>
 		lookupList; 	/* LookupList table */
+  OffsetTo<FeatureVariations, ULONG>
+		featureVars;	/* Offset to Feature Variations
+				   table--from beginning of table
+				 * (may be NULL).  Introduced
+				 * in version 0x00010001. */
   public:
-  DEFINE_SIZE_STATIC (10);
+  DEFINE_SIZE_MIN (10);
 };
 
 
commit 6f8a7b19952c5b238cb7492b1a78cf2128349b0b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 00:25:16 2016 -0700

    [GX] Fix another x/y thinko
    
    Thanks Werner!

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index c31a197..3f835f1 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1475,7 +1475,7 @@ struct Device
     switch (u.b.format)
     {
     case 1: case 2: case 3:
-      return u.hinting.get_x_delta (font);
+      return u.hinting.get_y_delta (font);
     case 0x8000:
       return u.variation.get_y_delta (font, store);
     default:
commit 0319f1631f9f7198ed2a08ea6c4078354b040f04
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 00:22:24 2016 -0700

    [GX] Rename VarStore to VariationStore

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index c18e520..c31a197 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1303,7 +1303,7 @@ struct VarData
   DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
 };
 
-struct VarStore
+struct VariationStore
 {
   inline float get_delta (unsigned int outer, unsigned int inner,
 			  int *coords, unsigned int coord_count) const
@@ -1417,10 +1417,10 @@ struct VariationDevice
 
   private:
 
-  inline hb_position_t get_x_delta (hb_font_t *font, const VarStore &store) const
+  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
   { return font->em_scalef_x (get_delta (store, font->x_coords, font->num_coords)); }
 
-  inline hb_position_t get_y_delta (hb_font_t *font, const VarStore &store) const
+  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
   { return font->em_scalef_y (get_delta (store, font->y_coords, font->num_coords)); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -1431,7 +1431,7 @@ struct VariationDevice
 
   private:
 
-  inline float get_delta (const VarStore &store,
+  inline float get_delta (const VariationStore &store,
 			  int *coords, unsigned int coord_count) const
   {
     return store.get_delta (outerIndex, innerIndex, coords, coord_count);
@@ -1458,7 +1458,7 @@ struct DeviceHeader
 
 struct Device
 {
-  inline hb_position_t get_x_delta (hb_font_t *font, const VarStore &store) const
+  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
   {
     switch (u.b.format)
     {
@@ -1470,7 +1470,7 @@ struct Device
       return 0;
     }
   }
-  inline hb_position_t get_y_delta (hb_font_t *font, const VarStore &store) const
+  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
   {
     switch (u.b.format)
     {
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 2a92ece..d85140e 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -146,7 +146,7 @@ struct CaretValueFormat3
 {
   friend struct CaretValue;
 
-  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, const VarStore &var_store) const
+  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, const VariationStore &var_store) const
   {
     return HB_DIRECTION_IS_HORIZONTAL (direction) ?
            font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
@@ -175,7 +175,7 @@ struct CaretValue
   inline hb_position_t get_caret_value (hb_font_t *font,
 					hb_direction_t direction,
 					hb_codepoint_t glyph_id,
-					const VarStore &var_store) const
+					const VariationStore &var_store) const
   {
     switch (u.format) {
     case 1: return u.format1.get_caret_value (font, direction);
@@ -213,7 +213,7 @@ struct LigGlyph
   inline unsigned int get_lig_carets (hb_font_t *font,
 				      hb_direction_t direction,
 				      hb_codepoint_t glyph_id,
-				      const VarStore &var_store,
+				      const VariationStore &var_store,
 				      unsigned int start_offset,
 				      unsigned int *caret_count /* IN/OUT */,
 				      hb_position_t *caret_array /* OUT */) const
@@ -248,7 +248,7 @@ struct LigCaretList
   inline unsigned int get_lig_carets (hb_font_t *font,
 				      hb_direction_t direction,
 				      hb_codepoint_t glyph_id,
-				      const VarStore &var_store,
+				      const VariationStore &var_store,
 				      unsigned int start_offset,
 				      unsigned int *caret_count /* IN/OUT */,
 				      hb_position_t *caret_array /* OUT */) const
@@ -381,8 +381,8 @@ struct GDEF
   { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
 
   inline bool has_var_store (void) const { return version.to_int () >= 0x00010003u && varStore != 0; }
-  inline const VarStore &get_var_store (void) const
-  { return version.to_int () >= 0x00010003u ? this+varStore : Null(VarStore); }
+  inline const VariationStore &get_var_store (void) const
+  { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -444,7 +444,7 @@ struct GDEF
 					 * definitions--from beginning of GDEF
 					 * header (may be NULL).  Introduced
 					 * in version 0x00010002. */
-  OffsetTo<VarStore, ULONG>
+  OffsetTo<VariationStore, ULONG>
 		varStore;		/* Offset to the table of Item Variation
 					 * Store--from beginning of GDEF
 					 * header (may be NULL).  Introduced
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index dd398f7..0ced5d0 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -133,7 +133,7 @@ struct ValueFormat : USHORT
 
     if (!use_x_device && !use_y_device) return;
 
-    const VarStore &store = c->var_store;
+    const VariationStore &store = c->var_store;
 
     /* pixel -> fractional pixel */
     if (format & xPlaDevice) {
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 1f501c6..5cb6ba7 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -469,7 +469,7 @@ struct hb_apply_context_t :
   unsigned int lookup_props;
   const GDEF &gdef;
   bool has_glyph_classes;
-  const VarStore &var_store;
+  const VariationStore &var_store;
   skipping_iterator_t iter_input, iter_context;
   unsigned int lookup_index;
   unsigned int debug_depth;


More information about the HarfBuzz mailing list