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

Behdad Esfahbod behdad at kemper.freedesktop.org
Sat Dec 17 01:06:50 UTC 2016


 configure.ac                         |    4 
 src/hb-coretext.cc                   |    8 
 src/hb-directwrite.cc                |    6 
 src/hb-fallback-shape.cc             |    4 
 src/hb-font-private.hh               |   10 
 src/hb-font.cc                       |   33 ++
 src/hb-font.h                        |    5 
 src/hb-ft.cc                         |   18 +
 src/hb-graphite2.cc                  |    4 
 src/hb-open-type-private.hh          |    5 
 src/hb-ot-layout-common-private.hh   |  468 ++++++++++++++++++++++++++++++++++-
 src/hb-ot-layout-gdef-table.hh       |   52 ++-
 src/hb-ot-layout-gpos-table.hh       |  103 +++----
 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                   |   12 
 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 
 win32/README.txt                     |    4 
 win32/build-rules-msvc.mak           |   13 
 win32/config-msvc.mak                |   37 +-
 win32/create-lists-msvc.mak          |   13 
 win32/detectenv-msvc.mak             |    4 
 win32/generate-msvc.mak              |    2 
 win32/info-msvc.mak                  |   12 
 win32/install.mak                    |    4 
 34 files changed, 968 insertions(+), 221 deletions(-)

New commits:
commit 4cd0cd67914db1da10906e40335faea7dbec1d0a
Author: elmarb <elmar.braun at web.de>
Date:   Wed Dec 7 11:50:27 2016 +0100

    NMake ICU option builds with builtin ICU (#375)

diff --git a/win32/build-rules-msvc.mak b/win32/build-rules-msvc.mak
index 03b3833..bfe0286 100644
--- a/win32/build-rules-msvc.mak
+++ b/win32/build-rules-msvc.mak
@@ -23,11 +23,6 @@ $<
 $<
 <<
 
-{..\src\}.cc{$(CFG)\$(PLAT)\harfbuzz-icu\}.obj::
-	$(CXX) $(CFLAGS) $(HB_LIB_CFLAGS) $(HB_ICU_CFLAGS) /Fo$(CFG)\$(PLAT)\harfbuzz-icu\ /c @<<
-$<
-<<
-
 {..\util\}.cc{$(CFG)\$(PLAT)\util\}.obj::
 	$(CXX) $(CFLAGS) $(HB_DEFINES) $(HB_CFLAGS) /Fo$(CFG)\$(PLAT)\util\ /c @<<
 $<
@@ -48,7 +43,6 @@ $<
 
 # Rules for building .lib files
 $(CFG)\$(PLAT)\harfbuzz.lib: $(HARFBUZZ_DLL_FILENAME).dll
-$(CFG)\$(PLAT)\harfbuzz-icu.lib: $(HARFBUZZ_ICU_DLL_FILENAME).dll
 $(CFG)\$(PLAT)\harfbuzz-gobject.lib: $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll
 
 # Rules for linking DLLs
@@ -64,12 +58,6 @@ $(harfbuzz_dll_OBJS)
 <<
 	@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;2
 
-$(HARFBUZZ_ICU_DLL_FILENAME).dll: $(CFG)\$(PLAT)\harfbuzz.lib $(harfbuzz_icu_OBJS) $(CFG)\$(PLAT)\harfbuzz-icu
-	link /DLL $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_ICU_DEP_LIBS) /implib:$(CFG)\$(PLAT)\harfbuzz-icu.lib -out:$@ @<<
-$(harfbuzz_icu_OBJS)
-<<
-	@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;2
-
 $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll: $(CFG)\$(PLAT)\harfbuzz.lib $(harfbuzz_gobject_OBJS) $(CFG)\$(PLAT)\harfbuzz-gobject
 	link /DLL $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_GOBJECT_DEP_LIBS) /implib:$(CFG)\$(PLAT)\harfbuzz-gobject.lib -out:$@ @<<
 $(harfbuzz_gobject_OBJS)
@@ -131,7 +119,6 @@ clean:
 	@-del /f /q $(CFG)\$(PLAT)\*.obj
 	@-if exist $(CFG)\$(PLAT)\util del /f /q $(CFG)\$(PLAT)\util\*.obj
 	@-if exist $(CFG)\$(PLAT)\harfbuzz-gobject del /f /q $(CFG)\$(PLAT)\harfbuzz-gobject\*.obj
-	@-if exist $(CFG)\$(PLAT)\harfbuzz-icu del /f /q $(CFG)\$(PLAT)\harfbuzz-icu\*.obj
 	@-del /f /q $(CFG)\$(PLAT)\harfbuzz\*.obj
 	@-rmdir /s /q $(CFG)\$(PLAT)
 	@-if exist $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h del $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h
diff --git a/win32/config-msvc.mak b/win32/config-msvc.mak
index d8b851d..ecbbe92 100644
--- a/win32/config-msvc.mak
+++ b/win32/config-msvc.mak
@@ -60,29 +60,12 @@ HB_TESTS_DEP_LIBS = $(HB_GLIB_LIBS)
 # Use libtool-style DLL names, if desired
 !if "$(LIBTOOL_DLL_NAME)" == "1"
 HARFBUZZ_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-0
-HARFBUZZ_ICU_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-icu-0
 HARFBUZZ_GOBJECT_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-gobject-0
 !else
 HARFBUZZ_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-vs$(VSVER)
-HARFBUZZ_ICU_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-icu-vs$(VSVER)
 HARFBUZZ_GOBJECT_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-gobject-vs$(VSVER)
 !endif
 
-# Enable HarfBuzz-ICU, if desired
-!if "$(ICU)" == "1"
-HB_ICU_CFLAGS =
-HB_LIBS =	\
-	$(HB_LIBS)	\
-	$(CFG)\$(PLAT)\harfbuzz-icu.lib
-
-# We don't want to re-define int8_t Visual Studio 2008, will cause build breakage
-# as we define it in hb-common.h, and we ought to use the definitions there.
-!if "$(VSVER)" == "9"
-HB_ICU_CFLAGS = /DU_HAVE_INT8_T
-!endif
-
-!endif
-
 # Enable Introspection (enables HarfBuzz-Gobject as well)
 !if "$(INTROSPECTION)" == "1"
 GOBJECT = 1
@@ -181,6 +164,26 @@ HB_TESTS = \
 	$(CFG)\$(PLAT)\test-unicode.exe				\
 	$(CFG)\$(PLAT)\test-version.exe
 
+!elseif "$(ICU)" == "1"
+# use ICU for Unicode functions
+# and define some of the macros in GLib's msvc_recommended_pragmas.h
+# to reduce some unneeded build-time warnings
+HB_DEFINES = $(HB_DEFINES) /DHAVE_ICU=1 /DHAVE_ICU_BUILTIN=1
+HB_CFLAGS =	\
+	$(HB_CFLAGS)					\
+	/wd4244							\
+	/D_CRT_SECURE_NO_WARNINGS		\
+	/D_CRT_NONSTDC_NO_WARNINGS
+
+# We don't want ICU to re-define int8_t in VS 2008, will cause build breakage
+# as we define it in hb-common.h, and we ought to use the definitions there.
+!if "$(VSVER)" == "9"
+HB_CFLAGS =	$(HB_CFLAGS) /DU_HAVE_INT8_T
+!endif
+
+HB_SOURCES = $(HB_SOURCES) $(HB_ICU_sources)
+HB_HEADERS = $(HB_HEADERS) $(HB_ICU_headers)
+HB_DEP_LIBS = $(HB_DEP_LIBS) $(HB_ICU_DEP_LIBS)
 !else
 # If there is no GLib support, use the built-in UCDN
 # and define some of the macros in GLib's msvc_recommended_pragmas.h
diff --git a/win32/create-lists-msvc.mak b/win32/create-lists-msvc.mak
index 9b5574b..dbd2a57 100644
--- a/win32/create-lists-msvc.mak
+++ b/win32/create-lists-msvc.mak
@@ -59,19 +59,6 @@ NULL=
 !endif
 !endif
 
-# For HarfBuzz-ICU
-!if "$(ICU)" == "1"
-
-!if [call create-lists.bat header hb_objs.mak harfbuzz_icu_OBJS]
-!endif
-
-!if [for %c in ($(HB_ICU_sources)) do @if "%~xc" == ".cc" @call create-lists.bat file hb_objs.mak ^$(CFG)\^$(PLAT)\harfbuzz-icu\%~nc.obj]
-!endif
-
-!if [call create-lists.bat footer hb_objs.mak]
-!endif
-!endif
-
 # For the utility programs (GLib support is required)
 !if "$(GLIB)" == "1"
 
diff --git a/win32/detectenv-msvc.mak b/win32/detectenv-msvc.mak
index 80a5eed..ca09793 100644
--- a/win32/detectenv-msvc.mak
+++ b/win32/detectenv-msvc.mak
@@ -110,7 +110,9 @@ VALID_CFGSET = TRUE
 # the resulting binaries
 !if "$(CFG)" == "release"
 CFLAGS_ADD = /MD /O2 /GL /MP
-!if "$(VSVER)" != "9"
+!if $(VSVER) > 9 && $(VSVER) < 14
+# Undocumented "enhance optimized debugging" switch. Became documented
+# as "/Zo" in VS 2013 Update 3, and is turned on by default in VS 2015.
 CFLAGS_ADD = $(CFLAGS_ADD) /d2Zi+
 !endif
 !else
diff --git a/win32/generate-msvc.mak b/win32/generate-msvc.mak
index 57cfb6e..32214eb 100644
--- a/win32/generate-msvc.mak
+++ b/win32/generate-msvc.mak
@@ -22,5 +22,5 @@ $(HB_GOBJECT_ENUM_GENERATED_SOURCES): ..\src\hb-gobject-enums.h.tmpl ..\src\hb-g
 !endif
 
 # Create the build directories
-$(CFG)\$(PLAT)\harfbuzz $(CFG)\$(PLAT)\harfbuzz-icu $(CFG)\$(PLAT)\harfbuzz-gobject $(CFG)\$(PLAT)\util:
+$(CFG)\$(PLAT)\harfbuzz $(CFG)\$(PLAT)\harfbuzz-gobject $(CFG)\$(PLAT)\util:
 	@-md $@
diff --git a/win32/info-msvc.mak b/win32/info-msvc.mak
index bbe631b..3ec11d4 100644
--- a/win32/info-msvc.mak
+++ b/win32/info-msvc.mak
@@ -11,6 +11,8 @@ BUILT_TOOLS = hb-shape.exe hb-ot-shape-closure.exe
 !if "$(CAIRO_FT)" == "1"
 BUILT_TOOLS = hb-view.exe $(BUILT_TOOLS)
 !endif
+!elseif "$(ICU)" == "1"
+UNICODE_IMPL = ICU
 !else
 UNICODE_IMPL = ucdn
 !endif
@@ -31,10 +33,6 @@ INC_FEATURES = $(INC_FEATURES) Uniscribe
 INC_FEATURES = $(INC_FEATURES) DirectWrite
 !endif
 
-!if "$(ICU)" == "1"
-BUILT_LIBRARIES = $(BUILT_LIBRARIES) HarfBuzz-ICU
-!endif
-
 !if "$(GOBJECT)" == "1"
 BUILT_LIBRARIES = $(BUILT_LIBRARIES) HarfBuzz-GObject
 !endif
@@ -101,20 +99,20 @@ help:
 	@echo library.  Enables the build of utility programs.
 	@echo.
 	@echo ICU:
-	@echo Enable the HarfBuzz-ICU layout library, requires the International
+	@echo Enable build with ICU Unicode functions, requires the International
 	@echo Components for Unicode (ICU) libraries.
 	@echo.
 	@echo GOBJECT:
 	@echo Enable the HarfBuzz-GObject library, also implies GLib2 support,
 	@echo requires the GNOME GLib2 libraries and tools, notably the glib-mkenums
-	@echo tool script, which will require a PERL interpretor (use
+	@echo tool script, which will require a PERL interpreter (use
 	@echo PERL=^$(PATH_TO_PERL_INTERPRETOR)) if it is not already in your PATH).
 	@echo.
 	@echo INTROSPECTION:
 	@echo Enable the build of introspection files, also implies GObject/GLib2 support,
 	@echo requires the GNOME gobject-introspection libraries and tools.  You will need
 	@echo to ensure the pkg-config (.pc) files can be found for GObject-2.0 and the
-	@echo Python interpretor (that was used to build the gobject-introsoection tools)
+	@echo Python interpreter (that was used to build the gobject-introspection tools)
 	@echo can be found by setting PKG_CONFIG_PATH beforehand, and passing in PYTHON=
 	@echo ^$(PATH_TO_PYTHON_INTERPRETOR) respectively, if python.exe is not already
 	@echo in your PATH.
diff --git a/win32/install.mak b/win32/install.mak
index fa239ea..e0a38e3 100644
--- a/win32/install.mak
+++ b/win32/install.mak
@@ -8,9 +8,6 @@ install: all
 	@copy /b $(HARFBUZZ_DLL_FILENAME).dll $(PREFIX)\bin
 	@copy /b $(HARFBUZZ_DLL_FILENAME).pdb $(PREFIX)\bin
 	@copy /b $(CFG)\$(PLAT)\harfbuzz.lib $(PREFIX)\lib
-	@if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll copy /b $(HARFBUZZ_ICU_DLL_FILENAME).dll $(PREFIX)\bin
-	@if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll copy /b $(HARFBUZZ_ICU_DLL_FILENAME).pdb $(PREFIX)\bin
-	@if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll copy /b $(CFG)\$(PLAT)\harfbuzz-icu.lib $(PREFIX)\lib
 	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy /b $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll $(PREFIX)\bin
 	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy /b $(HARFBUZZ_GOBJECT_DLL_FILENAME).pdb $(PREFIX)\bin
 	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy /b $(CFG)\$(PLAT)\harfbuzz-gobject.lib $(PREFIX)\lib
@@ -21,7 +18,6 @@ install: all
 	@if exist $(CFG)\$(PLAT)\hb-shape.exe copy /b $(CFG)\$(PLAT)\hb-shape.exe $(PREFIX)\bin
 	@if exist $(CFG)\$(PLAT)\hb-shape.exe copy /b $(CFG)\$(PLAT)\hb-shape.pdb $(PREFIX)\bin
 	@for %h in ($(HB_ACTUAL_HEADERS)) do @copy %h $(PREFIX)\include\harfbuzz
-	@if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll for %h in ($(HB_ICU_headers)) do @copy ..\src\%h $(PREFIX)\include\harfbuzz
 	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll for %h in ($(HB_GOBJECT_headers)) do @copy ..\src\%h $(PREFIX)\include\harfbuzz
 	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h $(PREFIX)\include\harfbuzz
 	@rem Copy the generated introspection files
commit 75fa884f925c203a839b5874f30bf9ebf025b6e4
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Mon Dec 5 23:20:47 2016 +0200

    [win32] Fix wrong description of the ICU option (#372)

diff --git a/win32/README.txt b/win32/README.txt
index 07e211c..af0dc15 100644
--- a/win32/README.txt
+++ b/win32/README.txt
@@ -63,9 +63,7 @@ CAIRO_FT: Enable the build of the hb-view tool, which makes use of Cairo, and
 
 GRAPHITE2: Enable the Graphite2 shaper, requires the SIL Graphite2 library.
 
-ICU: Enables the build HarfBuzz-ICU, which is now the recommended layout engine
-     for ICU (International Components for Unicode), which deprecated ICU LE.
-     Requires the ICU libraries.
+ICU: Enables the build of ICU Unicode functions. Requires the ICU libraries.
 
 UNISCRIBE: Enable Uniscribe platform shaper support.
 
commit 219cb29c5d230ecc6ee154b447fabd7b59fbe089
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Sep 28 17:16:06 2016 +0200

    Fix build after rebasing opentype-gx branch on top of MATH table

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 971c95a..4c7714a 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1650,7 +1650,7 @@ struct DeviceHeader
 
 struct Device
 {
-  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
+  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
   {
     switch (u.b.format)
     {
@@ -1662,7 +1662,7 @@ struct Device
       return 0;
     }
   }
-  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
+  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
   {
     switch (u.b.format)
     {
commit 0aedfd59be54972e61a952753ffc0d12631771fe
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Sep 28 17:05:43 2016 +0200

    [GX] Apply 'rvrn' feature before any other feature

diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 6c78b47..9872798 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -69,6 +69,9 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 {
   hb_ot_map_builder_t *map = &planner->map;
 
+  map->add_global_bool_feature (HB_TAG('r','v','r','n'));
+  map->add_gsub_pause (NULL);
+
   switch (props->direction) {
     case HB_DIRECTION_LTR:
       map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
commit 42c81425316190f6424ecb9b19d5a886aa1e4136
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Sep 13 23:49:46 2016 +0200

    [GX] Fix build with older FreeType

diff --git a/configure.ac b/configure.ac
index 0fdaf53..6948aa6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -346,6 +346,10 @@ if test "x$with_freetype" = "xyes" -a "x$have_freetype" != "xtrue"; then
 fi
 if $have_freetype; then
 	AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
+	save_libs=$LIBS
+	LIBS="$LIBS $FREETYPE_LIBS"
+	AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates)
+	LIBS=$save_libs
 fi
 AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
 
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 30d28c0..f127066 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -617,18 +617,22 @@ hb_ft_font_create (FT_Face           ft_face,
 		    ft_face->size->metrics.y_ppem);
 #endif
 
+#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
   FT_MM_Var *mm_var = NULL;
-  if (!FT_Get_MM_Var (ft_face, &mm_var)) {
+  if (!FT_Get_MM_Var (ft_face, &mm_var))
+  {
     FT_Fixed coords[mm_var->num_axis];
     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) {
+    if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, coords))
+    {
+      for (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);
     }
   }
   free (mm_var);
+#endif
 
   return font;
 }
commit 72873cf522a6e3bec1b6508d8d20d3d2ce233cd6
Author: Sascha Brawer <sascha at brawer.ch>
Date:   Tue Sep 13 18:40:07 2016 +0200

    Call hb_font_set_var_coords_normalized() from FT_Face coords

diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 2b06c59..30d28c0 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -36,6 +36,7 @@
 #include "hb-cache-private.hh" // Maybe use in the future?
 
 #include FT_ADVANCES_H
+#include FT_MULTIPLE_MASTERS_H
 #include FT_TRUETYPE_TABLES_H
 
 
@@ -616,6 +617,19 @@ hb_ft_font_create (FT_Face           ft_face,
 		    ft_face->size->metrics.y_ppem);
 #endif
 
+  FT_MM_Var *mm_var = NULL;
+  if (!FT_Get_MM_Var (ft_face, &mm_var)) {
+    FT_Fixed coords[mm_var->num_axis];
+    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) {
+	hbCoords[i] = coords[i] >> 2;
+      }
+      hb_font_set_var_coords_normalized (font, hbCoords, mm_var->num_axis);
+    }
+  }
+  free (mm_var);
+
   return font;
 }
 
commit 4ebbeb7c50e5c1e934d230ceacf792602c6eb9b9
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 72ada4f0c6998fc2a282efc2a573733e37db8be5
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 ec87ba9ba32a374d49dd3e40137f75f4f4232aee
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 b352cdb..345d5e6 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -582,10 +582,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);
 }
 
 /**
@@ -850,6 +853,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 30c42b644eb33551aa0986287182a46f2d8c32ed
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 0501181..b352cdb 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -836,6 +836,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 7ceadbe981aa50481163bb365f0fe3f994266165
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 bde5e3959c0ffdb92db87668035b01aaee9b2352
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 26648cebcd14bd26142ccfe5ac8c0be08a213671
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 48dc725..53671d7 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 c22176d4bac720b4c9121b3d6629595831f19fb0
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 59055b5494f802013ca3613a15e565ae1ca0c589
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 85ec4944346a1ac111217698e1424669a9732280
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 cf3de4d8f79fc6e8413957cdef034e975343ce30
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;
commit 1f6ed356e0a849b61ce98b6a2f38d04d98c2191e
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Sep 10 00:01:10 2016 -0700

    [GX] Fix build with some compilers
    
    Eg. https://ci.appveyor.com/project/behdad/harfbuzz/build/1.0.48/job/o9mnd33kcdeeg30r
    
    hb-open-type-private.hh:103:29: error: static data member 'OT::Device::<anonymous union>::<anonymous struct>::static_size' in unnamed class [-fpermissive]

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 35889c7..c18e520 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1445,6 +1445,17 @@ struct VariationDevice
   DEFINE_SIZE_STATIC (6);
 };
 
+struct DeviceHeader
+{
+  protected:
+  USHORT		reserved1;
+  USHORT		reserved2;
+  public:
+  USHORT		format;		/* Format identifier */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
 struct Device
 {
   inline hb_position_t get_x_delta (hb_font_t *font, const VarStore &store) const
@@ -1488,13 +1499,7 @@ struct Device
 
   protected:
   union {
-  struct {
-    USHORT		reserved1;
-    USHORT		reserved2;
-    USHORT		format;		/* Format identifier */
-    public:
-    DEFINE_SIZE_STATIC (6);
-  } b;
+  DeviceHeader		b;
   HintingDevice		hinting;
   VariationDevice	variation;
   } u;
commit 250bcd6fb691d6f15fa9ca71b475ce419d0b5e37
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 23:12:14 2016 -0700

    [GX] Skip tail zero entries when setting variation coordinates

diff --git a/src/hb-font.cc b/src/hb-font.cc
index d27961d..cce4359 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1556,6 +1556,10 @@ 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 = (int *) calloc (coords_length, sizeof (coords[0]));
   if (unlikely (!copy))
     return;
commit 1124d2ece55e323ed934357b30e68df75829cfaa
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 22:48:27 2016 -0700

    [GX] Fix thinko

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 8c63ad9..35889c7 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1265,7 +1265,6 @@ struct VarData
    const BYTE *bytes = &StructAfter<BYTE> (regionIndices);
    const BYTE *row = bytes + inner * (scount + count);
 
-
    float delta = 0.;
    unsigned int i = 0;
 
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 1893f0e..dd398f7 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -298,7 +298,7 @@ struct AnchorFormat3
     if (font->x_ppem || font->num_coords)
       *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
     if (font->y_ppem || font->num_coords)
-      *y += (this+yDeviceTable).get_x_delta (font, c->var_store);
+      *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
commit ad69e8f07c6e3e47fe7e7103c2ff7c053d272b1a
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 22:23:34 2016 -0700

    [GX] Add new API hb_font_set_var_coords_normalized()
    
    Will probably change.

diff --git a/src/hb-font.cc b/src/hb-font.cc
index 978e7dd..d27961d 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1548,6 +1548,29 @@ hb_font_get_ppem (hb_font_t *font,
 }
 
 
+void
+hb_font_set_var_coords_normalized (hb_font_t *font,
+				   int *coords, /* XXX 2.14 normalized */
+				   unsigned int coords_length)
+{
+  if (font->immutable)
+    return;
+
+  int *copy = (int *) calloc (coords_length, sizeof (coords[0]));
+  if (unlikely (!copy))
+    return;
+
+  if (font->x_coords)
+    free (font->x_coords);
+  if (font->y_coords && font->y_coords != font->x_coords)
+    free (font->y_coords);
+
+  memcpy (copy, coords, coords_length * sizeof (coords[0]));
+  font->x_coords = font->y_coords = copy;
+  font->num_coords = coords_length;
+}
+
+
 #ifndef HB_DISABLE_DEPRECATED
 
 /*
diff --git a/src/hb-font.h b/src/hb-font.h
index 2b6ab50..8813286 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -604,6 +604,11 @@ hb_font_get_ppem (hb_font_t *font,
 		  unsigned int *y_ppem);
 
 
+HB_EXTERN void
+hb_font_set_var_coords_normalized (hb_font_t *font,
+				   int *coords, /* XXX 2.14 normalized */
+				   unsigned int coords_length);
+
 HB_END_DECLS
 
 #endif /* HB_FONT_H */
commit 151d93de8a595924a8dcb00fcba648b4b3df0bf5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 17:03:11 2016 -0700

    [GX] Hook up GPOS to Variation Store stored in GDEF
    
    Untested.

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index ad67972..8c63ad9 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1418,11 +1418,11 @@ struct VariationDevice
 
   private:
 
-  inline hb_position_t get_x_delta (hb_font_t *font) const
-  { return font->em_scalef_x (get_delta (font->x_coords, font->num_coords)); }
+  inline hb_position_t get_x_delta (hb_font_t *font, const VarStore &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
-  { return font->em_scalef_y (get_delta (font->y_coords, font->num_coords)); }
+  inline hb_position_t get_y_delta (hb_font_t *font, const VarStore &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
   {
@@ -1432,11 +1432,10 @@ struct VariationDevice
 
   private:
 
-  inline float get_delta (int *coords, unsigned int coord_count) const
+  inline float get_delta (const VarStore &store,
+			  int *coords, unsigned int coord_count) const
   {
-    float v = 0;
-    /* XXXXXXXXXXXXXXX call into GDEF. */
-    return v;
+    return store.get_delta (outerIndex, innerIndex, coords, coord_count);
   }
 
   protected:
@@ -1449,25 +1448,26 @@ struct VariationDevice
 
 struct Device
 {
-  inline hb_position_t get_x_delta (hb_font_t *font) const
+  inline hb_position_t get_x_delta (hb_font_t *font, const VarStore &store) const
   {
     switch (u.b.format)
     {
     case 1: case 2: case 3:
       return u.hinting.get_x_delta (font);
     case 0x8000:
-      return u.variation.get_x_delta (font);
+      return u.variation.get_x_delta (font, store);
     default:
       return 0;
     }
   }
-  inline hb_position_t get_y_delta (hb_font_t *font) const
+  inline hb_position_t get_y_delta (hb_font_t *font, const VarStore &store) const
   {
     switch (u.b.format)
     {
     case 1: case 2: case 3:
       return u.hinting.get_x_delta (font);
     case 0x8000:
+      return u.variation.get_y_delta (font, store);
     default:
       return 0;
     }
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index e7d14f6..2a92ece 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -97,7 +97,7 @@ struct CaretValueFormat1
   friend struct CaretValue;
 
   private:
-  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
+  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
   {
     return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
   }
@@ -146,11 +146,11 @@ struct CaretValueFormat3
 {
   friend struct CaretValue;
 
-  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
+  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, const VarStore &var_store) const
   {
     return HB_DIRECTION_IS_HORIZONTAL (direction) ?
-           font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font) :
-           font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
+           font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
+           font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -172,12 +172,15 @@ struct CaretValueFormat3
 
 struct CaretValue
 {
-  inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
+  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
   {
     switch (u.format) {
-    case 1: return u.format1.get_caret_value (font, direction, glyph_id);
+    case 1: return u.format1.get_caret_value (font, direction);
     case 2: return u.format2.get_caret_value (font, direction, glyph_id);
-    case 3: return u.format3.get_caret_value (font, direction, glyph_id);
+    case 3: return u.format3.get_caret_value (font, direction, var_store);
     default:return 0;
     }
   }
@@ -210,6 +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,
 				      unsigned int start_offset,
 				      unsigned int *caret_count /* IN/OUT */,
 				      hb_position_t *caret_array /* OUT */) const
@@ -218,7 +222,7 @@ struct LigGlyph
       const OffsetTo<CaretValue> *array = carets.sub_array (start_offset, caret_count);
       unsigned int count = *caret_count;
       for (unsigned int i = 0; i < count; i++)
-	caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id);
+	caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
     }
 
     return carets.len;
@@ -244,6 +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,
 				      unsigned int start_offset,
 				      unsigned int *caret_count /* IN/OUT */,
 				      hb_position_t *caret_array /* OUT */) const
@@ -256,7 +261,7 @@ struct LigCaretList
       return 0;
     }
     const LigGlyph &lig_glyph = this+ligGlyph[index];
-    return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
+    return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -367,7 +372,9 @@ struct GDEF
 				      unsigned int start_offset,
 				      unsigned int *caret_count /* IN/OUT */,
 				      hb_position_t *caret_array /* OUT */) const
-  { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
+  { return (this+ligCaretList).get_lig_carets (font,
+					       direction, glyph_id, get_var_store(),
+					       start_offset, caret_count, caret_array); }
 
   inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
   inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 83b8060..1893f0e 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -103,17 +103,17 @@ struct ValueFormat : USHORT
   inline unsigned int get_size (void) const
   { return get_len () * Value::static_size; }
 
-  void apply_value (hb_font_t            *font,
-		    hb_direction_t        direction,
+  void apply_value (hb_apply_context_t   *c,
 		    const void           *base,
 		    const Value          *values,
 		    hb_glyph_position_t  &glyph_pos) const
   {
     unsigned int format = *this;
-    hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
-
     if (!format) return;
 
+    hb_font_t *font = c->font;
+    hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction);
+
     if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++));
     if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++));
     if (format & xAdvance) {
@@ -131,25 +131,26 @@ struct ValueFormat : USHORT
     bool use_x_device = font->x_ppem || font->num_coords;
     bool use_y_device = font->y_ppem || font->num_coords;
 
-
     if (!use_x_device && !use_y_device) return;
 
+    const VarStore &store = c->var_store;
+
     /* pixel -> fractional pixel */
     if (format & xPlaDevice) {
-      if (use_x_device) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font);
+      if (use_x_device) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font, store);
       values++;
     }
     if (format & yPlaDevice) {
-      if (use_y_device) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font);
+      if (use_y_device) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font, store);
       values++;
     }
     if (format & xAdvDevice) {
-      if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
+      if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font, store);
       values++;
     }
     if (format & yAdvDevice) {
       /* y_advance values grow downward but font-space grows upward, hence negation */
-      if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
+      if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font, store);
       values++;
     }
   }
@@ -295,9 +296,9 @@ struct AnchorFormat3
     *y = font->em_scale_y (yCoordinate);
 
     if (font->x_ppem || font->num_coords)
-      *x += (this+xDeviceTable).get_x_delta (font);
+      *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
     if (font->y_ppem || font->num_coords)
-      *y += (this+yDeviceTable).get_x_delta (font);
+      *y += (this+yDeviceTable).get_x_delta (font, c->var_store);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -475,8 +476,7 @@ struct SinglePosFormat1
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    valueFormat.apply_value (c->font, c->direction, this,
-			     values, buffer->cur_pos());
+    valueFormat.apply_value (c, this, values, buffer->cur_pos());
 
     buffer->idx++;
     return_trace (true);
@@ -526,7 +526,7 @@ struct SinglePosFormat2
 
     if (likely (index >= valueCount)) return_trace (false);
 
-    valueFormat.apply_value (c->font, c->direction, this,
+    valueFormat.apply_value (c, this,
 			     &values[index * valueFormat.get_len ()],
 			     buffer->cur_pos());
 
@@ -643,10 +643,8 @@ struct PairSet
         min = mid + 1;
       else
       {
-	valueFormats[0].apply_value (c->font, c->direction, this,
-				     &record->values[0], buffer->cur_pos());
-	valueFormats[1].apply_value (c->font, c->direction, this,
-				     &record->values[len1], buffer->pos[pos]);
+	valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+	valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
 	if (len2)
 	  pos++;
 	buffer->idx = pos;
@@ -793,10 +791,8 @@ struct PairPosFormat2
     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
 
     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
-    valueFormat1.apply_value (c->font, c->direction, this,
-			      v, buffer->cur_pos());
-    valueFormat2.apply_value (c->font, c->direction, this,
-			      v + len1, buffer->pos[skippy_iter.idx]);
+    valueFormat1.apply_value (c, this, v, buffer->cur_pos());
+    valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
 
     buffer->idx = skippy_iter.idx;
     if (len2)
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 997d225..1f501c6 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -469,6 +469,7 @@ struct hb_apply_context_t :
   unsigned int lookup_props;
   const GDEF &gdef;
   bool has_glyph_classes;
+  const VarStore &var_store;
   skipping_iterator_t iter_input, iter_context;
   unsigned int lookup_index;
   unsigned int debug_depth;
@@ -487,6 +488,7 @@ struct hb_apply_context_t :
 			lookup_props (0),
 			gdef (*hb_ot_layout_from_face (face)->gdef),
 			has_glyph_classes (gdef.has_glyph_classes ()),
+			var_store (gdef.get_var_store ()),
 			iter_input (),
 			iter_context (),
 			lookup_index ((unsigned int) -1),
commit dcfd309533ac83e44369dea7204d668623b08207
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 16:51:07 2016 -0700

    [GX] Change GDEF API to return varStore

diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index f8bbe31..e7d14f6 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -374,9 +374,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 float get_var_delta (unsigned int outer, unsigned int inner,
-			      int *coords, unsigned int coord_count) const
-  { return version.to_int () >= 0x00010003u ? (this+varStore).get_delta (outer, inner, coords, coord_count) : 0.; }
+  inline const VarStore &get_var_store (void) const
+  { return version.to_int () >= 0x00010003u ? this+varStore : Null(VarStore); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
commit 49cb87850c2692be45b201168c8ce10b263168cc
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 16:27:03 2016 -0700

    [GX] Pass apply-context down to get_anchor()
    
    Needed to access GDEF for varStore.

diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index d5db21d..83b8060 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -231,11 +231,12 @@ struct ValueFormat : USHORT
 
 struct AnchorFormat1
 {
-  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
+  inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
 			  hb_position_t *x, hb_position_t *y) const
   {
-      *x = font->em_scale_x (xCoordinate);
-      *y = font->em_scale_y (yCoordinate);
+    hb_font_t *font = c->font;
+    *x = font->em_scale_x (xCoordinate);
+    *y = font->em_scale_y (yCoordinate);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -254,18 +255,19 @@ struct AnchorFormat1
 
 struct AnchorFormat2
 {
-  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
+  inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id,
 			  hb_position_t *x, hb_position_t *y) const
   {
-      unsigned int x_ppem = font->x_ppem;
-      unsigned int y_ppem = font->y_ppem;
-      hb_position_t cx, cy;
-      hb_bool_t ret;
+    hb_font_t *font = c->font;
+    unsigned int x_ppem = font->x_ppem;
+    unsigned int y_ppem = font->y_ppem;
+    hb_position_t cx, cy;
+    hb_bool_t ret;
 
-      ret = (x_ppem || y_ppem) &&
-             font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
-      *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
-      *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
+    ret = (x_ppem || y_ppem) &&
+	   font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
+    *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
+    *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -285,16 +287,17 @@ struct AnchorFormat2
 
 struct AnchorFormat3
 {
-  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
+  inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
 			  hb_position_t *x, hb_position_t *y) const
   {
-      *x = font->em_scale_x (xCoordinate);
-      *y = font->em_scale_y (yCoordinate);
+    hb_font_t *font = c->font;
+    *x = font->em_scale_x (xCoordinate);
+    *y = font->em_scale_y (yCoordinate);
 
-      if (font->x_ppem || font->num_coords)
-	*x += (this+xDeviceTable).get_x_delta (font);
-      if (font->y_ppem || font->num_coords)
-	*y += (this+yDeviceTable).get_x_delta (font);
+    if (font->x_ppem || font->num_coords)
+      *x += (this+xDeviceTable).get_x_delta (font);
+    if (font->y_ppem || font->num_coords)
+      *y += (this+yDeviceTable).get_x_delta (font);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -321,14 +324,14 @@ struct AnchorFormat3
 
 struct Anchor
 {
-  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
+  inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id,
 			  hb_position_t *x, hb_position_t *y) const
   {
     *x = *y = 0;
     switch (u.format) {
-    case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
-    case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
-    case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
+    case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
+    case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
+    case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
     default:						 return;
     }
   }
@@ -428,8 +431,8 @@ struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage orde
 
     hb_position_t mark_x, mark_y, base_x, base_y;
 
-    mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
-    glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+    mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
+    glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
     hb_glyph_position_t &o = buffer->cur_pos();
     o.x_offset = base_x - mark_x;
@@ -931,8 +934,8 @@ struct CursivePosFormat1
     unsigned int j = skippy_iter.idx;
 
     hb_position_t entry_x, entry_y, exit_x, exit_y;
-    (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
-    (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
+    (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
+    (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
 
     hb_glyph_position_t *pos = buffer->pos;
 
commit f0c3fd8c9ab402be923fe0845fb51d99841829b6
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 16:22:45 2016 -0700

    [GX] Add varStore member to GDEF
    
    Still not hooked up from GPOS.

diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 93323c8..f8bbe31 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -373,6 +373,11 @@ struct GDEF
   inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   { 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 float get_var_delta (unsigned int outer, unsigned int inner,
+			      int *coords, unsigned int coord_count) const
+  { return version.to_int () >= 0x00010003u ? (this+varStore).get_delta (outer, inner, coords, coord_count) : 0.; }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -382,7 +387,8 @@ struct GDEF
 		  attachList.sanitize (c, this) &&
 		  ligCaretList.sanitize (c, this) &&
 		  markAttachClassDef.sanitize (c, this) &&
-		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)));
+		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
   }
 
 
@@ -410,7 +416,7 @@ struct GDEF
 
   protected:
   FixedVersion<>version;		/* Version of the GDEF table--currently
-					 * 0x00010002u */
+					 * 0x00010003u */
   OffsetTo<ClassDef>
 		glyphClassDef;		/* Offset to class definition table
 					 * for glyph type--from beginning of
@@ -431,7 +437,12 @@ struct GDEF
 		markGlyphSetsDef;	/* Offset to the table of mark set
 					 * definitions--from beginning of GDEF
 					 * header (may be NULL).  Introduced
-					 * in version 00010002. */
+					 * in version 0x00010002. */
+  OffsetTo<VarStore, ULONG>
+		varStore;		/* Offset to the table of Item Variation
+					 * Store--from beginning of GDEF
+					 * header (may be NULL).  Introduced
+					 * in version 0x00010003. */
   public:
   DEFINE_SIZE_MIN (12);
 };
commit 5c971f8dbc823dbad4a2869cf9e835095ab6ddb2
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 16:05:17 2016 -0700

    Minor change to GDEF, in prep for new version

diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 2b4bc5a..93323c8 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -369,9 +369,9 @@ struct GDEF
 				      hb_position_t *caret_array /* OUT */) const
   { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
 
-  inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef[0] != 0; }
+  inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
   inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
-  { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
+  { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -382,7 +382,7 @@ struct GDEF
 		  attachList.sanitize (c, this) &&
 		  ligCaretList.sanitize (c, this) &&
 		  markAttachClassDef.sanitize (c, this) &&
-		  (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
+		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)));
   }
 
 
@@ -428,12 +428,12 @@ struct GDEF
 					 * mark attachment type--from beginning
 					 * of GDEF header (may be Null) */
   OffsetTo<MarkGlyphSets>
-		markGlyphSetsDef[VAR];	/* Offset to the table of mark set
+		markGlyphSetsDef;	/* Offset to the table of mark set
 					 * definitions--from beginning of GDEF
 					 * header (may be NULL).  Introduced
 					 * in version 00010002. */
   public:
-  DEFINE_SIZE_ARRAY (12, markGlyphSetsDef);
+  DEFINE_SIZE_MIN (12);
 };
 
 
commit dc9f2297998b4cbc4f9e4c2591fc2bb5f92986d1
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 15:40:15 2016 -0700

    [GX] Port variation stuff to Variation Store design
    
    Not hooked up to GDEF yet.

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index bef26e1..ad67972 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1162,6 +1162,180 @@ struct ClassDef
 
 
 /*
+ * Item Variation Store
+ */
+
+struct VarRegionAxis
+{
+  inline float evaluate (int coord) const
+  {
+    int start = startCoord, peak = peakCoord, end = endCoord;
+
+    /* TODO Move these to sanitize(). */
+    if (unlikely (start > peak || peak > end))
+      return 1.;
+    if (unlikely (start < 0 && end > 0 && peak != 0))
+      return 1.;
+
+    if (peak == 0 || coord == peak)
+      return 1.;
+
+    if (coord <= start || end <= coord)
+      return 0.;
+
+    /* Interpolate */
+    if (coord < peak)
+      return float (coord - start) / (peak - start);
+    else
+      return float (end - coord) / (end - peak);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+    /* TODO Handle invalid start/peak/end configs, so we don't
+     * have to do that at runtime. */
+  }
+
+  public:
+  F2DOT14	startCoord;
+  F2DOT14	peakCoord;
+  F2DOT14	endCoord;
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct VarRegionList
+{
+  inline float evaluate (unsigned int region_index,
+			 int *coords, unsigned int coord_len) const
+  {
+    if (unlikely (region_index >= regionCount))
+      return 0.;
+
+    const VarRegionAxis *axes = axesZ + (region_index * axisCount);
+
+    float v = 1.;
+    unsigned int count = MIN (coord_len, (unsigned int) axisCount);
+    for (unsigned int i = 0; i < count; i++)
+    {
+      float factor = axes[i].evaluate (coords[i]);
+      if (factor == 0.)
+        return 0.;
+      v *= factor;
+    }
+    return v;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  c->check_array (axesZ, axesZ[0].static_size,
+				  (unsigned int) axisCount * (unsigned int) regionCount));
+  }
+
+  protected:
+  USHORT	axisCount;
+  USHORT	regionCount;
+  VarRegionAxis	axesZ[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (4, axesZ);
+};
+
+struct VarData
+{
+  inline unsigned int get_row_size (void) const
+  { return shortCount + regionIndices.len; }
+
+  inline unsigned int get_size (void) const
+  { return itemCount * get_row_size (); }
+
+  inline float get_delta (unsigned int inner,
+			  int *coords, unsigned int coord_count,
+			  const VarRegionList &regions) const
+  {
+    if (unlikely (inner >= itemCount))
+      return 0.;
+
+   unsigned int count = regionIndices.len;
+   unsigned int scount = shortCount;
+
+   const BYTE *bytes = &StructAfter<BYTE> (regionIndices);
+   const BYTE *row = bytes + inner * (scount + count);
+
+
+   float delta = 0.;
+   unsigned int i = 0;
+
+   const SHORT *scursor = reinterpret_cast<const SHORT *> (row);
+   for (; i < scount; i++)
+   {
+     float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
+     delta += scalar * *scursor++;
+   }
+   const INT8 *bcursor = reinterpret_cast<const INT8 *> (scursor);
+   for (; i < count; i++)
+   {
+     float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
+     delta += scalar * *bcursor++;
+   }
+
+   return delta;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  regionIndices.sanitize(c) &&
+		  shortCount <= regionIndices.len &&
+		  c->check_array (&StructAfter<BYTE> (regionIndices),
+				  get_row_size (), itemCount));
+  }
+
+  protected:
+  USHORT		itemCount;
+  USHORT		shortCount;
+  ArrayOf<USHORT>	regionIndices;
+  BYTE			bytesX[VAR];
+  public:
+  DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
+};
+
+struct VarStore
+{
+  inline float get_delta (unsigned int outer, unsigned int inner,
+			  int *coords, unsigned int coord_count) const
+  {
+    if (unlikely (outer >= dataSets.len))
+      return 0.;
+
+    return (this+dataSets[outer]).get_delta (inner,
+					     coords, coord_count,
+					     this+regions);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  format == 1 &&
+		  regions.sanitize (c, this) &&
+		  dataSets.sanitize (c, this));
+  }
+
+  protected:
+  USHORT				format;
+  OffsetTo<VarRegionList, ULONG>	regions;
+  OffsetArrayOf<VarData, ULONG>		dataSets;
+  public:
+  DEFINE_SIZE_ARRAY (8, dataSets);
+};
+
+
+/*
  * Device Tables
  */
 
@@ -1238,95 +1412,10 @@ struct HintingDevice
   DEFINE_SIZE_ARRAY (6, deltaValue);
 };
 
-
-struct VariationAxis
-{
-  inline float evaluate (int *coords, unsigned int coord_len) const
-  {
-    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
-
-    int start = startCoord, peak = peakCoord, end = endCoord;
-    //if (coord == 0) return 0;
-    //if (start < 0 && end > 0) return 0.;
-    if (coord < start || coord > end) return 0.;
-    if (coord == peak) return 1.;
-    /* Interpolate */
-    if (coord < peak)
-      return float (coord - start) / (peak - start);
-    else
-      return float (end - coord) / (end - peak);
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
-  }
-
-  public:
-  Index		axisIndex;
-  F2DOT14	startCoord;
-  F2DOT14	peakCoord;
-  F2DOT14	endCoord;
-  public:
-  DEFINE_SIZE_STATIC (8);
-};
-
-struct VariationTuple
-{
-  inline float evaluate (int *coords, unsigned int coord_len) const
-  {
-    float v = 1.;
-    unsigned int count = axes.len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      float factor = (this+axes[i]).evaluate (coords, coord_len);
-      v *= factor;
-      if (factor == 0.)
-        break;
-    }
-    return v;
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (axes.sanitize (c, this));
-  }
-
-  OffsetArrayOf<VariationAxis>
-		axes;
-  public:
-  DEFINE_SIZE_ARRAY (2, axes);
-};
-
-struct VariationMap
-{
-  inline const VariationTuple& operator [] (unsigned int i) const
-  { return this+tuples[i]; }
-
-  inline unsigned int get_len (void) const
-  { return tuples.len; }
-
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (tuples.sanitize (c, this));
-  }
-
-  OffsetArrayOf<VariationTuple>
-		tuples;
-  public:
-  DEFINE_SIZE_ARRAY (2, tuples);
-};
-
 struct VariationDevice
 {
   friend struct Device;
 
-  static const unsigned short FORMAT_BYTES  = 0x0100;
-  static const unsigned short FORMAT_SHORTS = 0x0101;
-
   private:
 
   inline hb_position_t get_x_delta (hb_font_t *font) const
@@ -1338,40 +1427,24 @@ struct VariationDevice
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  c->check_array (&deltaValue, get_item_size (), deltaCount));
+    return_trace (c->check_struct (this));
   }
 
   private:
 
-  inline unsigned int get_item_size (void) const
-  { return deltaFormat == FORMAT_BYTES ? 1 : 2; }
-
   inline float get_delta (int *coords, unsigned int coord_count) const
   {
     float v = 0;
-    const VariationMap &map = this+variationMap;
-    unsigned int count = MIN ((unsigned int) deltaCount, map.get_len ());
-    if (get_item_size () == 1)
-      for (unsigned int i = 0; i < count; i++)
-	v += deltaValue.bytesZ[i] * map[i].evaluate (coords, coord_count);
-   else
-      for (unsigned int i = 0; i < count; i++)
-	v += deltaValue.shortsZ[i] * map[i].evaluate (coords, coord_count);
+    /* XXXXXXXXXXXXXXX call into GDEF. */
     return v;
   }
 
   protected:
-  OffsetTo<VariationMap>
-		variationMap;	/* Offset to variation mapping for this table. */
-  USHORT	deltaCount;	/* Number of deltas in this table. */
-  USHORT	deltaFormat;	/* Format identifier for this table: 0x0100 or 0x0101 */
-  union {
-    INT8	bytesZ[VAR];	/* Deltas as signed bytes in design space; format=0x0100 */
-    SHORT	shortsZ[VAR];	/* Deltas as signed shorts in design space; format=0x0101 */
-  } deltaValue;
+  USHORT	outerIndex;
+  USHORT	innerIndex;
+  USHORT	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
   public:
-  DEFINE_SIZE_ARRAY (6, deltaValue.shortsZ);
+  DEFINE_SIZE_STATIC (6);
 };
 
 struct Device
@@ -1382,7 +1455,7 @@ struct Device
     {
     case 1: case 2: case 3:
       return u.hinting.get_x_delta (font);
-    case VariationDevice::FORMAT_BYTES: case VariationDevice::FORMAT_SHORTS:
+    case 0x8000:
       return u.variation.get_x_delta (font);
     default:
       return 0;
@@ -1394,8 +1467,7 @@ struct Device
     {
     case 1: case 2: case 3:
       return u.hinting.get_x_delta (font);
-    case VariationDevice::FORMAT_BYTES: case VariationDevice::FORMAT_SHORTS:
-      return u.variation.get_x_delta (font);
+    case 0x8000:
     default:
       return 0;
     }
@@ -1408,7 +1480,7 @@ struct Device
     switch (u.b.format) {
     case 1: case 2: case 3:
       return_trace (u.hinting.sanitize (c));
-    case VariationDevice::FORMAT_BYTES: case VariationDevice::FORMAT_SHORTS:
+    case 0x8000:
       return_trace (u.variation.sanitize (c));
     default:
       return_trace (true);
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 424a34e..d5db21d 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -370,7 +370,7 @@ struct AnchorMatrix
   {
     TRACE_SANITIZE (this);
     if (!c->check_struct (this)) return_trace (false);
-    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
+    if (unlikely (_hb_unsigned_int_mul_overflows (rows, cols))) return_trace (false);
     unsigned int count = rows * cols;
     if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
     for (unsigned int i = 0; i < count; i++)
commit a7edeb6f02cbc4418285fdfc58ef8a8740a380e9
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 15:39:52 2016 -0700

    Make OffsetArrayOf take OffsetType template argument

diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index bc7e9a4..5b7ff33 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -952,8 +952,8 @@ struct ArrayOf
 };
 
 /* Array of Offset's */
-template <typename Type>
-struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
+template <typename Type, typename OffsetType=USHORT>
+struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {};
 
 /* Array of offsets relative to the beginning of the array itself. */
 template <typename Type>
commit 8dddc231cf9d934eb93a39f2657717cbdad43a64
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 13:17:33 2016 -0700

    [GX] Revert "[GX] Add VariationAlternates, to allow conditional lookups in GSUB/GPOS"
    
    This reverts commit 2859f1c7174d6f7ae5dcf0db5411bc0182b21594.
    We are going in a different direction.

diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 9bd2fa4..bc7e9a4 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -630,7 +630,6 @@ struct IntType
   inline operator Type(void) const { return v; }
   inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
   inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
-  inline unsigned int get_size (void) const { return Size; }
   static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
   inline int cmp (Type a) const
   {
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 61bf1fa..bef26e1 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -575,7 +575,6 @@ struct LookupFlag : USHORT
     IgnoreMarks		= 0x0008u,
     IgnoreFlags		= 0x000Eu,
     UseMarkFilteringSet	= 0x0010u,
-    UseVariationAlternates= 0x0020u,
     Reserved		= 0x00E0u,
     MarkAttachmentType	= 0xFF00u
   };
@@ -588,88 +587,6 @@ struct LookupFlag : USHORT
 HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
 namespace OT {
 
-struct VariationGridAxis
-{
-  inline int locate (int *coords, unsigned int coord_len) const
-  {
-    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
-
-    unsigned int count = axisCoords.len;
-    unsigned int i = 0;
-    while (i + 1 < count && coord < axisCoords[i + 1])
-      i++;
-
-    return axisCoords[i] <= coord ? i : -1;
-  }
-
-  inline unsigned int get_len (void) const
-  {
-    return axisCoords.len - 1;
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && axisCoords.sanitize (c));
-  }
-
-  Index				axisIndex;
-  SortedArrayOf<F2DOT14>	axisCoords;
-  public:
-  DEFINE_SIZE_ARRAY (4, axisCoords);
-};
-
-struct VariationGrid
-{
-  inline int locate (int *coords, unsigned int coord_len) const
-  {
-    int location = 0;
-    unsigned int count = axes.len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      const VariationGridAxis &axis = (this+axes[i]);
-      int axisLoc = axis.locate (coords, coord_len);
-      if (axisLoc == -1)
-        return -1;
-      location = location * (axis.get_len () - 1) + axisLoc; /* XXX Check for overflow?. */
-    }
-    return location;
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (axes.sanitize (c, this));
-  }
-
-  OffsetArrayOf<VariationGridAxis>
-		axes;
-  public:
-  DEFINE_SIZE_ARRAY (2, axes);
-};
-
-struct VariationAlternates
-{
-  inline unsigned int get_lookup_index (int *coords, unsigned int coord_len) const
-  {
-    int location = (this+grid).locate (coords, coord_len);
-    if (location == -1)
-      return 0xFFFE; /* TODO: give it a name. */
-    return lookupIndex[location];
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (grid.sanitize (c, this) && lookupIndex.sanitize (c));
-  }
-
-  OffsetTo<VariationGrid>	grid;
-  IndexArray			lookupIndex;
-  public:
-  DEFINE_SIZE_ARRAY (4, lookupIndex);
-};
-
 struct Lookup
 {
   inline unsigned int get_subtable_count (void) const { return subTable.len; }
@@ -738,17 +655,10 @@ struct Lookup
     TRACE_SANITIZE (this);
     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
-    const void *cursor = &StructAfter<char> (subTable);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      const USHORT &markFilteringSet = CastR<USHORT> (cursor);
+      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
       if (!markFilteringSet.sanitize (c)) return_trace (false);
-      cursor = &StructAfter<char> (markFilteringSet);
-    }
-    if (lookupFlag & LookupFlag::UseVariationAlternates)
-    {
-      const OffsetTo<VariationAlternates,ULONG> &varAlts = CastR<const OffsetTo<VariationAlternates,ULONG> > (cursor);
-      if (!varAlts.sanitize (c, this)) return_trace (false);
     }
     return_trace (true);
   }
@@ -761,13 +671,8 @@ struct Lookup
   USHORT	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
 					 * structure. This field is only present if bit
 					 * UseMarkFilteringSet of lookup flags is set. */
-  OffsetTo<VariationAlternates,ULONG>
-		variationAlternatesZ[VAR];
-					/* Index (base 0) into GDEF mark glyph sets
-					 * structure. This field is only present if bit
-					 * UseMarkFilteringSet of lookup flags is set. */
   public:
-  DEFINE_SIZE_MIN (6);
+  DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
 };
 
 typedef OffsetListOf<Lookup> LookupList;
commit bb4d2e6ed562c248fff15313a013d49e38a18789
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Sep 9 13:08:52 2016 -0700

    [GX] Free GX coordinates

diff --git a/src/hb-font.cc b/src/hb-font.cc
index 75c8515..978e7dd 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1254,7 +1254,10 @@ hb_font_destroy (hb_font_t *font)
   hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
 
-  /* TODO: destroy variation coordinates. */
+  if (font->x_coords)
+    free (font->x_coords);
+  if (font->y_coords && font->y_coords != font->x_coords)
+    free (font->y_coords);
 
   free (font);
 }
commit baa329c6a12c7ffd56feed32351d9405b7d1651b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Mar 18 15:52:24 2016 -0700

    [GX] Add compact VariationDevice implementation
    
    Add compact format that uses signed bytes instead of shorts.

diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 865429d..9bd2fa4 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -653,6 +653,7 @@ struct IntType
 
 typedef	IntType<int8_t	, 1> CHAR;	/* 8-bit signed integer. */
 typedef	IntType<uint8_t	, 1> BYTE;	/* 8-bit unsigned integer. */
+typedef	IntType<int8_t	, 1> INT8;	/* 8-bit signed integer. */
 typedef IntType<uint16_t, 2> USHORT;	/* 16-bit unsigned integer. */
 typedef IntType<int16_t,  2> SHORT;	/* 16-bit signed integer. */
 typedef IntType<uint32_t, 4> ULONG;	/* 32-bit unsigned integer. */
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 328472f..61bf1fa 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1419,6 +1419,9 @@ struct VariationDevice
 {
   friend struct Device;
 
+  static const unsigned short FORMAT_BYTES  = 0x0100;
+  static const unsigned short FORMAT_SHORTS = 0x0101;
+
   private:
 
   inline hb_position_t get_x_delta (hb_font_t *font) const
@@ -1431,29 +1434,39 @@ struct VariationDevice
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
-		  c->check_array (&deltaValue, SHORT::static_size, deltaCount));
+		  c->check_array (&deltaValue, get_item_size (), deltaCount));
   }
 
   private:
 
+  inline unsigned int get_item_size (void) const
+  { return deltaFormat == FORMAT_BYTES ? 1 : 2; }
+
   inline float get_delta (int *coords, unsigned int coord_count) const
   {
     float v = 0;
     const VariationMap &map = this+variationMap;
     unsigned int count = MIN ((unsigned int) deltaCount, map.get_len ());
-    for (unsigned int i = 0; i < count; i++)
-      v += deltaValue[i] * map[i].evaluate (coords, coord_count);
+    if (get_item_size () == 1)
+      for (unsigned int i = 0; i < count; i++)
+	v += deltaValue.bytesZ[i] * map[i].evaluate (coords, coord_count);
+   else
+      for (unsigned int i = 0; i < count; i++)
+	v += deltaValue.shortsZ[i] * map[i].evaluate (coords, coord_count);
     return v;
   }
 
   protected:
   OffsetTo<VariationMap>
-		variationMap;		/* Offset to variation mapping for this table. */
-  USHORT	deltaCount;		/* Number of deltas in this table. */
-  USHORT	deltaFormat;		/* Format identifier for this table: 0x10 */
-  SHORT		deltaValue[VAR];	/* Deltas as signed values in design space. */
+		variationMap;	/* Offset to variation mapping for this table. */
+  USHORT	deltaCount;	/* Number of deltas in this table. */
+  USHORT	deltaFormat;	/* Format identifier for this table: 0x0100 or 0x0101 */
+  union {
+    INT8	bytesZ[VAR];	/* Deltas as signed bytes in design space; format=0x0100 */
+    SHORT	shortsZ[VAR];	/* Deltas as signed shorts in design space; format=0x0101 */
+  } deltaValue;
   public:
-  DEFINE_SIZE_ARRAY (6, deltaValue);
+  DEFINE_SIZE_ARRAY (6, deltaValue.shortsZ);
 };
 
 struct Device
@@ -1464,7 +1477,7 @@ struct Device
     {
     case 1: case 2: case 3:
       return u.hinting.get_x_delta (font);
-    case 0x10:
+    case VariationDevice::FORMAT_BYTES: case VariationDevice::FORMAT_SHORTS:
       return u.variation.get_x_delta (font);
     default:
       return 0;
@@ -1476,7 +1489,7 @@ struct Device
     {
     case 1: case 2: case 3:
       return u.hinting.get_x_delta (font);
-    case 0x10:
+    case VariationDevice::FORMAT_BYTES: case VariationDevice::FORMAT_SHORTS:
       return u.variation.get_x_delta (font);
     default:
       return 0;
@@ -1490,7 +1503,7 @@ struct Device
     switch (u.b.format) {
     case 1: case 2: case 3:
       return_trace (u.hinting.sanitize (c));
-    case 0x10:
+    case VariationDevice::FORMAT_BYTES: case VariationDevice::FORMAT_SHORTS:
       return_trace (u.variation.sanitize (c));
     default:
       return_trace (true);
commit 71b06fd392680b6fcfece60d8a83ba6c56eada09
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Mar 12 23:49:09 2016 -0800

    [GX] Add VariationAlternates, to allow conditional lookups in GSUB/GPOS
    
    Not hooked up to runtime yet.

diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 66f1c08..865429d 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -630,6 +630,7 @@ struct IntType
   inline operator Type(void) const { return v; }
   inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
   inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
+  inline unsigned int get_size (void) const { return Size; }
   static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
   inline int cmp (Type a) const
   {
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 3154cfe..328472f 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -575,6 +575,7 @@ struct LookupFlag : USHORT
     IgnoreMarks		= 0x0008u,
     IgnoreFlags		= 0x000Eu,
     UseMarkFilteringSet	= 0x0010u,
+    UseVariationAlternates= 0x0020u,
     Reserved		= 0x00E0u,
     MarkAttachmentType	= 0xFF00u
   };
@@ -587,6 +588,88 @@ struct LookupFlag : USHORT
 HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
 namespace OT {
 
+struct VariationGridAxis
+{
+  inline int locate (int *coords, unsigned int coord_len) const
+  {
+    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
+
+    unsigned int count = axisCoords.len;
+    unsigned int i = 0;
+    while (i + 1 < count && coord < axisCoords[i + 1])
+      i++;
+
+    return axisCoords[i] <= coord ? i : -1;
+  }
+
+  inline unsigned int get_len (void) const
+  {
+    return axisCoords.len - 1;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && axisCoords.sanitize (c));
+  }
+
+  Index				axisIndex;
+  SortedArrayOf<F2DOT14>	axisCoords;
+  public:
+  DEFINE_SIZE_ARRAY (4, axisCoords);
+};
+
+struct VariationGrid
+{
+  inline int locate (int *coords, unsigned int coord_len) const
+  {
+    int location = 0;
+    unsigned int count = axes.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      const VariationGridAxis &axis = (this+axes[i]);
+      int axisLoc = axis.locate (coords, coord_len);
+      if (axisLoc == -1)
+        return -1;
+      location = location * (axis.get_len () - 1) + axisLoc; /* XXX Check for overflow?. */
+    }
+    return location;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (axes.sanitize (c, this));
+  }
+
+  OffsetArrayOf<VariationGridAxis>
+		axes;
+  public:
+  DEFINE_SIZE_ARRAY (2, axes);
+};
+
+struct VariationAlternates
+{
+  inline unsigned int get_lookup_index (int *coords, unsigned int coord_len) const
+  {
+    int location = (this+grid).locate (coords, coord_len);
+    if (location == -1)
+      return 0xFFFE; /* TODO: give it a name. */
+    return lookupIndex[location];
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (grid.sanitize (c, this) && lookupIndex.sanitize (c));
+  }
+
+  OffsetTo<VariationGrid>	grid;
+  IndexArray			lookupIndex;
+  public:
+  DEFINE_SIZE_ARRAY (4, lookupIndex);
+};
+
 struct Lookup
 {
   inline unsigned int get_subtable_count (void) const { return subTable.len; }
@@ -655,10 +738,17 @@ struct Lookup
     TRACE_SANITIZE (this);
     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
+    const void *cursor = &StructAfter<char> (subTable);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      const USHORT &markFilteringSet = CastR<USHORT> (cursor);
       if (!markFilteringSet.sanitize (c)) return_trace (false);
+      cursor = &StructAfter<char> (markFilteringSet);
+    }
+    if (lookupFlag & LookupFlag::UseVariationAlternates)
+    {
+      const OffsetTo<VariationAlternates,ULONG> &varAlts = CastR<const OffsetTo<VariationAlternates,ULONG> > (cursor);
+      if (!varAlts.sanitize (c, this)) return_trace (false);
     }
     return_trace (true);
   }
@@ -671,8 +761,13 @@ struct Lookup
   USHORT	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
 					 * structure. This field is only present if bit
 					 * UseMarkFilteringSet of lookup flags is set. */
+  OffsetTo<VariationAlternates,ULONG>
+		variationAlternatesZ[VAR];
+					/* Index (base 0) into GDEF mark glyph sets
+					 * structure. This field is only present if bit
+					 * UseMarkFilteringSet of lookup flags is set. */
   public:
-  DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
+  DEFINE_SIZE_MIN (6);
 };
 
 typedef OffsetListOf<Lookup> LookupList;
commit 976eeb8e025e2b7601a91e661d6e9a88bf8afbd2
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat Mar 12 23:28:12 2016 -0800

    [GX] Minor

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 52d213c..3154cfe 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1243,8 +1243,7 @@ struct VariationAxis
 {
   inline float evaluate (int *coords, unsigned int coord_len) const
   {
-    unsigned int i = axisIndex;
-    int coord = i < coord_len ? coords[i] : 0;
+    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
 
     int start = startCoord, peak = peakCoord, end = endCoord;
     //if (coord == 0) return 0;
commit ed8a9067ca0fe51ac4b80dab55db596763df72bb
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Mar 2 12:54:35 2016 -0800

    [GX] Minor

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index b1dcb01..52d213c 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1336,7 +1336,8 @@ struct VariationDevice
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && c->check_range (&deltaValue, deltaCount * SHORT::static_size));
+    return_trace (c->check_struct (this) &&
+		  c->check_array (&deltaValue, SHORT::static_size, deltaCount));
   }
 
   private:
commit 15c5ee67473a17859a919104c5e6fed1f813aa65
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Mar 2 12:41:49 2016 +0900

    [GX] Minor rename

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index e34acd9..b1dcb01 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1336,7 +1336,7 @@ struct VariationDevice
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && c->check_range (&deltaValue, numDeltas * SHORT::static_size));
+    return_trace (c->check_struct (this) && c->check_range (&deltaValue, deltaCount * SHORT::static_size));
   }
 
   private:
@@ -1345,7 +1345,7 @@ struct VariationDevice
   {
     float v = 0;
     const VariationMap &map = this+variationMap;
-    unsigned int count = MIN ((unsigned int) numDeltas, map.get_len ());
+    unsigned int count = MIN ((unsigned int) deltaCount, map.get_len ());
     for (unsigned int i = 0; i < count; i++)
       v += deltaValue[i] * map[i].evaluate (coords, coord_count);
     return v;
@@ -1354,7 +1354,7 @@ struct VariationDevice
   protected:
   OffsetTo<VariationMap>
 		variationMap;		/* Offset to variation mapping for this table. */
-  USHORT	numDeltas;		/* Number of deltas for in this table. */
+  USHORT	deltaCount;		/* Number of deltas in this table. */
   USHORT	deltaFormat;		/* Format identifier for this table: 0x10 */
   SHORT		deltaValue[VAR];	/* Deltas as signed values in design space. */
   public:
commit 4c535a822f16b23a4e41e14d1b17fe179b83eabc
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Mar 2 12:21:36 2016 +0900

    [GX] Hookup VariationDevice to Device table implementation

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 168dbe4..e34acd9 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1165,8 +1165,11 @@ struct ClassDef
  * Device Tables
  */
 
-struct Device
+struct HintingDevice
 {
+  friend struct Device;
+
+  private:
 
   inline hb_position_t get_x_delta (hb_font_t *font) const
   { return get_delta (font->x_ppem, font->x_scale); }
@@ -1320,6 +1323,9 @@ struct VariationMap
 
 struct VariationDevice
 {
+  friend struct Device;
+
+  private:
 
   inline hb_position_t get_x_delta (hb_font_t *font) const
   { return font->em_scalef_x (get_delta (font->x_coords, font->num_coords)); }
@@ -1355,6 +1361,63 @@ struct VariationDevice
   DEFINE_SIZE_ARRAY (6, deltaValue);
 };
 
+struct Device
+{
+  inline hb_position_t get_x_delta (hb_font_t *font) const
+  {
+    switch (u.b.format)
+    {
+    case 1: case 2: case 3:
+      return u.hinting.get_x_delta (font);
+    case 0x10:
+      return u.variation.get_x_delta (font);
+    default:
+      return 0;
+    }
+  }
+  inline hb_position_t get_y_delta (hb_font_t *font) const
+  {
+    switch (u.b.format)
+    {
+    case 1: case 2: case 3:
+      return u.hinting.get_x_delta (font);
+    case 0x10:
+      return u.variation.get_x_delta (font);
+    default:
+      return 0;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.b.format.sanitize (c)) return_trace (false);
+    switch (u.b.format) {
+    case 1: case 2: case 3:
+      return_trace (u.hinting.sanitize (c));
+    case 0x10:
+      return_trace (u.variation.sanitize (c));
+    default:
+      return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  struct {
+    USHORT		reserved1;
+    USHORT		reserved2;
+    USHORT		format;		/* Format identifier */
+    public:
+    DEFINE_SIZE_STATIC (6);
+  } b;
+  HintingDevice		hinting;
+  VariationDevice	variation;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (6, b);
+};
+
 
 } /* namespace OT */
 
commit a0c2366075fcb894212b9bf137e4dd34bb65537c
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Mar 1 19:42:24 2016 +0900

    [GX] Break out early if factor is zero
    
    Also disable sanity-checking of variation records.

diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index cd26db3..168dbe4 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1244,6 +1244,8 @@ struct VariationAxis
     int coord = i < coord_len ? coords[i] : 0;
 
     int start = startCoord, peak = peakCoord, end = endCoord;
+    //if (coord == 0) return 0;
+    //if (start < 0 && end > 0) return 0.;
     if (coord < start || coord > end) return 0.;
     if (coord == peak) return 1.;
     /* Interpolate */
@@ -1275,7 +1277,12 @@ struct VariationTuple
     float v = 1.;
     unsigned int count = axes.len;
     for (unsigned int i = 0; i < count; i++)
-      v *= (this+axes[i]).evaluate (coords, coord_len);
+    {
+      float factor = (this+axes[i]).evaluate (coords, coord_len);
+      v *= factor;
+      if (factor == 0.)
+        break;
+    }
     return v;
   }
 
commit ca286703164caf1eda665f6f27ef83bf04e2f8ba
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Mar 1 19:29:36 2016 +0900

    [GX] Towards anisotropic interpolation
    
    Also hookup to ValueRecord and Anchors.

diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 3a1e31f..48dc725 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -109,8 +109,9 @@ struct hb_font_t {
   unsigned int y_ppem;
 
   /* Font variation coordinates. */
-  int *coords;
-  unsigned int coord_count;
+  unsigned int num_coords;
+  int *x_coords;
+  int *y_coords;
 
   hb_font_funcs_t   *klass;
   void              *user_data;
diff --git a/src/hb-font.cc b/src/hb-font.cc
index b4b4d0a..75c8515 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1165,6 +1165,8 @@ hb_font_create_sub_font (hb_font_t *parent)
   font->x_ppem = parent->x_ppem;
   font->y_ppem = parent->y_ppem;
 
+  /* TODO: copy variation coordinates. */
+
   return font;
 }
 
@@ -1194,8 +1196,9 @@ hb_font_get_empty (void)
     0, /* x_ppem */
     0, /* y_ppem */
 
-    NULL, /* coords */
-    0, /* coord_count */
+    0, /* num_coords */
+    NULL, /* x_coords */
+    NULL, /* y_coords */
 
     const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
     NULL, /* user_data */
@@ -1251,6 +1254,8 @@ hb_font_destroy (hb_font_t *font)
   hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
 
+  /* TODO: destroy variation coordinates. */
+
   free (font);
 }
 
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index a18ce74..cd26db3 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1315,10 +1315,10 @@ struct VariationDevice
 {
 
   inline hb_position_t get_x_delta (hb_font_t *font) const
-  { return font->em_scalef_x (get_delta (font->coords, font->coord_count)); }
+  { return font->em_scalef_x (get_delta (font->x_coords, font->num_coords)); }
 
   inline hb_position_t get_y_delta (hb_font_t *font) const
-  { return font->em_scalef_y (get_delta (font->coords, font->coord_count)); }
+  { return font->em_scalef_y (get_delta (font->y_coords, font->num_coords)); }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index bbe390c..424a34e 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -109,7 +109,6 @@ struct ValueFormat : USHORT
 		    const Value          *values,
 		    hb_glyph_position_t  &glyph_pos) const
   {
-    unsigned int x_ppem, y_ppem;
     unsigned int format = *this;
     hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
 
@@ -129,27 +128,28 @@ struct ValueFormat : USHORT
 
     if (!has_device ()) return;
 
-    x_ppem = font->x_ppem;
-    y_ppem = font->y_ppem;
+    bool use_x_device = font->x_ppem || font->num_coords;
+    bool use_y_device = font->y_ppem || font->num_coords;
 
-    if (!x_ppem && !y_ppem) return;
+
+    if (!use_x_device && !use_y_device) return;
 
     /* pixel -> fractional pixel */
     if (format & xPlaDevice) {
-      if (x_ppem) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font);
+      if (use_x_device) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font);
       values++;
     }
     if (format & yPlaDevice) {
-      if (y_ppem) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font);
+      if (use_y_device) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font);
       values++;
     }
     if (format & xAdvDevice) {
-      if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
+      if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
       values++;
     }
     if (format & yAdvDevice) {
       /* y_advance values grow downward but font-space grows upward, hence negation */
-      if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
+      if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
       values++;
     }
   }
@@ -291,9 +291,9 @@ struct AnchorFormat3
       *x = font->em_scale_x (xCoordinate);
       *y = font->em_scale_y (yCoordinate);
 
-      if (font->x_ppem)
+      if (font->x_ppem || font->num_coords)
 	*x += (this+xDeviceTable).get_x_delta (font);
-      if (font->y_ppem)
+      if (font->y_ppem || font->num_coords)
 	*y += (this+yDeviceTable).get_x_delta (font);
   }
 
commit 6d9d3c55bbd4209ba339ccd2b925bb4a6c97f622
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Mar 1 19:12:08 2016 +0900

    [GX] Add data types for encoding numerical variations

diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index cda97a6..3a1e31f 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -108,6 +108,10 @@ struct hb_font_t {
   unsigned int x_ppem;
   unsigned int y_ppem;
 
+  /* Font variation coordinates. */
+  int *coords;
+  unsigned int coord_count;
+
   hb_font_funcs_t   *klass;
   void              *user_data;
   hb_destroy_func_t  destroy;
@@ -120,6 +124,8 @@ struct hb_font_t {
   { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
   inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
   inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
+  inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
+  inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
   inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
   { return em_scale (v, dir_scale (direction)); }
 
@@ -531,6 +537,10 @@ struct hb_font_t {
     scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
     return (hb_position_t) (scaled / upem);
   }
+  inline hb_position_t em_scalef (float v, int scale)
+  {
+    return (hb_position_t) (v * scale / face->get_upem ());
+  }
 };
 
 #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 08fcd64..b4b4d0a 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1194,6 +1194,9 @@ hb_font_get_empty (void)
     0, /* x_ppem */
     0, /* y_ppem */
 
+    NULL, /* coords */
+    0, /* coord_count */
+
     const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
     NULL, /* user_data */
     NULL, /* destroy */
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 34fa1b7..a18ce74 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -1236,6 +1236,119 @@ struct Device
 };
 
 
+struct VariationAxis
+{
+  inline float evaluate (int *coords, unsigned int coord_len) const
+  {
+    unsigned int i = axisIndex;
+    int coord = i < coord_len ? coords[i] : 0;
+
+    int start = startCoord, peak = peakCoord, end = endCoord;
+    if (coord < start || coord > end) return 0.;
+    if (coord == peak) return 1.;
+    /* Interpolate */
+    if (coord < peak)
+      return float (coord - start) / (peak - start);
+    else
+      return float (end - coord) / (end - peak);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  public:
+  Index		axisIndex;
+  F2DOT14	startCoord;
+  F2DOT14	peakCoord;
+  F2DOT14	endCoord;
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct VariationTuple
+{
+  inline float evaluate (int *coords, unsigned int coord_len) const
+  {
+    float v = 1.;
+    unsigned int count = axes.len;
+    for (unsigned int i = 0; i < count; i++)
+      v *= (this+axes[i]).evaluate (coords, coord_len);
+    return v;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (axes.sanitize (c, this));
+  }
+
+  OffsetArrayOf<VariationAxis>
+		axes;
+  public:
+  DEFINE_SIZE_ARRAY (2, axes);
+};
+
+struct VariationMap
+{
+  inline const VariationTuple& operator [] (unsigned int i) const
+  { return this+tuples[i]; }
+
+  inline unsigned int get_len (void) const
+  { return tuples.len; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (tuples.sanitize (c, this));
+  }
+
+  OffsetArrayOf<VariationTuple>
+		tuples;
+  public:
+  DEFINE_SIZE_ARRAY (2, tuples);
+};
+
+struct VariationDevice
+{
+
+  inline hb_position_t get_x_delta (hb_font_t *font) const
+  { return font->em_scalef_x (get_delta (font->coords, font->coord_count)); }
+
+  inline hb_position_t get_y_delta (hb_font_t *font) const
+  { return font->em_scalef_y (get_delta (font->coords, font->coord_count)); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && c->check_range (&deltaValue, numDeltas * SHORT::static_size));
+  }
+
+  private:
+
+  inline float get_delta (int *coords, unsigned int coord_count) const
+  {
+    float v = 0;
+    const VariationMap &map = this+variationMap;
+    unsigned int count = MIN ((unsigned int) numDeltas, map.get_len ());
+    for (unsigned int i = 0; i < count; i++)
+      v += deltaValue[i] * map[i].evaluate (coords, coord_count);
+    return v;
+  }
+
+  protected:
+  OffsetTo<VariationMap>
+		variationMap;		/* Offset to variation mapping for this table. */
+  USHORT	numDeltas;		/* Number of deltas for in this table. */
+  USHORT	deltaFormat;		/* Format identifier for this table: 0x10 */
+  SHORT		deltaValue[VAR];	/* Deltas as signed values in design space. */
+  public:
+  DEFINE_SIZE_ARRAY (6, deltaValue);
+};
+
+
 } /* namespace OT */
 
 


More information about the HarfBuzz mailing list