Add SkTypeface::getVariationDesignParameters

This adds a way for users to query the axis parameters for a typeface.

Change-Id: Idc2ac0d84bc7ae2ca484ae410cba5b01883418e5
Reviewed-on: https://skia-review.googlesource.com/137706
Commit-Queue: Ben Wagner <bungeman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/gn/core.gni b/gn/core.gni
index d379816..96ac5cd 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -399,6 +399,7 @@
   "$_include/core/SkFontArguments.h",
   "$_include/core/SkFontLCDConfig.h",
   "$_include/core/SkFontMgr.h",
+  "$_include/core/SkFontParameters.h",
   "$_include/core/SkFontStyle.h",
   "$_include/core/SkGraphics.h",
   "$_include/core/SkImage.h",
diff --git a/include/core/SkFontArguments.h b/include/core/SkFontArguments.h
index 473798f..52f2072 100644
--- a/include/core/SkFontArguments.h
+++ b/include/core/SkFontArguments.h
@@ -5,8 +5,8 @@
  * found in the LICENSE file.
  */
 
-#ifndef SkFontAgruments_DEFINED
-#define SkFontAgruments_DEFINED
+#ifndef SkFontArguments_DEFINED
+#define SkFontArguments_DEFINED
 
 #include "SkScalar.h"
 #include "SkTypes.h"
@@ -16,15 +16,15 @@
     struct VariationPosition {
         struct Coordinate {
             SkFourByteTag axis;
-            SkScalar value;
+            float value;
         };
         const Coordinate* coordinates;
         int coordinateCount;
     };
-    // deprecated, use VariationCoordinate instead
+    // deprecated, use VariationPosition::Coordinate instead
     struct Axis {
        SkFourByteTag fTag;
-       SkScalar fStyleValue;
+       float fStyleValue;
     };
 
     SkFontArguments() : fCollectionIndex(0), fVariationDesignPosition{nullptr, 0} {}
diff --git a/include/core/SkFontParameters.h b/include/core/SkFontParameters.h
new file mode 100644
index 0000000..7d3c407
--- /dev/null
+++ b/include/core/SkFontParameters.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontParameters_DEFINED
+#define SkFontParameters_DEFINED
+
+#include "SkScalar.h"
+#include "SkTypes.h"
+
+struct SkFontParameters {
+    struct Variation {
+        // Parameters in a variation font axis.
+        struct Axis {
+            // Four character identifier of the font axis (weight, width, slant, italic...).
+            SkFourByteTag tag;
+            // Minimum value supported by this axis.
+            float min;
+            // Default value set by this axis.
+            float def;
+            // Maximum value supported by this axis. The maximum can equal the minimum.
+            float max;
+            // Return whether this axis is recommended to be remain hidden in user interfaces.
+            bool isHidden() const { return flags & HIDDEN; }
+            // Set this axis to be remain hidden in user interfaces.
+            void setHidden(bool hidden) { flags = hidden ? (flags | HIDDEN) : (flags & ~HIDDEN); }
+        private:
+            static constexpr uint16_t HIDDEN = 0x0001;
+            // Attributes for a font axis.
+            uint16_t flags;
+        };
+    };
+};
+
+#endif
diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h
index 4118152..51f339c 100644
--- a/include/core/SkTypeface.h
+++ b/include/core/SkTypeface.h
@@ -11,6 +11,7 @@
 #include "../private/SkOnce.h"
 #include "../private/SkWeakRefCnt.h"
 #include "SkFontArguments.h"
+#include "SkFontParameters.h"
 #include "SkFontStyle.h"
 #include "SkRect.h"
 #include "SkString.h"
@@ -71,6 +72,20 @@
     int getVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
                                    int coordinateCount) const;
 
+    /** Copy into 'parameters' (allocated by the caller) the design variation parameters.
+     *
+     *  @param parameters the buffer into which to write the design variation parameters.
+     *  @param coordinateCount the number of entries available through 'parameters'.
+     *
+     *  @return The number of axes, or -1 if there is an error.
+     *  If 'parameters != nullptr' and 'parameterCount >= numAxes' then 'parameters' will be
+     *  filled with the variation parameters describing the position of this typeface in design
+     *  variation space. It is possible the number of axes can be retrieved but actual parameters
+     *  cannot.
+     */
+    int getVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                     int parameterCount) const;
+
     /** Return a 32bit value for this typeface, unique for the underlying font
         data. Will never return 0.
      */
@@ -341,6 +356,9 @@
         SkFontArguments::VariationPosition::Coordinate coordinates[],
         int coordinateCount) const = 0;
 
+    virtual int onGetVariationDesignParameters(
+        SkFontParameters::Variation::Axis parameters[], int parameterCount) const;
+
     virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0;
 
     virtual int onCharsToGlyphs(const void* chars, Encoding, SkGlyphID glyphs[],
diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp
index 8e90f51..cc0bd3f 100644
--- a/src/core/SkTypeface.cpp
+++ b/src/core/SkTypeface.cpp
@@ -79,6 +79,11 @@
     {
         return 0;
     }
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) 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;
@@ -207,6 +212,12 @@
     return this->onGetVariationDesignPosition(coordinates, coordinateCount);
 }
 
+int SkTypeface::getVariationDesignParameters(
+        SkFontParameters::Variation::Axis parameters[], int parameterCount) const
+{
+    return this->onGetVariationDesignParameters(parameters, parameterCount);
+}
+
 int SkTypeface::countTables() const {
     return this->onGetTableTags(nullptr);
 }
@@ -324,6 +335,11 @@
     return sk_ref_sp(this);
 }
 
+int SkTypeface::onGetVariationDesignParameters(
+        SkFontParameters::Variation::Axis parameters[], int parameterCount) const {
+    return -1;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "SkDescriptor.h"
diff --git a/src/core/SkTypeface_remote.h b/src/core/SkTypeface_remote.h
index 1b4ad89..c751745 100644
--- a/src/core/SkTypeface_remote.h
+++ b/src/core/SkTypeface_remote.h
@@ -82,6 +82,11 @@
         SK_ABORT("Should never be called.");
         return 0;
     }
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) const override {
+        SK_ABORT("Should never be called.");
+        return 0;
+    }
     void onGetFamilyName(SkString* familyName) const override {
         // Used by SkStrikeCache::DumpMemoryStatistics.
         *familyName = "";
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index b8ce203..03f499f 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -72,6 +72,12 @@
 #    define FT_LOAD_BITMAP_METRICS_ONLY ( 1L << 22 )
 #endif
 
+// FT_VAR_AXIS_FLAG_HIDDEN was introduced in FreeType 2.8.1
+// The variation axis should not be exposed to user interfaces.
+#ifndef FT_VAR_AXIS_FLAG_HIDDEN
+#    define FT_VAR_AXIS_FLAG_HIDDEN 1
+#endif
+
 //#define ENABLE_GLYPH_SPEW     // for tracing calls
 //#define DUMP_STRIKE_CREATION
 //#define SK_FONTHOST_FREETYPE_RUNTIME_VERSION
@@ -104,6 +110,7 @@
 public:
     FreeTypeLibrary()
         : fGetVarDesignCoordinates(nullptr)
+        , fGetVarAxisFlags(nullptr)
         , fLibrary(nullptr)
         , fIsLCDSupported(false)
         , fLCDExtra(0)
@@ -153,6 +160,19 @@
         }
 #endif
 
+#if SK_FREETYPE_MINIMUM_RUNTIME_VERSION >= 0x02080100
+        fGetVarAxisFlags = FT_Get_Var_Axis_Flags;
+#elif SK_FREETYPE_MINIMUM_RUNTIME_VERSION & SK_FREETYPE_DLOPEN
+        if (major > 2 || ((major == 2 && minor > 7) || (major == 2 && minor == 7 && patch >= 0))) {
+            //The FreeType library is already loaded, so symbols are available in process.
+            void* self = dlopen(nullptr, RTLD_LAZY);
+            if (self) {
+                *(void**)(&fGetVarAxisFlags) = dlsym(self, "FT_Get_Var_Axis_Flags");
+                dlclose(self);
+            }
+        }
+#endif
+
         // Setup LCD filtering. This reduces color fringes for LCD smoothed glyphs.
         // The default has changed over time, so this doesn't mean the same thing to all users.
         if (FT_Library_SetLcdFilter(fLibrary, FT_LCD_FILTER_DEFAULT) == 0) {
@@ -177,6 +197,12 @@
     using FT_Get_Var_Blend_CoordinatesProc = FT_Error (*)(FT_Face, FT_UInt, FT_Fixed*);
     FT_Get_Var_Blend_CoordinatesProc fGetVarDesignCoordinates;
 
+    // FT_Get_Var_Axis_Flags was introduced in FreeType 2.8.1
+    // Get the ‘flags’ field of an OpenType Variation Axis Record.
+    // Not meaningful for Adobe MM fonts (‘*flags’ is always zero).
+    using FT_Get_Var_Axis_FlagsProc = FT_Error (*)(FT_MM_Var*, FT_UInt, FT_UInt*);
+    FT_Get_Var_Axis_FlagsProc fGetVarAxisFlags;
+
 private:
     FT_Library fLibrary;
     bool fIsLCDSupported;
@@ -1546,18 +1572,21 @@
 }
 
 int SkTypeface_FreeType::onGetVariationDesignPosition(
-        SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
+    SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
 {
     AutoFTAccess fta(this);
     FT_Face face = fta.face();
+    if (!face) {
+        return -1;
+    }
 
-    if (!face || !(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
+    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;
+        return -1;
     }
     SkAutoFree autoFreeVariations(variations);
 
@@ -1590,6 +1619,44 @@
     return variations->num_axis;
 }
 
+int SkTypeface_FreeType::onGetVariationDesignParameters(
+    SkFontParameters::Variation::Axis parameters[], int parameterCount) const
+{
+    AutoFTAccess fta(this);
+    FT_Face face = fta.face();
+    if (!face) {
+        return -1;
+    }
+
+    if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
+        return 0;
+    }
+
+    FT_MM_Var* variations = nullptr;
+    if (FT_Get_MM_Var(face, &variations)) {
+        return -1;
+    }
+    SkAutoFree autoFreeVariations(variations);
+
+    if (!parameters || parameterCount < SkToInt(variations->num_axis)) {
+        return variations->num_axis;
+    }
+
+    for (FT_UInt i = 0; i < variations->num_axis; ++i) {
+        parameters[i].tag = variations->axis[i].tag;
+        parameters[i].min = SkFixedToScalar(variations->axis[i].minimum);
+        parameters[i].def = SkFixedToScalar(variations->axis[i].def);
+        parameters[i].max = SkFixedToScalar(variations->axis[i].maximum);
+        FT_UInt flags = 0;
+        bool hidden = gFTLibrary->fGetVarAxisFlags &&
+            !gFTLibrary->fGetVarAxisFlags(variations, i, &flags) &&
+            (flags & FT_VAR_AXIS_FLAG_HIDDEN);
+        parameters[i].setHidden(hidden);
+    }
+
+    return variations->num_axis;
+}
+
 int SkTypeface_FreeType::onGetTableTags(SkFontTableTag tags[]) const {
     AutoFTAccess fta(this);
     FT_Face face = fta.face();
diff --git a/src/ports/SkFontHost_FreeType_common.h b/src/ports/SkFontHost_FreeType_common.h
index 1386775..939aa4b 100644
--- a/src/ports/SkFontHost_FreeType_common.h
+++ b/src/ports/SkFontHost_FreeType_common.h
@@ -107,6 +107,8 @@
 
     int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
                                      int coordinateCount) const override;
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) 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_win.cpp b/src/ports/SkFontHost_win.cpp
index 264ae92..07d37ae 100644
--- a/src/ports/SkFontHost_win.cpp
+++ b/src/ports/SkFontHost_win.cpp
@@ -277,6 +277,11 @@
     {
         return -1;
     }
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) const override
+    {
+        return -1;
+    }
     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/SkTypeface_win_dw.cpp b/src/ports/SkTypeface_win_dw.cpp
index a7bad0d..3bf6134 100644
--- a/src/ports/SkTypeface_win_dw.cpp
+++ b/src/ports/SkTypeface_win_dw.cpp
@@ -185,8 +185,9 @@
     return nameIter;
 }
 
-int DWriteFontTypeface::onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
-    int coordinateCount) const {
+int DWriteFontTypeface::onGetVariationDesignPosition(
+    SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
+{
 
 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
 
@@ -210,20 +211,73 @@
         }
     }
 
-    if (!coordinates || !coordinateCount || !variableAxisCount) {
+    if (!coordinates || coordinateCount < variableAxisCount) {
         return variableAxisCount;
     }
 
     SkAutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> fontAxisValue(fontAxisCount);
     HR_GENERAL(fontFace5->GetFontAxisValues(fontAxisValue.get(), fontAxisCount), nullptr, -1);
-    UINT32 minCount = SkMin32(variableAxisCount, SkTo<UINT32>(coordinateCount));
-    UINT32 coordinatesIndex = 0;
+    UINT32 coordIndex = 0;
 
     for (UINT32 axisIndex = 0; axisIndex < fontAxisCount; ++axisIndex) {
         if (fontResource->GetFontAxisAttributes(axisIndex) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
-            coordinates[coordinatesIndex].axis = SkEndian_SwapBE32(fontAxisValue[axisIndex].axisTag);
-            coordinates[coordinatesIndex].value = fontAxisValue[axisIndex].value;
-            if (++coordinatesIndex == minCount) break;
+            coordinates[coordIndex].axis = SkEndian_SwapBE32(fontAxisValue[axisIndex].axisTag);
+            coordinates[coordIndex].value = fontAxisValue[axisIndex].value;
+        }
+    }
+
+    return variableAxisCount;
+
+#endif
+
+    return -1;
+}
+
+int DWriteFontTypeface::onGetVariationDesignParameters(
+    SkFontParameters::Variation::Axis parameters[], int parameterCount) const
+{
+
+#if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
+
+    SkTScopedComPtr<IDWriteFontFace5> fontFace5;
+    if (FAILED(fDWriteFontFace->QueryInterface(&fontFace5))) {
+        return -1;
+    }
+
+    // Return 0 if the font is not variable font.
+    if (!fontFace5->HasVariations()) {
+        return 0;
+    }
+
+    UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
+    SkTScopedComPtr<IDWriteFontResource> fontResource;
+    HR_GENERAL(fontFace5->GetFontResource(&fontResource), nullptr, -1);
+    int variableAxisCount = 0;
+    for (UINT32 i = 0; i < fontAxisCount; ++i) {
+        if (fontResource->GetFontAxisAttributes(i) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
+            variableAxisCount++;
+        }
+    }
+
+    if (!parameters || parameterCount < variableAxisCount) {
+        return variableAxisCount;
+    }
+
+    SkAutoSTMalloc<8, DWRITE_FONT_AXIS_RANGE> fontAxisRange(fontAxisCount);
+    HR_GENERAL(fontResource->GetFontAxisRanges(fontAxisRange.get(), fontAxisCount), nullptr, -1);
+    SkAutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> fontAxisDefaultValue(fontAxisCount);
+    HR_GENERAL(fontResource->GetDefaultFontAxisValues(fontAxisDefaultValue.get(), fontAxisCount),
+               nullptr, -1);
+    UINT32 coordIndex = 0;
+
+    for (UINT32 axisIndex = 0; axisIndex < fontAxisCount; ++axisIndex) {
+        if (fontResource->GetFontAxisAttributes(axisIndex) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
+            parameters[coordIndex].tag = SkEndian_SwapBE32(fontAxisDefaultValue[axisIndex].axisTag);
+            parameters[coordIndex].min = fontAxisRange[axisIndex].minValue;
+            parameters[coordIndex].def = fontAxisDefaultValue[axisIndex].value;
+            parameters[coordIndex].max = fontAxisRange[axisIndex].maxValue;
+            parameters[coordIndex].setHidden(fontResource->GetFontAxisAttributes(axisIndex) &
+                                             DWRITE_FONT_AXIS_ATTRIBUTES_HIDDEN);
         }
     }
 
diff --git a/src/ports/SkTypeface_win_dw.h b/src/ports/SkTypeface_win_dw.h
index 2d76b39..a671eb4 100644
--- a/src/ports/SkTypeface_win_dw.h
+++ b/src/ports/SkTypeface_win_dw.h
@@ -117,6 +117,8 @@
     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
     int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
                                      int coordinateCount) const override;
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) 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/tests/TypefaceTest.cpp b/tests/TypefaceTest.cpp
index 757f3a5..cc04fa2 100644
--- a/tests/TypefaceTest.cpp
+++ b/tests/TypefaceTest.cpp
@@ -226,6 +226,43 @@
     REPORTER_ASSERT(reporter, SkTypeface::Equal(t2.get(), nullptr));
 }
 
+DEF_TEST(TypefaceAxesParameters, reporter) {
+    std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
+    if (!distortable) {
+        REPORT_FAILURE(reporter, "distortable", SkString());
+        return;
+    }
+    constexpr int numberOfAxesInDistortable = 1;
+    constexpr SkScalar minAxisInDistortable = 0.5;
+    constexpr SkScalar defAxisInDistortable = 1;
+    constexpr SkScalar maxAxisInDistortable = 2;
+    constexpr bool axisIsHiddenInDistortable = false;
+
+    sk_sp<SkFontMgr> fm = SkFontMgr::RefDefault();
+
+    SkFontArguments params;
+    sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
+
+    if (!typeface) {
+        // Not all SkFontMgr can makeFromStream().
+        return;
+    }
+
+    SkFontParameters::Variation::Axis parameter[numberOfAxesInDistortable];
+    int count = typeface->getVariationDesignParameters(parameter, SK_ARRAY_COUNT(parameter));
+    if (count == -1) {
+        return;
+    }
+
+    REPORTER_ASSERT(reporter, count == SK_ARRAY_COUNT(parameter));
+    REPORTER_ASSERT(reporter, parameter[0].min == minAxisInDistortable);
+    REPORTER_ASSERT(reporter, parameter[0].def == defAxisInDistortable);
+    REPORTER_ASSERT(reporter, parameter[0].max == maxAxisInDistortable);
+    REPORTER_ASSERT(reporter, parameter[0].tag == SkSetFourByteTag('w','g','h','t'));
+    REPORTER_ASSERT(reporter, parameter[0].isHidden() == axisIsHiddenInDistortable);
+
+}
+
 namespace {
 
 class EmptyTypeface : public SkTypeface {
@@ -264,6 +301,11 @@
     {
         return 0;
     }
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) 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/tools/fonts/SkRandomScalerContext.cpp b/tools/fonts/SkRandomScalerContext.cpp
index c7cfbff..d32fd62 100644
--- a/tools/fonts/SkRandomScalerContext.cpp
+++ b/tools/fonts/SkRandomScalerContext.cpp
@@ -217,6 +217,12 @@
     return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount);
 }
 
+int SkRandomTypeface::onGetVariationDesignParameters(
+        SkFontParameters::Variation::Axis parameters[], int parameterCount) const
+{
+    return fProxy->onGetVariationDesignParameters(parameters, parameterCount);
+}
+
 int SkRandomTypeface::onGetTableTags(SkFontTableTag tags[]) const {
     return fProxy->getTableTags(tags);
 }
diff --git a/tools/fonts/SkRandomScalerContext.h b/tools/fonts/SkRandomScalerContext.h
index 8eb8b99..42f6095 100644
--- a/tools/fonts/SkRandomScalerContext.h
+++ b/tools/fonts/SkRandomScalerContext.h
@@ -43,6 +43,8 @@
 
     int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
                                      int coordinateCount) const override;
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) 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/tools/fonts/SkTestSVGTypeface.h b/tools/fonts/SkTestSVGTypeface.h
index 2275c67..597ec33 100644
--- a/tools/fonts/SkTestSVGTypeface.h
+++ b/tools/fonts/SkTestSVGTypeface.h
@@ -110,6 +110,12 @@
         return 0;
     }
 
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) const override
+    {
+        return 0;
+    }
+
     int onGetTableTags(SkFontTableTag tags[]) const override {
         return 0;
     }
diff --git a/tools/fonts/SkTestTypeface.h b/tools/fonts/SkTestTypeface.h
index e5ca64f..6778743 100644
--- a/tools/fonts/SkTestTypeface.h
+++ b/tools/fonts/SkTestTypeface.h
@@ -104,6 +104,12 @@
         return 0;
     }
 
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) const override
+    {
+        return 0;
+    }
+
     int onGetTableTags(SkFontTableTag tags[]) const override {
         return 0;
     }