Add SkTypeface::getVariationDesignPosition.

Allow users to query a typeface's position in variation design space.

Change-Id: Id7cae439e795b8c9586394f11359fb7fe55e1c0b
Reviewed-on: https://skia-review.googlesource.com/8861
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index af188f8..e8d24db 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -335,8 +335,8 @@
   enabled = fontmgr_android_enabled
 
   deps = [
+    ":typeface_freetype",
     "//third_party/expat",
-    "//third_party/freetype2",
   ]
   sources = [
     "src/ports/SkFontMgr_android.cpp",
@@ -349,7 +349,7 @@
   enabled = is_linux && skia_use_freetype && !skia_use_fontconfig
 
   deps = [
-    "//third_party/freetype2",
+    ":typeface_freetype",
   ]
   sources = [
     "src/ports/SkFontMgr_custom.cpp",
@@ -365,8 +365,8 @@
   enabled = skia_use_freetype && skia_use_fontconfig
 
   deps = [
+    ":typeface_freetype",
     "//third_party:fontconfig",
-    "//third_party/freetype2",
   ]
   sources = [
     "src/ports/SkFontConfigInterface.cpp",
@@ -382,7 +382,7 @@
   enabled = is_fuchsia && skia_use_freetype
 
   deps = [
-    "//third_party/freetype2",
+    ":typeface_freetype",
   ]
   sources = [
     "src/ports/SkFontMgr_custom.cpp",
@@ -581,7 +581,6 @@
     ":sse41",
     ":sse42",
     ":ssse3",
-    ":typeface_freetype",
     ":webp",
     ":xml",
   ]
diff --git a/gm/fontscalerdistortable.cpp b/gm/fontscalerdistortable.cpp
index c557ec5..1823b50 100644
--- a/gm/fontscalerdistortable.cpp
+++ b/gm/fontscalerdistortable.cpp
@@ -49,9 +49,12 @@
 
                 SkFourByteTag tag = SkSetFourByteTag('w','g','h','t');
                 SkScalar styleValue = SkDoubleToScalar(0.5 + (5*j + i) * ((2.0 - 0.5) / (2 * 5)));
-                SkFontMgr::FontParameters::Axis axes[] = { { tag, styleValue } };
+                SkFontArguments::VariationPosition::Coordinate coordinates[] = {{tag, styleValue}};
+                SkFontArguments::VariationPosition position =
+                        { coordinates, SK_ARRAY_COUNT(coordinates) };
                 paint.setTypeface(sk_sp<SkTypeface>(fontMgr->createFromStream(
-                        distortable->duplicate(), SkFontMgr::FontParameters().setAxes(axes, 1))));
+                        distortable->duplicate(),
+                        SkFontArguments().setVariationDesignPosition(position))));
 
                 SkAutoCanvasRestore acr(canvas, true);
                 canvas->translate(SkIntToScalar(30 + i * 100), SkIntToScalar(20));
diff --git a/gn/core.gni b/gn/core.gni
index 7dd997e..3b71c45 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -398,6 +398,7 @@
   "$_include/core/SkDrawLooper.h",
   "$_include/core/SkFlattenable.h",
   "$_include/core/SkFlattenableSerialization.h",
+  "$_include/core/SkFontArguments.h",
   "$_include/core/SkFontLCDConfig.h",
   "$_include/core/SkFontStyle.h",
   "$_include/core/SkGraphics.h",
diff --git a/include/core/SkFontArguments.h b/include/core/SkFontArguments.h
new file mode 100644
index 0000000..473798f
--- /dev/null
+++ b/include/core/SkFontArguments.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontAgruments_DEFINED
+#define SkFontAgruments_DEFINED
+
+#include "SkScalar.h"
+#include "SkTypes.h"
+
+/** Represents a set of actual arguments for a font. */
+struct SkFontArguments {
+    struct VariationPosition {
+        struct Coordinate {
+            SkFourByteTag axis;
+            SkScalar value;
+        };
+        const Coordinate* coordinates;
+        int coordinateCount;
+    };
+    // deprecated, use VariationCoordinate instead
+    struct Axis {
+       SkFourByteTag fTag;
+       SkScalar fStyleValue;
+    };
+
+    SkFontArguments() : fCollectionIndex(0), fVariationDesignPosition{nullptr, 0} {}
+
+    /** Specify the index of the desired font.
+     *
+     *  Font formats like ttc, dfont, cff, cid, pfr, t42, t1, and fon may actually be indexed
+     *  collections of fonts.
+     */
+    SkFontArguments& setCollectionIndex(int collectionIndex) {
+        fCollectionIndex = collectionIndex;
+        return *this;
+    }
+
+    // deprecated, use setVariationDesignPosition instead.
+    SkFontArguments& setAxes(const Axis* axes, int axisCount) {
+        fVariationDesignPosition.coordinates =
+                reinterpret_cast<const VariationPosition::Coordinate*>(axes);
+        fVariationDesignPosition.coordinateCount = axisCount;
+        return *this;
+    }
+
+    /** Specify a position in the variation design space.
+     *
+     *  Any axis not specified will use the default value.
+     *  Any specified axis not actually present in the font will be ignored.
+     *
+     *  @param position not copied. The value must remain valid for life of SkFontArguments.
+     */
+    SkFontArguments& setVariationDesignPosition(VariationPosition position) {
+        fVariationDesignPosition.coordinates = position.coordinates;
+        fVariationDesignPosition.coordinateCount = position.coordinateCount;
+        return *this;
+    }
+
+    int getCollectionIndex() const {
+        return fCollectionIndex;
+    }
+    // deprecated, use getVariationDesignPosition instead.
+    const Axis* getAxes(int* axisCount) const {
+        *axisCount = fVariationDesignPosition.coordinateCount;
+        return reinterpret_cast<const Axis*>(fVariationDesignPosition.coordinates);
+    }
+    VariationPosition getVariationDesignPosition() const {
+        return fVariationDesignPosition;
+    }
+private:
+    int fCollectionIndex;
+    VariationPosition fVariationDesignPosition;
+};
+
+#endif
diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h
index 51d5a0b..24693a9 100644
--- a/include/core/SkTypeface.h
+++ b/include/core/SkTypeface.h
@@ -11,6 +11,7 @@
 #include "../private/SkBitmaskEnum.h"
 #include "../private/SkOnce.h"
 #include "../private/SkWeakRefCnt.h"
+#include "SkFontArguments.h"
 #include "SkFontStyle.h"
 #include "SkRect.h"
 #include "SkString.h"
@@ -77,6 +78,20 @@
      */
     bool isFixedPitch() const { return fIsFixedPitch; }
 
+    /** Copy into 'coordinates' (allocated by the caller) the design variation coordinates.
+     *
+     *  @param coordinates the buffer into which to write the design variation coordinates.
+     *  @param coordinateCount the number of entries available through 'coordinates'.
+     *
+     *  @return The number of axes, or -1 if there is an error.
+     *  If 'coordinates != nullptr' and 'coordinateCount >= numAxes' then 'coordinates' will be
+     *  filled with the variation coordinates describing the position of this typeface in design
+     *  variation space. It is possible the number of axes can be retrieved but actual position
+     *  cannot.
+     */
+    int getVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                   int coordinateCount) const;
+
     /** Return a 32bit value for this typeface, unique for the underlying font
         data. Will never return 0.
      */
@@ -96,16 +111,16 @@
     /** Returns the default typeface, which is never nullptr. */
     static sk_sp<SkTypeface> MakeDefault(Style style = SkTypeface::kNormal);
 
-  /** Creates a new reference to the typeface that most closely matches the
-      requested familyName and fontStyle. This method allows extended font
-      face specifiers as in the SkFontStyle type. Will never return null.
+    /** Creates a new reference to the typeface that most closely matches the
+        requested familyName and fontStyle. This method allows extended font
+        face specifiers as in the SkFontStyle type. Will never return null.
 
-      @param familyName  May be NULL. The name of the font family.
-      @param fontStyle   The style of the typeface.
-      @return reference to the closest-matching typeface. Call must call
+        @param familyName  May be NULL. The name of the font family.
+        @param fontStyle   The style of the typeface.
+        @return reference to the closest-matching typeface. Call must call
               unref() when they are done.
     */
-  static sk_sp<SkTypeface> MakeFromName(const char familyName[], SkFontStyle fontStyle);
+    static sk_sp<SkTypeface> MakeFromName(const char familyName[], SkFontStyle fontStyle);
 
     /** Return the typeface that most closely matches the requested typeface and style.
         Use this to pick a new style from the same family of the existing typeface.
@@ -341,6 +356,11 @@
     // TODO: make pure virtual.
     virtual std::unique_ptr<SkFontData> onMakeFontData() const;
 
+    // TODO: make pure virtual.
+    virtual int onGetVariationDesignPosition(
+        SkFontArguments::VariationPosition::Coordinate coordinates[],
+        int coordinateCount) const;
+
     virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0;
 
     virtual int onCharsToGlyphs(const void* chars, Encoding, SkGlyphID glyphs[],
diff --git a/include/ports/SkFontMgr.h b/include/ports/SkFontMgr.h
index 4103e87..b5879d3 100644
--- a/include/ports/SkFontMgr.h
+++ b/include/ports/SkFontMgr.h
@@ -8,9 +8,9 @@
 #ifndef SkFontMgr_DEFINED
 #define SkFontMgr_DEFINED
 
+#include "SkFontArguments.h"
 #include "SkFontStyle.h"
 #include "SkRefCnt.h"
-#include "SkScalar.h"
 #include "SkTypes.h"
 
 class SkData;
@@ -102,51 +102,10 @@
      */
     SkTypeface* createFromStream(SkStreamAsset*, int ttcIndex = 0) const;
 
-    struct FontParameters {
-        struct Axis {
-            SkFourByteTag fTag;
-            SkScalar fStyleValue;
-        };
-
-        FontParameters() : fCollectionIndex(0), fAxisCount(0), fAxes(nullptr) {}
-
-        /** Specify the index of the desired font.
-         *
-         *  Font formats like ttc, dfont, cff, cid, pfr, t42, t1, and fon may actually be indexed
-         *  collections of fonts.
-         */
-        FontParameters& setCollectionIndex(int collectionIndex) {
-            fCollectionIndex = collectionIndex;
-            return *this;
-        }
-
-        /** Specify the GX variation axis values.
-         *
-         *  Any axes not specified will use the default value. Specified axes not present in the
-         *  font will be ignored.
-         *
-         *  @param axes not copied. This pointer must remain valid for life of FontParameters.
-         */
-        FontParameters& setAxes(const Axis* axes, int axisCount) {
-            fAxisCount = axisCount;
-            fAxes = axes;
-            return *this;
-        }
-
-        int getCollectionIndex() const {
-            return fCollectionIndex;
-        }
-        const Axis* getAxes(int* axisCount) const {
-            *axisCount = fAxisCount;
-            return fAxes;
-        }
-    private:
-        int fCollectionIndex;
-        int fAxisCount;
-        const Axis* fAxes;
-    };
+    // deprecated, use SkFontArguments instead.
+    using FontParameters = SkFontArguments;
     /* Experimental, API subject to change. */
-    SkTypeface* createFromStream(SkStreamAsset*, const FontParameters&) const;
+    SkTypeface* createFromStream(SkStreamAsset*, const SkFontArguments&) const;
 
     /**
      *  Create a typeface from the specified font data.
@@ -187,7 +146,7 @@
     virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) const = 0;
     virtual SkTypeface* onCreateFromStream(SkStreamAsset*, int ttcIndex) const = 0;
     // TODO: make pure virtual.
-    virtual SkTypeface* onCreateFromStream(SkStreamAsset*, const FontParameters&) const;
+    virtual SkTypeface* onCreateFromStream(SkStreamAsset*, const SkFontArguments&) const;
     virtual SkTypeface* onCreateFromFontData(std::unique_ptr<SkFontData>) const;
     virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const = 0;
 
diff --git a/src/core/SkFontMgr.cpp b/src/core/SkFontMgr.cpp
index 03ac2eb..8ce0b39 100644
--- a/src/core/SkFontMgr.cpp
+++ b/src/core/SkFontMgr.cpp
@@ -132,11 +132,11 @@
     return this->onCreateFromStream(stream, ttcIndex);
 }
 
-SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, const FontParameters& params) const {
+SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, const SkFontArguments& args) const {
     if (nullptr == stream) {
         return nullptr;
     }
-    return this->onCreateFromStream(stream, params);
+    return this->onCreateFromStream(stream, args);
 }
 
 SkTypeface* SkFontMgr::createFromFontData(std::unique_ptr<SkFontData> data) const {
@@ -147,8 +147,8 @@
 }
 
 // This implementation is temporary until it can be made pure virtual.
-SkTypeface* SkFontMgr::onCreateFromStream(SkStreamAsset* stream, const FontParameters& p) const {
-    return this->createFromStream(stream, p.getCollectionIndex());
+SkTypeface* SkFontMgr::onCreateFromStream(SkStreamAsset* stream, const SkFontArguments& args) const{
+    return this->createFromStream(stream, args.getCollectionIndex());
 }
 
 // This implementation is temporary until it can be made pure virtual.
diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp
index 70c0c76..ff473c9 100644
--- a/src/core/SkTypeface.cpp
+++ b/src/core/SkTypeface.cpp
@@ -73,6 +73,11 @@
     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override {
         return new EmptyLocalizedStrings;
     }
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override
+    {
+        return 0;
+    }
     int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
     size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override {
         return 0;
@@ -202,6 +207,12 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+int SkTypeface::getVariationDesignPosition(
+        SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
+{
+    return this->onGetVariationDesignPosition(coordinates, coordinateCount);
+}
+
 int SkTypeface::countTables() const {
     return this->onGetTableTags(nullptr);
 }
@@ -239,6 +250,13 @@
     return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0);
 };
 
+// This implementation is temporary until this method can be made pure virtual.
+int SkTypeface::onGetVariationDesignPosition(
+        SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
+{
+    return -1;
+}
+
 int SkTypeface::charsToGlyphs(const void* chars, Encoding encoding,
                               uint16_t glyphs[], int glyphCount) const {
     if (glyphCount <= 0) {
diff --git a/src/fonts/SkGScalerContext.cpp b/src/fonts/SkGScalerContext.cpp
index 8a0ac4c..3b9c660 100644
--- a/src/fonts/SkGScalerContext.cpp
+++ b/src/fonts/SkGScalerContext.cpp
@@ -195,6 +195,12 @@
     return fProxy->createFamilyNameIterator();
 }
 
+int SkGTypeface::onGetVariationDesignPosition(
+        SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
+{
+    return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount);
+}
+
 int SkGTypeface::onGetTableTags(SkFontTableTag tags[]) const {
     return fProxy->getTableTags(tags);
 }
diff --git a/src/fonts/SkGScalerContext.h b/src/fonts/SkGScalerContext.h
index 3eb25a8..562513c 100644
--- a/src/fonts/SkGScalerContext.h
+++ b/src/fonts/SkGScalerContext.h
@@ -37,6 +37,8 @@
     void onGetFamilyName(SkString* familyName) const override;
     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
 
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override;
     int onGetTableTags(SkFontTableTag tags[]) const override;
     size_t onGetTableData(SkFontTableTag, size_t offset,
                           size_t length, void* data) const override;
diff --git a/src/fonts/SkRandomScalerContext.cpp b/src/fonts/SkRandomScalerContext.cpp
index 55c7fb3..3a292dc 100644
--- a/src/fonts/SkRandomScalerContext.cpp
+++ b/src/fonts/SkRandomScalerContext.cpp
@@ -242,6 +242,12 @@
     return fProxy->createFamilyNameIterator();
 }
 
+int SkRandomTypeface::onGetVariationDesignPosition(
+        SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
+{
+    return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount);
+}
+
 int SkRandomTypeface::onGetTableTags(SkFontTableTag tags[]) const {
     return fProxy->getTableTags(tags);
 }
diff --git a/src/fonts/SkRandomScalerContext.h b/src/fonts/SkRandomScalerContext.h
index 076689d..c84b764 100644
--- a/src/fonts/SkRandomScalerContext.h
+++ b/src/fonts/SkRandomScalerContext.h
@@ -42,6 +42,8 @@
     void onGetFamilyName(SkString* familyName) const override;
     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
 
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override;
     int onGetTableTags(SkFontTableTag tags[]) const override;
     size_t onGetTableData(SkFontTableTag, size_t offset,
                           size_t length, void* data) const override;
diff --git a/src/fonts/SkTestScalerContext.h b/src/fonts/SkTestScalerContext.h
index 217e57c..20cce91 100644
--- a/src/fonts/SkTestScalerContext.h
+++ b/src/fonts/SkTestScalerContext.h
@@ -91,6 +91,12 @@
     void onGetFamilyName(SkString* familyName) const override;
     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
 
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override
+    {
+        return 0;
+    }
+
     int onGetTableTags(SkFontTableTag tags[]) const override {
         return 0;
     }
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index 47790f3..1feea4d 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -27,9 +27,6 @@
 #include "SkTemplates.h"
 #include <memory>
 
-#if defined(SK_CAN_USE_DLOPEN)
-#include <dlfcn.h>
-#endif
 #include <ft2build.h>
 #include FT_ADVANCES_H
 #include FT_BITMAP_H
@@ -44,6 +41,20 @@
 #include FT_TYPE1_TABLES_H
 #include FT_XFREE86_H
 
+// SK_FREETYPE_MINIMUM_RUNTIME_VERSION 0x<major><minor><patch><flags>
+// Flag SK_FREETYPE_DLOPEN: also try dlopen to get newer features.
+#define SK_FREETYPE_DLOPEN (0x1)
+#ifndef SK_FREETYPE_MINIMUM_RUNTIME_VERSION
+#  if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) || defined (GOOGLE3)
+#    define SK_FREETYPE_MINIMUM_RUNTIME_VERSION (((FREETYPE_MAJOR) << 24) | ((FREETYPE_MINOR) << 16) | ((FREETYPE_PATCH) << 8))
+#  else
+#    define SK_FREETYPE_MINIMUM_RUNTIME_VERSION ((2 << 24) | (3 << 16) | (11 << 8) | (SK_FREETYPE_DLOPEN))
+#  endif
+#endif
+#if SK_FREETYPE_MINIMUM_RUNTIME_VERSION & SK_FREETYPE_DLOPEN
+#  include <dlfcn.h>
+#endif
+
 // FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
 // were introduced in FreeType 2.5.0.
 // The following may be removed once FreeType 2.5.0 is required to build.
@@ -85,12 +96,37 @@
 
 class FreeTypeLibrary : SkNoncopyable {
 public:
-    FreeTypeLibrary() : fLibrary(nullptr), fIsLCDSupported(false), fLCDExtra(0) {
+    FreeTypeLibrary()
+        : fGetVarDesignCoordinates(nullptr)
+        , fLibrary(nullptr)
+        , fIsLCDSupported(false)
+        , fLCDExtra(0)
+    {
         if (FT_New_Library(&gFTMemory, &fLibrary)) {
             return;
         }
         FT_Add_Default_Modules(fLibrary);
 
+#if SK_FREETYPE_MINIMUM_RUNTIME_VERSION >= 0x02070100
+        fGetVarDesignCoordinates = FT_Get_Var_Design_Coordinates;
+#elif SK_FREETYPE_MINIMUM_RUNTIME_VERSION & SK_FREETYPE_DLOPEN
+        FT_Int major, minor, patch;
+        FT_Library_Version(fLibrary, &major, &minor, &patch);
+        if (major > 2 || ((major == 2 && minor > 7) || (major == 2 && minor == 7 && patch >= 1))) {
+            //The FreeType library is already loaded, so symbols are available in process.
+            void* self = dlopen(nullptr, RTLD_LAZY);
+            if (self) {
+                // The following cast is non-standard, but safe for POSIX.
+                // Cannot write this with reinterpret_cast, because clang has not implemented DR573.
+                // See http://clang.llvm.org/cxx_dr_status.html .
+                //*reinterpret_cast<void**>(&fGetVarDesignCoordinates) =
+                //        dlsym(self, "FT_Get_Var_Design_Coordinates");
+                *(void**)(&fGetVarDesignCoordinates) = dlsym(self, "FT_Get_Var_Design_Coordinates");
+                dlclose(self);
+            }
+        }
+#endif
+
         // Setup LCD filtering. This reduces color fringes for LCD smoothed glyphs.
         // Default { 0x10, 0x40, 0x70, 0x40, 0x10 } adds up to 0x110, simulating ink spread.
         // SetLcdFilter must be called before SetLcdFilterWeights.
@@ -102,23 +138,26 @@
             // Adds to 0x110 simulating ink spread, but provides better results than default.
             static unsigned char gGaussianLikeHeavyWeights[] = { 0x1A, 0x43, 0x56, 0x43, 0x1A, };
 
-#    if SK_FONTHOST_FREETYPE_RUNTIME_VERSION > 0x020400
+#  if SK_FREETYPE_MINIMUM_RUNTIME_VERSION >= 0x02040000
             FT_Library_SetLcdFilterWeights(fLibrary, gGaussianLikeHeavyWeights);
-#    elif SK_CAN_USE_DLOPEN == 1
+#  elif SK_FREETYPE_MINIMUM_RUNTIME_VERSION & SK_FREETYPE_DLOPEN
             //The FreeType library is already loaded, so symbols are available in process.
             void* self = dlopen(nullptr, RTLD_LAZY);
             if (self) {
                 FT_Library_SetLcdFilterWeightsProc setLcdFilterWeights;
-                //The following cast is non-standard, but safe for POSIX.
-                *reinterpret_cast<void**>(&setLcdFilterWeights) =
-                        dlsym(self, "FT_Library_SetLcdFilterWeights");
+                // The following cast is non-standard, but safe for POSIX.
+                // Cannot write this with reinterpret_cast, because clang has not implemented DR573.
+                // See http://clang.llvm.org/cxx_dr_status.html .
+                //*reinterpret_cast<void**>(&setLcdFilterWeights) =
+                //        dlsym(self, "FT_Library_SetLcdFilterWeights");
+                *(void**)(&setLcdFilterWeights) = dlsym(self, "FT_Library_SetLcdFilterWeights");
                 dlclose(self);
 
                 if (setLcdFilterWeights) {
                     setLcdFilterWeights(fLibrary, gGaussianLikeHeavyWeights);
                 }
             }
-#    endif
+#  endif
 #endif
         }
     }
@@ -132,6 +171,13 @@
     bool isLCDSupported() { return fIsLCDSupported; }
     int lcdExtra() { return fLCDExtra; }
 
+    // FT_Get_{MM,Var}_{Blend,Design}_Coordinates were added in FreeType 2.7.1.
+    // Prior to this there was no way to get the coordinates out of the FT_Face.
+    // This wasn't too bad because you needed to specify them anyway, and the clamp was provided.
+    // However, this doesn't work when face_index specifies named variations as introduced in 2.6.1.
+    using FT_Get_Var_Blend_CoordinatesProc = FT_Error (*)(FT_Face, FT_UInt, FT_Fixed*);
+    FT_Get_Var_Blend_CoordinatesProc fGetVarDesignCoordinates;
+
 private:
     FT_Library fLibrary;
     bool fIsLCDSupported;
@@ -144,7 +190,8 @@
     // OpenSuse >= 11.4 (previous deprecated January 2012 / Nov 2013 for Evergreen 11.2)
     // Fedora >= 14 (good)
     // Android >= Gingerbread (good)
-    typedef FT_Error (*FT_Library_SetLcdFilterWeightsProc)(FT_Library, unsigned char*);
+    // RHEL >= 7 (6 has 2.3.11, EOL Nov 2020, Phase 3 May 2017)
+    using FT_Library_SetLcdFilterWeightsProc = FT_Error (*)(FT_Library, unsigned char*);
 };
 
 struct SkFaceRec;
@@ -183,6 +230,223 @@
     }
 }
 
+///////////////////////////////////////////////////////////////////////////
+
+struct SkFaceRec {
+    SkFaceRec* fNext;
+    std::unique_ptr<FT_FaceRec, SkFunctionWrapper<FT_Error, FT_FaceRec, FT_Done_Face>> fFace;
+    FT_StreamRec fFTStream;
+    std::unique_ptr<SkStreamAsset> fSkStream;
+    uint32_t fRefCnt;
+    uint32_t fFontID;
+
+    // FreeType prior to 2.7.1 does not implement retreiving variation design metrics.
+    // Cache the variation design metrics used to create the font if the user specifies them.
+    SkAutoSTMalloc<4, SkFixed> fAxes;
+    int fAxesCount;
+
+    // FreeType from 2.6.1 (14d6b5d7) until 2.7.0 (ee3f36f6b38) uses font_index for both font index
+    // and named variation index on input, but masks the named variation index part on output.
+    // Manually keep track of when a named variation is requested for 2.6.1 until 2.7.1.
+    bool fNamedVariationSpecified;
+
+    SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID);
+};
+
+extern "C" {
+    static unsigned long sk_ft_stream_io(FT_Stream ftStream,
+                                         unsigned long offset,
+                                         unsigned char* buffer,
+                                         unsigned long count)
+    {
+        SkStreamAsset* stream = static_cast<SkStreamAsset*>(ftStream->descriptor.pointer);
+
+        if (count) {
+            if (!stream->seek(offset)) {
+                return 0;
+            }
+            count = stream->read(buffer, count);
+        }
+        return count;
+    }
+
+    static void sk_ft_stream_close(FT_Stream) {}
+}
+
+SkFaceRec::SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID)
+        : fNext(nullptr), fSkStream(std::move(stream)), fRefCnt(1), fFontID(fontID)
+        , fAxesCount(0), fNamedVariationSpecified(false)
+{
+    sk_bzero(&fFTStream, sizeof(fFTStream));
+    fFTStream.size = fSkStream->getLength();
+    fFTStream.descriptor.pointer = fSkStream.get();
+    fFTStream.read  = sk_ft_stream_io;
+    fFTStream.close = sk_ft_stream_close;
+}
+
+static void ft_face_setup_axes(SkFaceRec* rec, const SkFontData& data) {
+    if (!(rec->fFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
+        return;
+    }
+
+    // If a named variation is requested, don't overwrite the named variation's position.
+    if (data.getIndex() > 0xFFFF) {
+        rec->fNamedVariationSpecified = true;
+        return;
+    }
+
+    SkDEBUGCODE(
+        FT_MM_Var* variations = nullptr;
+        if (FT_Get_MM_Var(rec->fFace.get(), &variations)) {
+            SkDEBUGF(("INFO: font %s claims variations, but none found.\n",
+                      rec->fFace->family_name));
+            return;
+        }
+        SkAutoFree autoFreeVariations(variations);
+
+        if (static_cast<FT_UInt>(data.getAxisCount()) != variations->num_axis) {
+            SkDEBUGF(("INFO: font %s has %d variations, but %d were specified.\n",
+                      rec->fFace->family_name, variations->num_axis, data.getAxisCount()));
+            return;
+        }
+    )
+
+    SkAutoSTMalloc<4, FT_Fixed> coords(data.getAxisCount());
+    for (int i = 0; i < data.getAxisCount(); ++i) {
+        coords[i] = data.getAxis()[i];
+    }
+    if (FT_Set_Var_Design_Coordinates(rec->fFace.get(), data.getAxisCount(), coords.get())) {
+        SkDEBUGF(("INFO: font %s has variations, but specified variations could not be set.\n",
+                  rec->fFace->family_name));
+        return;
+    }
+
+    rec->fAxesCount = data.getAxisCount();
+    rec->fAxes.reset(rec->fAxesCount);
+    for (int i = 0; i < rec->fAxesCount; ++i) {
+        rec->fAxes[i] = data.getAxis()[i];
+    }
+}
+
+// Will return nullptr on failure
+// Caller must lock gFTMutex before calling this function.
+static SkFaceRec* ref_ft_face(const SkTypeface* typeface) {
+    gFTMutex.assertHeld();
+
+    const SkFontID fontID = typeface->uniqueID();
+    SkFaceRec* cachedRec = gFaceRecHead;
+    while (cachedRec) {
+        if (cachedRec->fFontID == fontID) {
+            SkASSERT(cachedRec->fFace);
+            cachedRec->fRefCnt += 1;
+            return cachedRec;
+        }
+        cachedRec = cachedRec->fNext;
+    }
+
+    std::unique_ptr<SkFontData> data = typeface->makeFontData();
+    if (nullptr == data || !data->hasStream()) {
+        return nullptr;
+    }
+
+    std::unique_ptr<SkFaceRec> rec(new SkFaceRec(data->detachStream(), fontID));
+
+    FT_Open_Args args;
+    memset(&args, 0, sizeof(args));
+    const void* memoryBase = rec->fSkStream->getMemoryBase();
+    if (memoryBase) {
+        args.flags = FT_OPEN_MEMORY;
+        args.memory_base = (const FT_Byte*)memoryBase;
+        args.memory_size = rec->fSkStream->getLength();
+    } else {
+        args.flags = FT_OPEN_STREAM;
+        args.stream = &rec->fFTStream;
+    }
+
+    {
+        FT_Face rawFace;
+        FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rawFace);
+        if (err) {
+            SkDEBUGF(("ERROR: unable to open font '%x'\n", fontID));
+            return nullptr;
+        }
+        rec->fFace.reset(rawFace);
+    }
+    SkASSERT(rec->fFace);
+
+    ft_face_setup_axes(rec.get(), *data);
+
+    // FreeType will set the charmap to the "most unicode" cmap if it exists.
+    // If there are no unicode cmaps, the charmap is set to nullptr.
+    // However, "symbol" cmaps should also be considered "fallback unicode" cmaps
+    // because they are effectively private use area only (even if they aren't).
+    // This is the last on the fallback list at
+    // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
+    if (!rec->fFace->charmap) {
+        FT_Select_Charmap(rec->fFace.get(), FT_ENCODING_MS_SYMBOL);
+    }
+
+    rec->fNext = gFaceRecHead;
+    gFaceRecHead = rec.get();
+    return rec.release();
+}
+
+// Caller must lock gFTMutex before calling this function.
+static void unref_ft_face(SkFaceRec* faceRec) {
+    gFTMutex.assertHeld();
+
+    SkFaceRec*  rec = gFaceRecHead;
+    SkFaceRec*  prev = nullptr;
+    while (rec) {
+        SkFaceRec* next = rec->fNext;
+        if (rec->fFace == faceRec->fFace) {
+            if (--rec->fRefCnt == 0) {
+                if (prev) {
+                    prev->fNext = next;
+                } else {
+                    gFaceRecHead = next;
+                }
+                delete rec;
+            }
+            return;
+        }
+        prev = rec;
+        rec = next;
+    }
+    SkDEBUGFAIL("shouldn't get here, face not in list");
+}
+
+class AutoFTAccess {
+public:
+    AutoFTAccess(const SkTypeface* tf) : fFaceRec(nullptr) {
+        gFTMutex.acquire();
+        if (!ref_ft_library()) {
+            sk_throw();
+        }
+        fFaceRec = ref_ft_face(tf);
+    }
+
+    ~AutoFTAccess() {
+        if (fFaceRec) {
+            unref_ft_face(fFaceRec);
+        }
+        unref_ft_library();
+        gFTMutex.release();
+    }
+
+    FT_Face face() { return fFaceRec ? fFaceRec->fFace.get() : nullptr; }
+    int getAxesCount() { return fFaceRec ? fFaceRec->fAxesCount : 0; }
+    SkFixed* getAxes() { return fFaceRec ? fFaceRec->fAxes.get() : nullptr; }
+    bool isNamedVariationSpecified() {
+        return fFaceRec ? fFaceRec->fNamedVariationSpecified : false;
+    }
+
+private:
+    SkFaceRec* fFaceRec;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
 class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base {
 public:
     SkScalerContext_FreeType(sk_sp<SkTypeface>,
@@ -205,7 +469,10 @@
     SkUnichar generateGlyphToChar(uint16_t glyph) override;
 
 private:
-    FT_Face   fFace;  // Shared face from gFaceRecHead.
+    using UnrefFTFace = SkFunctionWrapper<void, SkFaceRec, unref_ft_face>;
+    std::unique_ptr<SkFaceRec, UnrefFTFace> fFaceRec;
+
+    FT_Face   fFace;  // Borrowed face from gFaceRecHead.
     FT_Size   fFTSize;  // The size on the fFace for this scaler.
     FT_Int    fStrikeIndex;
 
@@ -236,192 +503,6 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-
-struct SkFaceRec {
-    SkFaceRec* fNext;
-    FT_Face fFace;
-    FT_StreamRec fFTStream;
-    std::unique_ptr<SkStreamAsset> fSkStream;
-    uint32_t fRefCnt;
-    uint32_t fFontID;
-
-    SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID);
-};
-
-extern "C" {
-    static unsigned long sk_ft_stream_io(FT_Stream ftStream,
-                                         unsigned long offset,
-                                         unsigned char* buffer,
-                                         unsigned long count)
-    {
-        SkStreamAsset* stream = static_cast<SkStreamAsset*>(ftStream->descriptor.pointer);
-
-        if (count) {
-            if (!stream->seek(offset)) {
-                return 0;
-            }
-            count = stream->read(buffer, count);
-        }
-        return count;
-    }
-
-    static void sk_ft_stream_close(FT_Stream) {}
-}
-
-SkFaceRec::SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID)
-        : fNext(nullptr), fSkStream(std::move(stream)), fRefCnt(1), fFontID(fontID)
-{
-    sk_bzero(&fFTStream, sizeof(fFTStream));
-    fFTStream.size = fSkStream->getLength();
-    fFTStream.descriptor.pointer = fSkStream.get();
-    fFTStream.read  = sk_ft_stream_io;
-    fFTStream.close = sk_ft_stream_close;
-}
-
-static void ft_face_setup_axes(FT_Face face, const SkFontData& data) {
-    if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
-        return;
-    }
-
-    SkDEBUGCODE(
-        FT_MM_Var* variations = nullptr;
-        if (FT_Get_MM_Var(face, &variations)) {
-            SkDEBUGF(("INFO: font %s claims variations, but none found.\n", face->family_name));
-            return;
-        }
-        SkAutoFree autoFreeVariations(variations);
-
-        if (static_cast<FT_UInt>(data.getAxisCount()) != variations->num_axis) {
-            SkDEBUGF(("INFO: font %s has %d variations, but %d were specified.\n",
-                    face->family_name, variations->num_axis, data.getAxisCount()));
-            return;
-        }
-    )
-
-    SkAutoSTMalloc<4, FT_Fixed> coords(data.getAxisCount());
-    for (int i = 0; i < data.getAxisCount(); ++i) {
-        coords[i] = data.getAxis()[i];
-    }
-    if (FT_Set_Var_Design_Coordinates(face, data.getAxisCount(), coords.get())) {
-        SkDEBUGF(("INFO: font %s has variations, but specified variations could not be set.\n",
-                  face->family_name));
-        return;
-    }
-}
-
-// Will return 0 on failure
-// Caller must lock gFTMutex before calling this function.
-static FT_Face ref_ft_face(const SkTypeface* typeface) {
-    gFTMutex.assertHeld();
-
-    const SkFontID fontID = typeface->uniqueID();
-    SkFaceRec* rec = gFaceRecHead;
-    while (rec) {
-        if (rec->fFontID == fontID) {
-            SkASSERT(rec->fFace);
-            rec->fRefCnt += 1;
-            return rec->fFace;
-        }
-        rec = rec->fNext;
-    }
-
-    std::unique_ptr<SkFontData> data = typeface->makeFontData();
-    if (nullptr == data || !data->hasStream()) {
-        return nullptr;
-    }
-
-    rec = new SkFaceRec(data->detachStream(), fontID);
-
-    FT_Open_Args args;
-    memset(&args, 0, sizeof(args));
-    const void* memoryBase = rec->fSkStream->getMemoryBase();
-    if (memoryBase) {
-        args.flags = FT_OPEN_MEMORY;
-        args.memory_base = (const FT_Byte*)memoryBase;
-        args.memory_size = rec->fSkStream->getLength();
-    } else {
-        args.flags = FT_OPEN_STREAM;
-        args.stream = &rec->fFTStream;
-    }
-
-    FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rec->fFace);
-    if (err) {
-        SkDEBUGF(("ERROR: unable to open font '%x'\n", fontID));
-        delete rec;
-        return nullptr;
-    }
-    SkASSERT(rec->fFace);
-
-    ft_face_setup_axes(rec->fFace, *data);
-
-    // FreeType will set the charmap to the "most unicode" cmap if it exists.
-    // If there are no unicode cmaps, the charmap is set to nullptr.
-    // However, "symbol" cmaps should also be considered "fallback unicode" cmaps
-    // because they are effectively private use area only (even if they aren't).
-    // This is the last on the fallback list at
-    // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
-    if (!rec->fFace->charmap) {
-        FT_Select_Charmap(rec->fFace, FT_ENCODING_MS_SYMBOL);
-    }
-
-    rec->fNext = gFaceRecHead;
-    gFaceRecHead = rec;
-    return rec->fFace;
-}
-
-// Caller must lock gFTMutex before calling this function.
-extern void unref_ft_face(FT_Face face);
-void unref_ft_face(FT_Face face) {
-    gFTMutex.assertHeld();
-
-    SkFaceRec*  rec = gFaceRecHead;
-    SkFaceRec*  prev = nullptr;
-    while (rec) {
-        SkFaceRec* next = rec->fNext;
-        if (rec->fFace == face) {
-            if (--rec->fRefCnt == 0) {
-                if (prev) {
-                    prev->fNext = next;
-                } else {
-                    gFaceRecHead = next;
-                }
-                FT_Done_Face(face);
-                delete rec;
-            }
-            return;
-        }
-        prev = rec;
-        rec = next;
-    }
-    SkDEBUGFAIL("shouldn't get here, face not in list");
-}
-
-class AutoFTAccess {
-public:
-    AutoFTAccess(const SkTypeface* tf) : fFace(nullptr) {
-        gFTMutex.acquire();
-        if (!ref_ft_library()) {
-            sk_throw();
-        }
-        fFace = ref_ft_face(tf);
-    }
-
-    ~AutoFTAccess() {
-        if (fFace) {
-            unref_ft_face(fFace);
-        }
-        unref_ft_library();
-        gFTMutex.release();
-    }
-
-    FT_Face face() { return fFace; }
-
-private:
-    FT_Face     fFace;
-};
-
-///////////////////////////////////////////////////////////////////////////
 
 static bool canEmbed(FT_Face face) {
     FT_UShort fsType = FT_Get_FSType_Flags(face);
@@ -746,11 +827,10 @@
         sk_throw();
     }
 
+    fFaceRec.reset(ref_ft_face(this->getTypeface()));
+
     // load the font file
-    using UnrefFTFace = SkFunctionWrapper<void, skstd::remove_pointer_t<FT_Face>, unref_ft_face>;
-    using FT_FaceRef = skstd::remove_pointer_t<FT_Face>;
-    std::unique_ptr<FT_FaceRef, UnrefFTFace> ftFace(ref_ft_face(this->getTypeface()));
-    if (nullptr == ftFace) {
+    if (nullptr == fFaceRec) {
         SkDEBUGF(("Could not create FT_Face.\n"));
         return;
     }
@@ -836,11 +916,11 @@
     }
 
     using DoneFTSize = SkFunctionWrapper<FT_Error, skstd::remove_pointer_t<FT_Size>, FT_Done_Size>;
-    std::unique_ptr<skstd::remove_pointer_t<FT_Size>, DoneFTSize> ftSize([&ftFace]() -> FT_Size {
+    std::unique_ptr<skstd::remove_pointer_t<FT_Size>, DoneFTSize> ftSize([this]() -> FT_Size {
         FT_Size size;
-        FT_Error err = FT_New_Size(ftFace.get(), &size);
+        FT_Error err = FT_New_Size(fFaceRec->fFace.get(), &size);
         if (err != 0) {
-            SkDEBUGF(("FT_New_Size(%s) returned 0x%x.\n", ftFace->family_name, err));
+            SkDEBUGF(("FT_New_Size(%s) returned 0x%x.\n", fFaceRec->fFace->family_name, err));
             return nullptr;
         }
         return size;
@@ -852,36 +932,37 @@
 
     FT_Error err = FT_Activate_Size(ftSize.get());
     if (err != 0) {
-        SkDEBUGF(("FT_Activate_Size(%s) returned 0x%x.\n", ftFace->family_name, err));
+        SkDEBUGF(("FT_Activate_Size(%s) returned 0x%x.\n", fFaceRec->fFace->family_name, err));
         return;
     }
 
-    if (FT_IS_SCALABLE(ftFace)) {
-        err = FT_Set_Char_Size(ftFace.get(), scaleX, scaleY, 72, 72);
+    if (FT_IS_SCALABLE(fFaceRec->fFace)) {
+        err = FT_Set_Char_Size(fFaceRec->fFace.get(), scaleX, scaleY, 72, 72);
         if (err != 0) {
             SkDEBUGF(("FT_Set_CharSize(%s, %f, %f) returned 0x%x.\n",
-                      ftFace->family_name, fScale.fX, fScale.fY, err));
+                      fFaceRec->fFace->family_name, fScale.fX, fScale.fY, err));
             return;
         }
-    } else if (FT_HAS_FIXED_SIZES(ftFace)) {
-        fStrikeIndex = chooseBitmapStrike(ftFace.get(), scaleY);
+    } else if (FT_HAS_FIXED_SIZES(fFaceRec->fFace)) {
+        fStrikeIndex = chooseBitmapStrike(fFaceRec->fFace.get(), scaleY);
         if (fStrikeIndex == -1) {
-            SkDEBUGF(("No glyphs for font \"%s\" size %f.\n", ftFace->family_name, fScale.fY));
+            SkDEBUGF(("No glyphs for font \"%s\" size %f.\n",
+                      fFaceRec->fFace->family_name, fScale.fY));
             return;
         }
 
-        err = FT_Select_Size(ftFace.get(), fStrikeIndex);
+        err = FT_Select_Size(fFaceRec->fFace.get(), fStrikeIndex);
         if (err != 0) {
             SkDEBUGF(("FT_Select_Size(%s, %d) returned 0x%x.\n",
-                      ftFace->family_name, fStrikeIndex, err));
+                      fFaceRec->fFace->family_name, fStrikeIndex, err));
             fStrikeIndex = -1;
             return;
         }
 
         // A non-ideal size was picked, so recompute the matrix.
         // This adjusts for the difference between FT_Set_Char_Size and FT_Select_Size.
-        fMatrix22Scalar.preScale(fScale.x() / ftFace->size->metrics.x_ppem,
-                                 fScale.y() / ftFace->size->metrics.y_ppem);
+        fMatrix22Scalar.preScale(fScale.x() / fFaceRec->fFace->size->metrics.x_ppem,
+                                 fScale.y() / fFaceRec->fFace->size->metrics.y_ppem);
         fMatrix22.xx = SkScalarToFixed(fMatrix22Scalar.getScaleX());
         fMatrix22.xy = SkScalarToFixed(-fMatrix22Scalar.getSkewX());
         fMatrix22.yx = SkScalarToFixed(-fMatrix22Scalar.getSkewY());
@@ -898,12 +979,12 @@
         // Force this flag off for bitmap only fonts.
         fLoadGlyphFlags &= ~FT_LOAD_NO_BITMAP;
     } else {
-        SkDEBUGF(("Unknown kind of font \"%s\" size %f.\n", fFace->family_name, fScale.fY));
+        SkDEBUGF(("Unknown kind of font \"%s\" size %f.\n", fFaceRec->fFace->family_name, fScale.fY));
         return;
     }
 
     fFTSize = ftSize.release();
-    fFace = ftFace.release();
+    fFace = fFaceRec->fFace.get();
     fDoLinearMetrics = linearMetrics;
 }
 
@@ -914,9 +995,7 @@
         FT_Done_Size(fFTSize);
     }
 
-    if (fFace != nullptr) {
-        unref_ft_face(fFace);
-    }
+    fFaceRec = nullptr;
 
     unref_ft_library();
 }
@@ -1500,6 +1579,51 @@
     return nameIter;
 }
 
+int SkTypeface_FreeType::onGetVariationDesignPosition(
+        SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
+{
+    AutoFTAccess fta(this);
+    FT_Face face = fta.face();
+
+    if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
+        return 0;
+    }
+
+    FT_MM_Var* variations = nullptr;
+    if (FT_Get_MM_Var(face, &variations)) {
+        return 0;
+    }
+    SkAutoFree autoFreeVariations(variations);
+
+    if (!coordinates || coordinateCount < SkToInt(variations->num_axis)) {
+        return variations->num_axis;
+    }
+
+    SkAutoSTMalloc<4, FT_Fixed> coords(variations->num_axis);
+    // FT_Get_{MM,Var}_{Blend,Design}_Coordinates were added in FreeType 2.7.1.
+    if (gFTLibrary->fGetVarDesignCoordinates &&
+        !gFTLibrary->fGetVarDesignCoordinates(face, variations->num_axis, coords.get()))
+    {
+        for (FT_UInt i = 0; i < variations->num_axis; ++i) {
+            coordinates[i].axis = variations->axis[i].tag;
+            coordinates[i].value = SkFixedToScalar(coords[i]);
+        }
+    } else if (static_cast<FT_UInt>(fta.getAxesCount()) == variations->num_axis) {
+        for (FT_UInt i = 0; i < variations->num_axis; ++i) {
+            coordinates[i].axis = variations->axis[i].tag;
+            coordinates[i].value = SkFixedToScalar(fta.getAxes()[i]);
+        }
+    } else if (fta.isNamedVariationSpecified()) {
+        // The font has axes, they cannot be retrieved, and some named axis was specified.
+        return -1;
+    } else {
+        // The font has axes, they cannot be retrieved, but no named instance was specified.
+        return 0;
+    }
+
+    return variations->num_axis;
+}
+
 int SkTypeface_FreeType::onGetTableTags(SkFontTableTag tags[]) const {
     AutoFTAccess fta(this);
     FT_Face face = fta.face();
@@ -1730,7 +1854,7 @@
 
 /*static*/ void SkTypeface_FreeType::Scanner::computeAxisValues(
     AxisDefinitions axisDefinitions,
-    const SkFontMgr::FontParameters::Axis* requestedAxes, int requestedAxisCount,
+    const SkFontArguments::VariationPosition position,
     SkFixed* axisValues,
     const SkString& name)
 {
@@ -1739,11 +1863,11 @@
         const SkScalar axisMin = SkFixedToScalar(axisDefinition.fMinimum);
         const SkScalar axisMax = SkFixedToScalar(axisDefinition.fMaximum);
         axisValues[i] = axisDefinition.fDefault;
-        for (int j = 0; j < requestedAxisCount; ++j) {
-            const SkFontMgr::FontParameters::Axis& axisSpecified = requestedAxes[j];
-            if (axisDefinition.fTag == axisSpecified.fTag) {
-                const SkScalar axisValue = SkTPin(axisSpecified.fStyleValue, axisMin, axisMax);
-                if (axisSpecified.fStyleValue != axisValue) {
+        for (int j = 0; j < position.coordinateCount; ++j) {
+            const auto& coordinate = position.coordinates[j];
+            if (axisDefinition.fTag == coordinate.axis) {
+                const SkScalar axisValue = SkTPin(coordinate.value, axisMin, axisMax);
+                if (coordinate.value != axisValue) {
                     SkDEBUGF(("Requested font axis value out of range: "
                               "%s '%c%c%c%c' %f; pinned to %f.\n",
                               name.c_str(),
@@ -1751,7 +1875,7 @@
                               (axisDefinition.fTag >> 16) & 0xFF,
                               (axisDefinition.fTag >>  8) & 0xFF,
                               (axisDefinition.fTag      ) & 0xFF,
-                              SkScalarToDouble(axisSpecified.fStyleValue),
+                              SkScalarToDouble(coordinate.value),
                               SkScalarToDouble(axisValue)));
                 }
                 axisValues[i] = SkScalarToFixed(axisValue);
@@ -1763,8 +1887,8 @@
 
     SkDEBUGCODE(
         // Check for axis specified, but not matched in font.
-        for (int i = 0; i < requestedAxisCount; ++i) {
-            SkFourByteTag skTag = requestedAxes[i].fTag;
+        for (int i = 0; i < position.coordinateCount; ++i) {
+            SkFourByteTag skTag = position.coordinates[i].axis;
             bool found = false;
             for (int j = 0; j < axisDefinitions.count(); ++j) {
                 if (skTag == axisDefinitions[j].fTag) {
diff --git a/src/ports/SkFontHost_FreeType_common.h b/src/ports/SkFontHost_FreeType_common.h
index 867e139..b9e8b13 100644
--- a/src/ports/SkFontHost_FreeType_common.h
+++ b/src/ports/SkFontHost_FreeType_common.h
@@ -17,8 +17,11 @@
 
 #include "SkFontMgr.h"
 
-#include <ft2build.h>
-#include FT_FREETYPE_H
+// These are forward declared to avoid pimpl but also hide the FreeType implementation.
+typedef struct FT_LibraryRec_* FT_Library;
+typedef struct FT_FaceRec_* FT_Face;
+typedef struct FT_StreamRec_* FT_Stream;
+typedef signed long FT_Pos;
 
 class SkScalerContext_FreeType_Base : public SkScalerContext {
 protected:
@@ -59,7 +62,7 @@
                       AxisDefinitions* axes) const;
         static void computeAxisValues(
             AxisDefinitions axisDefinitions,
-            const SkFontMgr::FontParameters::Axis* requestedAxis, int requestedAxisCount,
+            const SkFontArguments::VariationPosition position,
             SkFixed* axisValues,
             const SkString& name);
 
@@ -88,6 +91,8 @@
 
     LocalizedStrings* onCreateFamilyNameIterator() const override;
 
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override;
     int onGetTableTags(SkFontTableTag tags[]) const override;
     size_t onGetTableData(SkFontTableTag, size_t offset,
                           size_t length, void* data) const override;
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp
index 7a46d40..b5022d9 100644
--- a/src/ports/SkFontHost_mac.cpp
+++ b/src/ports/SkFontHost_mac.cpp
@@ -492,6 +492,8 @@
     int onGetUPEM() const override;
     SkStreamAsset* onOpenStream(int* ttcIndex) const override;
     std::unique_ptr<SkFontData> onMakeFontData() const override;
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override;
     void onGetFamilyName(SkString* familyName) const override;
     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
     int onGetTableTags(SkFontTableTag tags[]) const override;
@@ -1374,7 +1376,10 @@
 
 // Returns nullptr on failure
 // Call must still manage its ownership of provider
-static SkTypeface* create_from_dataProvider(UniqueCFRef<CGDataProviderRef> provider) {
+static SkTypeface* create_from_dataProvider(UniqueCFRef<CGDataProviderRef> provider, int ttcIndex) {
+    if (ttcIndex != 0) {
+        return nullptr;
+    }
     UniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
     if (!cg) {
         return nullptr;
@@ -1695,13 +1700,14 @@
     }
     self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble);
 }
-static bool get_variations(CTFontRef fFontRef, CFIndex* cgAxisCount,
+static bool get_variations(CTFontRef ctFont, CFIndex* cgAxisCount,
                            SkAutoSTMalloc<4, SkFixed>* axisValues)
 {
-    // CTFontCopyVariationAxes and CTFontCopyVariation do not work when applied to fonts which
-    // started life with CGFontCreateWithDataProvider (they simply always return nullptr).
-    // As a result, we are limited to CGFontCopyVariationAxes and CGFontCopyVariations.
-    UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, nullptr));
+    // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when
+    // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always
+    // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and
+    // CGFontCopyVariations here until support for 10.10 and earlier is removed.
+    UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
     if (!cgFont) {
         return false;
     }
@@ -1766,6 +1772,126 @@
     return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0);
 }
 
+/** Creates a CT variation dictionary {tag, value} from a CG variation dictionary {name, value}. */
+static UniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionaryRef cgVariations,
+                                                                   CFArrayRef ctAxes) {
+
+    UniqueCFRef<CFMutableDictionaryRef> ctVariations(
+            CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                      &kCFTypeDictionaryKeyCallBacks,
+                                      &kCFTypeDictionaryValueCallBacks));
+
+    CFIndex axisCount = CFArrayGetCount(ctAxes);
+    for (CFIndex i = 0; i < axisCount; ++i) {
+        CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes, i);
+        if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
+            return nullptr;
+        }
+        CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
+
+        // The assumption is that values produced by kCTFontVariationAxisNameKey and
+        // kCGFontVariationAxisName will always be equal.
+        CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
+        if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
+            return nullptr;
+        }
+
+        CFTypeRef axisValue = CFDictionaryGetValue(cgVariations, axisName);
+        if (!axisValue || CFGetTypeID(axisValue) != CFNumberGetTypeID()) {
+            return nullptr;
+        }
+
+        CFTypeRef axisTag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
+        if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) {
+            return nullptr;
+        }
+
+        CFDictionaryAddValue(ctVariations.get(), axisTag, axisValue);
+    }
+    return std::move(ctVariations);
+}
+
+int SkTypeface_Mac::onGetVariationDesignPosition(
+        SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
+{
+    // The CGFont variation data does not contain the tag.
+
+    // This call always returns nullptr on 10.10 and under for CGFontCreateWithDataProvider fonts.
+    // When this happens, there is no API to provide the tag.
+    UniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get()));
+    if (!ctAxes) {
+        return -1;
+    }
+    CFIndex axisCount = CFArrayGetCount(ctAxes.get());
+    if (!coordinates || coordinateCount < axisCount) {
+        return axisCount;
+    }
+
+    // This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts.
+    // When this happens, try converting the CG variation to a CT variation.
+    // On 10.12 and later, this only returns non-default variations.
+    UniqueCFRef<CFDictionaryRef> ctVariations(CTFontCopyVariation(fFontRef.get()));
+    if (!ctVariations) {
+        // When 10.11 and earlier are no longer supported, the following code can be replaced with
+        // return -1 and ct_variation_from_cg_variation can be removed.
+        UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
+        if (!cgFont) {
+            return -1;
+        }
+        UniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get()));
+        if (!cgVariations) {
+            return -1;
+        }
+        ctVariations = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get());
+        if (!ctVariations) {
+            return -1;
+        }
+    }
+
+    for (int i = 0; i < axisCount; ++i) {
+        CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
+        if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
+            return -1;
+        }
+        CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
+
+        CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
+        if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
+            return -1;
+        }
+        CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
+        int64_t tagLong;
+        if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
+            return -1;
+        }
+        coordinates[i].axis = tagLong;
+
+        CGFloat variationCGFloat;
+        CFTypeRef variationValue = CFDictionaryGetValue(ctVariations.get(), tagNumber);
+        if (variationValue) {
+            if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) {
+                return -1;
+            }
+            CFNumberRef variationNumber = static_cast<CFNumberRef>(variationValue);
+            if (!CFNumberGetValue(variationNumber, kCFNumberCGFloatType, &variationCGFloat)) {
+                return -1;
+            }
+        } else {
+            CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
+            if (!def || CFGetTypeID(def) != CFNumberGetTypeID()) {
+                return -1;
+            }
+            CFNumberRef defNumber = static_cast<CFNumberRef>(def);
+            if (!CFNumberGetValue(defNumber, kCFNumberCGFloatType, &variationCGFloat)) {
+                return -1;
+            }
+        }
+        coordinates[i].value = CGToScalar(variationCGFloat);
+
+    }
+    return axisCount;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -2247,7 +2373,7 @@
         if (!pr) {
             return nullptr;
         }
-        return create_from_dataProvider(std::move(pr));
+        return create_from_dataProvider(std::move(pr), ttcIndex);
     }
 
     SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
@@ -2256,55 +2382,26 @@
         if (!pr) {
             return nullptr;
         }
-        return create_from_dataProvider(std::move(pr));
+        return create_from_dataProvider(std::move(pr), ttcIndex);
     }
 
-    static CFNumberRef get_tag_for_name(CFStringRef name, CFArrayRef ctAxes) {
-        CFIndex ctAxisCount = CFArrayGetCount(ctAxes);
-        for (int i = 0; i < ctAxisCount; ++i) {
-            CFTypeRef ctAxisInfo = CFArrayGetValueAtIndex(ctAxes, i);
-            if (CFDictionaryGetTypeID() != CFGetTypeID(ctAxisInfo)) {
-                return nullptr;
-            }
-            CFDictionaryRef ctAxisInfoDict = static_cast<CFDictionaryRef>(ctAxisInfo);
-
-            CFTypeRef ctAxisName = CFDictionaryGetValue(ctAxisInfoDict,
-                                                        kCTFontVariationAxisNameKey);
-            if (!ctAxisName || CFGetTypeID(ctAxisName) != CFStringGetTypeID()) {
-                return nullptr;
-            }
-
-            if (CFEqual(name, ctAxisName)) {
-                CFTypeRef tag = CFDictionaryGetValue(ctAxisInfoDict,
-                                                     kCTFontVariationAxisIdentifierKey);
-                if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
-                    return nullptr;
-                }
-                return static_cast<CFNumberRef>(tag);
-            }
-        }
-        return nullptr;
-    }
-    static UniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, const FontParameters& params) {
-        UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
-        if (!cgAxes) {
-            return nullptr;
-        }
-        CFIndex axisCount = CFArrayGetCount(cgAxes.get());
-
-        // The CGFont variation data is keyed by name, and lacks the tag.
+    /** Creates a dictionary suitable for setting the axes on a CGFont. */
+    static UniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, const SkFontArguments& args) {
+        // The CGFont variation data is keyed by name, but lacks the tag.
         // The CTFont variation data is keyed by tag, and also has the name.
-        // We would like to work with CTFont variaitons, but creating a CTFont font with
+        // We would like to work with CTFont variations, but creating a CTFont font with
         // CTFont variation dictionary runs into bugs. So use the CTFont variation data
         // to match names to tags to create the appropriate CGFont.
         UniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr));
+        // This call always returns nullptr on 10.10 and under.
+        // When this happens, there is no API to provide the tag.
         UniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct.get()));
-        if (!ctAxes || CFArrayGetCount(ctAxes.get()) != axisCount) {
+        if (!ctAxes) {
             return nullptr;
         }
+        CFIndex axisCount = CFArrayGetCount(ctAxes.get());
 
-        int paramAxisCount;
-        const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
+        const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
 
         UniqueCFRef<CFMutableDictionaryRef> dict(
                 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
@@ -2312,24 +2409,25 @@
                                           &kCFTypeDictionaryValueCallBacks));
 
         for (int i = 0; i < axisCount; ++i) {
-            CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes.get(), i);
+            CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
             if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
                 return nullptr;
             }
             CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
 
-            CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName);
+            // The assumption is that values produced by kCTFontVariationAxisNameKey and
+            // kCGFontVariationAxisName will always be equal.
+            // If they are ever not, seach the project history for "get_tag_for_name".
+            CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
             if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
                 return nullptr;
             }
 
-            CFNumberRef tagNumber =
-                    get_tag_for_name(static_cast<CFStringRef>(axisName), ctAxes.get());
-            if (!tagNumber) {
-                // Could not find a tag to go with the name of this index.
-                // This would be a bug in CG/CT.
-                continue;
+            CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
+            if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
+                return nullptr;
             }
+            CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
             int64_t tagLong;
             if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
                 return nullptr;
@@ -2337,9 +2435,9 @@
 
             // The variation axes can be set to any value, but cg will effectively pin them.
             // Pin them here to normalize.
-            CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue);
-            CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue);
-            CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisDefaultValue);
+            CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
+            CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
+            CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
             if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
                 !max || CFGetTypeID(max) != CFNumberGetTypeID() ||
                 !def || CFGetTypeID(def) != CFNumberGetTypeID())
@@ -2360,9 +2458,10 @@
             }
 
             double value = defDouble;
-            for (int j = 0; j < paramAxisCount; ++j) {
-                if (paramAxes[j].fTag == tagLong) {
-                    value = SkTPin(SkScalarToDouble(paramAxes[j].fStyleValue),minDouble,maxDouble);
+            for (int j = 0; j < position.coordinateCount; ++j) {
+                if (position.coordinates[j].axis == tagLong) {
+                    value = SkTPin(SkScalarToDouble(position.coordinates[j].value),
+                                   minDouble, maxDouble);
                     break;
                 }
             }
@@ -2372,8 +2471,11 @@
         }
         return std::move(dict);
     }
-    SkTypeface* onCreateFromStream(SkStreamAsset* bs, const FontParameters& params) const override {
+    SkTypeface* onCreateFromStream(SkStreamAsset* bs, const SkFontArguments& args) const override {
         std::unique_ptr<SkStreamAsset> s(bs);
+        if (args.getCollectionIndex() != 0) {
+            return nullptr;
+        }
         UniqueCFRef<CGDataProviderRef> provider(SkCreateDataProviderFromStream(std::move(s)));
         if (!provider) {
             return nullptr;
@@ -2383,7 +2485,7 @@
             return nullptr;
         }
 
-        UniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), params);
+        UniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), args);
         // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
         // created from a data provider does not appear to have any ownership of the underlying
         // data. The original CGFontRef must be kept alive until the copy will no longer be used.
@@ -2402,6 +2504,7 @@
         return create_from_CTFontRef(std::move(ct), std::move(cg), true);
     }
 
+    /** Creates a dictionary suitable for setting the axes on a CGFont. */
     static UniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, SkFontData* fontData) {
         UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
         if (!cgAxes) {
@@ -2456,6 +2559,9 @@
         return std::move(dict);
     }
     SkTypeface* onCreateFromFontData(std::unique_ptr<SkFontData> fontData) const override {
+        if (fontData->getIndex() != 0) {
+            return nullptr;
+        }
         UniqueCFRef<CGDataProviderRef> provider(
                 SkCreateDataProviderFromStream(fontData->detachStream()));
         if (!provider) {
@@ -2490,7 +2596,7 @@
         if (!pr) {
             return nullptr;
         }
-        return create_from_dataProvider(std::move(pr));
+        return create_from_dataProvider(std::move(pr), ttcIndex);
     }
 
     SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override {
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp
index e6e0715..fbcd01a 100644
--- a/src/ports/SkFontHost_win.cpp
+++ b/src/ports/SkFontHost_win.cpp
@@ -262,15 +262,19 @@
     SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
                                 PerGlyphInfo, const uint32_t*, uint32_t) const override;
     void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
-    virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
-                                uint16_t glyphs[], int glyphCount) const override;
+    int onCharsToGlyphs(const void* chars, Encoding encoding,
+                        uint16_t glyphs[], int glyphCount) const override;
     int onCountGlyphs() const override;
     int onGetUPEM() const override;
     void onGetFamilyName(SkString* familyName) const override;
     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override
+    {
+        return -1;
+    }
     int onGetTableTags(SkFontTableTag tags[]) const override;
-    virtual size_t onGetTableData(SkFontTableTag, size_t offset,
-                                  size_t length, void* data) const override;
+    size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
 };
 
 class FontMemResourceTypeface : public LogFontTypeface {
@@ -2455,17 +2459,20 @@
 
     SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
         std::unique_ptr<SkStreamAsset> stream(bareStream);
+        if (ttcIndex != 0) {
+            return nullptr;
+        }
         return create_from_stream(stream.get());
     }
 
     SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
         // could be in base impl
-        return this->createFromStream(new SkMemoryStream(sk_ref_sp(data)));
+        return this->createFromStream(new SkMemoryStream(sk_ref_sp(data)), ttcIndex);
     }
 
     SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
         // could be in base impl
-        return this->createFromStream(SkStream::MakeFromFile(path).release());
+        return this->createFromStream(SkStream::MakeFromFile(path).release(), ttcIndex);
     }
 
     SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override {
diff --git a/src/ports/SkFontMgr_FontConfigInterface.cpp b/src/ports/SkFontMgr_FontConfigInterface.cpp
index 81c4868..6264710 100644
--- a/src/ports/SkFontMgr_FontConfigInterface.cpp
+++ b/src/ports/SkFontMgr_FontConfigInterface.cpp
@@ -222,7 +222,7 @@
         return SkTypeface_FCI::Create(std::move(fontData), std::move(name), style, isFixedPitch);
     }
 
-    SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override {
+    SkTypeface* onCreateFromStream(SkStreamAsset* s, const SkFontArguments& args) const override {
         using Scanner = SkTypeface_FreeType::Scanner;
         std::unique_ptr<SkStreamAsset> stream(s);
         const size_t length = stream->getLength();
@@ -237,19 +237,18 @@
         SkFontStyle style;
         SkString name;
         Scanner::AxisDefinitions axisDefinitions;
-        if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(),
+        if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(),
                                &name, &style, &isFixedPitch, &axisDefinitions))
         {
             return nullptr;
         }
 
-        int paramAxisCount;
-        const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
         SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
-        Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name);
+        Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(),
+                                   axisValues, name);
 
         auto fontData = skstd::make_unique<SkFontData>(std::move(stream),
-                                                       params.getCollectionIndex(),
+                                                       args.getCollectionIndex(),
                                                        axisValues.get(),
                                                        axisDefinitions.count());
         return SkTypeface_FCI::Create(std::move(fontData), std::move(name), style, isFixedPitch);
diff --git a/src/ports/SkFontMgr_android.cpp b/src/ports/SkFontMgr_android.cpp
index d4d7967..a180215 100644
--- a/src/ports/SkFontMgr_android.cpp
+++ b/src/ports/SkFontMgr_android.cpp
@@ -201,8 +201,11 @@
             }
 
             SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
-            Scanner::computeAxisValues(axisDefinitions,
-                                       fontFile.fAxes.begin(), fontFile.fAxes.count(),
+            SkFontArguments::VariationPosition position = {
+                fontFile.fVariationDesignPosition.begin(),
+                fontFile.fVariationDesignPosition.count()
+            };
+            Scanner::computeAxisValues(axisDefinitions, position,
                                        axisValues, familyName);
 
             fStyles.push_back().reset(new SkTypeface_AndroidSystem(
@@ -428,25 +431,24 @@
         return new SkTypeface_AndroidStream(std::move(data), style, isFixedPitch, name);
     }
 
-    SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override {
+    SkTypeface* onCreateFromStream(SkStreamAsset* s, const SkFontArguments& args) const override {
         using Scanner = SkTypeface_FreeType::Scanner;
         std::unique_ptr<SkStreamAsset> stream(s);
         bool isFixedPitch;
         SkFontStyle style;
         SkString name;
         Scanner::AxisDefinitions axisDefinitions;
-        if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(),
+        if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(),
                                &name, &style, &isFixedPitch, &axisDefinitions))
         {
             return nullptr;
         }
 
-        int paramAxisCount;
-        const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
         SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
-        Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name);
+        Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(),
+                                   axisValues, name);
 
-        auto data = skstd::make_unique<SkFontData>(std::move(stream), params.getCollectionIndex(),
+        auto data = skstd::make_unique<SkFontData>(std::move(stream), args.getCollectionIndex(),
                                                    axisValues.get(), axisDefinitions.count());
         return new SkTypeface_AndroidStream(std::move(data), style, isFixedPitch, name);
     }
diff --git a/src/ports/SkFontMgr_android_parser.cpp b/src/ports/SkFontMgr_android_parser.cpp
index e5fdcd0..e50a739 100644
--- a/src/ports/SkFontMgr_android_parser.cpp
+++ b/src/ports/SkFontMgr_android_parser.cpp
@@ -167,8 +167,8 @@
                 if (valueLen == 4) {
                     axisTag = SkSetFourByteTag(value[0], value[1], value[2], value[3]);
                     axisTagIsValid = true;
-                    for (int j = 0; j < file.fAxes.count() - 1; ++j) {
-                        if (file.fAxes[j].fTag == axisTag) {
+                    for (int j = 0; j < file.fVariationDesignPosition.count() - 1; ++j) {
+                        if (file.fVariationDesignPosition[j].axis == axisTag) {
                             axisTagIsValid = false;
                             SK_FONTCONFIGPARSER_WARNING("'%c%c%c%c' axis specified more than once",
                                                         (axisTag >> 24) & 0xFF,
@@ -189,9 +189,9 @@
             }
         }
         if (axisTagIsValid && axisStyleValueIsValid) {
-            SkFontMgr::FontParameters::Axis& axis = file.fAxes.push_back();
-            axis.fTag = axisTag;
-            axis.fStyleValue = SkFixedToScalar(axisStyleValue);
+            auto& coordinate = file.fVariationDesignPosition.push_back();
+            coordinate.axis = axisTag;
+            coordinate.value = SkFixedToScalar(axisStyleValue);
         }
     },
     /*end*/nullptr,
diff --git a/src/ports/SkFontMgr_android_parser.h b/src/ports/SkFontMgr_android_parser.h
index efd8144..75b31c3 100644
--- a/src/ports/SkFontMgr_android_parser.h
+++ b/src/ports/SkFontMgr_android_parser.h
@@ -73,7 +73,7 @@
     int fIndex;
     int fWeight;
     enum class Style { kAuto, kNormal, kItalic } fStyle;
-    SkTArray<SkFontMgr::FontParameters::Axis, true> fAxes;
+    SkTArray<SkFontArguments::VariationPosition::Coordinate, true> fVariationDesignPosition;
 };
 
 /**
diff --git a/src/ports/SkFontMgr_custom.cpp b/src/ports/SkFontMgr_custom.cpp
index 4e4887d..91a5908 100644
--- a/src/ports/SkFontMgr_custom.cpp
+++ b/src/ports/SkFontMgr_custom.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "SkFontArguments.h"
 #include "SkFontDescriptor.h"
 #include "SkFontHost_FreeType_common.h"
 #include "SkFontMgr.h"
@@ -200,7 +201,7 @@
 }
 
 SkTypeface* SkFontMgr_Custom::onCreateFromStream(SkStreamAsset* s,
-                                                 const FontParameters& params) const
+                                                 const SkFontArguments& args) const
 {
     using Scanner = SkTypeface_FreeType::Scanner;
     std::unique_ptr<SkStreamAsset> stream(s);
@@ -208,19 +209,18 @@
     SkFontStyle style;
     SkString name;
     Scanner::AxisDefinitions axisDefinitions;
-    if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(),
+    if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(),
                             &name, &style, &isFixedPitch, &axisDefinitions))
     {
         return nullptr;
     }
 
-    int paramAxisCount;
-    const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
+    const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
     SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
-    Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name);
+    Scanner::computeAxisValues(axisDefinitions, position, axisValues, name);
 
-    auto data = skstd::make_unique<SkFontData>(std::move(stream), params.getCollectionIndex(),
-                                                axisValues.get(), axisDefinitions.count());
+    auto data = skstd::make_unique<SkFontData>(std::move(stream), args.getCollectionIndex(),
+                                               axisValues.get(), axisDefinitions.count());
     return new SkTypeface_Stream(std::move(data), style, isFixedPitch, false, name);
 }
 
diff --git a/src/ports/SkFontMgr_custom.h b/src/ports/SkFontMgr_custom.h
index 9149378..f8d083c 100644
--- a/src/ports/SkFontMgr_custom.h
+++ b/src/ports/SkFontMgr_custom.h
@@ -144,7 +144,7 @@
                                  const SkFontStyle& fontStyle) const override;
     SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override;
     SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override;
-    SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override;
+    SkTypeface* onCreateFromStream(SkStreamAsset* s, const SkFontArguments& args) const override;
     SkTypeface* onCreateFromFontData(std::unique_ptr<SkFontData> data) const override;
     SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override;
     SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override;
diff --git a/src/ports/SkFontMgr_fontconfig.cpp b/src/ports/SkFontMgr_fontconfig.cpp
index 63d720b..85230b3 100644
--- a/src/ports/SkFontMgr_fontconfig.cpp
+++ b/src/ports/SkFontMgr_fontconfig.cpp
@@ -899,25 +899,24 @@
         return new SkTypeface_stream(std::move(data), std::move(name), style, isFixedWidth);
     }
 
-    SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override {
+    SkTypeface* onCreateFromStream(SkStreamAsset* s, const SkFontArguments& args) const override {
         using Scanner = SkTypeface_FreeType::Scanner;
         std::unique_ptr<SkStreamAsset> stream(s);
         bool isFixedPitch;
         SkFontStyle style;
         SkString name;
         Scanner::AxisDefinitions axisDefinitions;
-        if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(),
+        if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(),
                                &name, &style, &isFixedPitch, &axisDefinitions))
         {
             return nullptr;
         }
 
-        int paramAxisCount;
-        const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
         SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
-        Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name);
+        Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(),
+                                   axisValues, name);
 
-        auto data = skstd::make_unique<SkFontData>(std::move(stream), params.getCollectionIndex(),
+        auto data = skstd::make_unique<SkFontData>(std::move(stream), args.getCollectionIndex(),
                                                    axisValues.get(), axisDefinitions.count());
         return new SkTypeface_stream(std::move(data), std::move(name), style, isFixedPitch);
     }
diff --git a/src/ports/SkTypeface_win_dw.h b/src/ports/SkTypeface_win_dw.h
index 1119841..ffc49f3 100644
--- a/src/ports/SkTypeface_win_dw.h
+++ b/src/ports/SkTypeface_win_dw.h
@@ -104,15 +104,19 @@
     SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
                                 PerGlyphInfo, const uint32_t*, uint32_t) const override;
     void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
-    virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
-                                uint16_t glyphs[], int glyphCount) const override;
+    int onCharsToGlyphs(const void* chars, Encoding encoding,
+                        uint16_t glyphs[], int glyphCount) const override;
     int onCountGlyphs() const override;
     int onGetUPEM() const override;
     void onGetFamilyName(SkString* familyName) const override;
     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override
+    {
+        return -1;
+    }
     int onGetTableTags(SkFontTableTag tags[]) const override;
-    virtual size_t onGetTableData(SkFontTableTag, size_t offset,
-                                  size_t length, void* data) const override;
+    size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
 
 private:
     typedef SkTypeface INHERITED;
diff --git a/tests/FontMgrAndroidParserTest.cpp b/tests/FontMgrAndroidParserTest.cpp
index 92dbd95..cbcfb3b 100644
--- a/tests/FontMgrAndroidParserTest.cpp
+++ b/tests/FontMgrAndroidParserTest.cpp
@@ -90,13 +90,13 @@
         for (int j = 0; j < fontFamilies[i]->fFonts.count(); ++j) {
             const FontFileInfo& ffi = fontFamilies[i]->fFonts[j];
             SkDebugf("  file (%d) %s#%d", ffi.fWeight, ffi.fFileName.c_str(), ffi.fIndex);
-            for (const auto& axis : ffi.fAxes) {
+            for (const auto& coordinate : ffi.fVariationDesignPosition) {
                 SkDebugf(" @'%c%c%c%c'=%f",
-                         (axis.fTag >> 24) & 0xFF,
-                         (axis.fTag >> 16) & 0xFF,
-                         (axis.fTag >>  8) & 0xFF,
-                         (axis.fTag      ) & 0xFF,
-                         axis.fStyleValue);
+                         (coordinate.axis >> 24) & 0xFF,
+                         (coordinate.axis >> 16) & 0xFF,
+                         (coordinate.axis >>  8) & 0xFF,
+                         (coordinate.axis      ) & 0xFF,
+                         coordinate.value);
             }
             SkDebugf("\n");
         }
diff --git a/tests/FontMgrTest.cpp b/tests/FontMgrTest.cpp
index 50e2d5a..b6a0cc5 100644
--- a/tests/FontMgrTest.cpp
+++ b/tests/FontMgrTest.cpp
@@ -150,6 +150,12 @@
         SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override {
             return new EmptyLocalizedStrings;
         }
+        int onGetVariationDesignPosition(
+                SkFontArguments::VariationPosition::Coordinate coordinates[],
+                int coordinateCount) const override
+        {
+            return 0;
+        }
         int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
         size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override {
             return 0;
diff --git a/tests/TypefaceTest.cpp b/tests/TypefaceTest.cpp
index 2a3b32d..4786cc2 100644
--- a/tests/TypefaceTest.cpp
+++ b/tests/TypefaceTest.cpp
@@ -6,6 +6,9 @@
  */
 
 #include "SkData.h"
+#include "SkFixed.h"
+#include "SkFontMgr.h"
+#include "SkMakeUnique.h"
 #include "SkOTTable_OS_2.h"
 #include "SkSFNTHeader.h"
 #include "SkStream.h"
@@ -87,6 +90,77 @@
     }
 }
 
+DEF_TEST(TypefaceAxes, reporter) {
+    std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("/fonts/Distortable.ttf"));
+    if (!distortable) {
+        REPORT_FAILURE(reporter, "distortable", SkString());
+        return;
+    }
+
+    sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
+    const SkFontArguments::VariationPosition::Coordinate position[] = {
+        { SkSetFourByteTag('w','g','h','t'), SK_ScalarSqrt2 }
+    };
+    SkFontArguments params;
+    params.setVariationDesignPosition({position, SK_ARRAY_COUNT(position)});
+    // TODO: if axes are set and the back-end doesn't support them, should we create the typeface?
+    sk_sp<SkTypeface> typeface(fm->createFromStream(distortable.release(), params));
+
+    int count = typeface->getVariationDesignPosition(nullptr, 0);
+    if (count == -1) {
+        return;
+    }
+    REPORTER_ASSERT(reporter, count == SK_ARRAY_COUNT(position));
+
+    SkFontArguments::VariationPosition::Coordinate positionRead[SK_ARRAY_COUNT(position)];
+    count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
+    REPORTER_ASSERT(reporter, count == SK_ARRAY_COUNT(position));
+
+    REPORTER_ASSERT(reporter, positionRead[0].axis == position[0].axis);
+
+    // Convert to fixed for "almost equal".
+    SkFixed fixedRead = SkScalarToFixed(positionRead[0].value);
+    SkFixed fixedOriginal = SkScalarToFixed(position[0].value);
+    REPORTER_ASSERT(reporter, fixedRead == fixedOriginal);
+}
+
+DEF_TEST(TypefaceVariationIndex, reporter) {
+    std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("/fonts/Distortable.ttf"));
+    if (!distortable) {
+        REPORT_FAILURE(reporter, "distortable", SkString());
+        return;
+    }
+
+    sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
+    SkFontArguments params;
+    // The first named variation position in Distortable is 'Thin'.
+    params.setCollectionIndex(0x00010000);
+    sk_sp<SkTypeface> typeface(fm->createFromStream(distortable.release(), params));
+    if (!typeface) {
+        // FreeType is the only weird thing that supports this, Skia just needs to make sure if it
+        // gets one of these things make sense.
+        return;
+    }
+
+    int count = typeface->getVariationDesignPosition(nullptr, 0);
+    if (!(count == 1)) {
+        REPORT_FAILURE(reporter, "count == 1", SkString());
+        return;
+    }
+
+    SkFontArguments::VariationPosition::Coordinate positionRead[1];
+    count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
+    if (count == -1) {
+        return;
+    }
+    if (!(count == 1)) {
+        REPORT_FAILURE(reporter, "count == 1", SkString());
+        return;
+    }
+    REPORTER_ASSERT(reporter, positionRead[0].axis == SkSetFourByteTag('w','g','h','t'));
+    REPORTER_ASSERT(reporter, positionRead[0].value == 0.5);
+}
+
 DEF_TEST(Typeface, reporter) {
 
     sk_sp<SkTypeface> t1(SkTypeface::MakeFromName(nullptr, SkFontStyle()));
@@ -134,6 +208,11 @@
         SK_ABORT("unimplemented");
         return nullptr;
     }
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override
+    {
+        return 0;
+    }
     int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
     size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; }
 };
diff --git a/third_party/freetype2/BUILD.gn b/third_party/freetype2/BUILD.gn
index 89b64e4..d543dac 100644
--- a/third_party/freetype2/BUILD.gn
+++ b/third_party/freetype2/BUILD.gn
@@ -17,6 +17,7 @@
   }
 } else {
   third_party("freetype2") {
+    public_defines = [ "SK_FREETYPE_MINIMUM_RUNTIME_VERSION=(((FREETYPE_MAJOR) << 24) | ((FREETYPE_MINOR) << 16) | ((FREETYPE_PATCH) << 8))" ]
     public_include_dirs = [ "../externals/freetype/include" ]
 
     deps = [