diff options
author | Ben Wagner <bungeman@google.com> | 2017-02-16 16:56:26 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-02-17 18:05:47 +0000 |
commit | 87e7f820f74a990a59fb8f1d5c182584ce586ecf (patch) | |
tree | f278c33e19d91bcd4089c0723ad3cc7d29876bea | |
parent | 86125483f93fb9be7c90e1cea03054a1e0e80449 (diff) |
Add SkTypeface::getVariationDesignPosition.
Allow users to query a typeface's position in variation design space.
Change-Id: I5d80c8ff658708a5d1aa386ec5b7396dcb621198
Reviewed-on: https://skia-review.googlesource.com/7130
Commit-Queue: Ben Wagner <bungeman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
29 files changed, 653 insertions, 308 deletions
@@ -333,8 +333,8 @@ optional("fontmgr_android") { enabled = fontmgr_android_enabled deps = [ + ":typeface_freetype", "//third_party/expat", - "//third_party/freetype2", ] sources = [ "src/ports/SkFontMgr_android.cpp", @@ -347,7 +347,7 @@ optional("fontmgr_custom") { enabled = is_linux && skia_use_freetype && !skia_use_fontconfig deps = [ - "//third_party/freetype2", + ":typeface_freetype", ] sources = [ "src/ports/SkFontMgr_custom.cpp", @@ -363,8 +363,8 @@ optional("fontmgr_fontconfig") { enabled = skia_use_freetype && skia_use_fontconfig deps = [ + ":typeface_freetype", "//third_party:fontconfig", - "//third_party/freetype2", ] sources = [ "src/ports/SkFontConfigInterface.cpp", @@ -380,7 +380,7 @@ optional("fontmgr_fuchsia") { enabled = is_fuchsia && skia_use_freetype deps = [ - "//third_party/freetype2", + ":typeface_freetype", ] sources = [ "src/ports/SkFontMgr_custom.cpp", @@ -571,7 +571,6 @@ component("skia") { ":sse41", ":sse42", ":ssse3", - ":typeface_freetype", ":webp", ":xml", ] diff --git a/gm/fontscalerdistortable.cpp b/gm/fontscalerdistortable.cpp index c557ec573d..1823b50efa 100644 --- a/gm/fontscalerdistortable.cpp +++ b/gm/fontscalerdistortable.cpp @@ -49,9 +49,12 @@ protected: 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 bc6035be9d..8e3596af8d 100644 --- a/gn/core.gni +++ b/gn/core.gni @@ -394,6 +394,7 @@ skia_core_sources = [ "$_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 0000000000..473798fb84 --- /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 51d5a0b11c..07d8bc395b 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 @@ public: */ 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 @@ public: /** 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,10 @@ protected: // TODO: make pure virtual. virtual std::unique_ptr<SkFontData> onMakeFontData() const; + virtual int onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const = 0; + 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 4103e8747e..b5879d35b8 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 @@ public: */ 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 @@ protected: 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 03ac2eba83..8ce0b39682 100644 --- a/src/core/SkFontMgr.cpp +++ b/src/core/SkFontMgr.cpp @@ -132,11 +132,11 @@ SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, int ttcIndex) con 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 @@ SkTypeface* SkFontMgr::createFromFontData(std::unique_ptr<SkFontData> data) cons } // 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 70c0c76d06..2d8f920ba9 100644 --- a/src/core/SkTypeface.cpp +++ b/src/core/SkTypeface.cpp @@ -73,6 +73,11 @@ protected: 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 @@ sk_sp<SkTypeface> SkTypeface::MakeDeserialize(SkStream* stream) { /////////////////////////////////////////////////////////////////////////////// +int SkTypeface::getVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const +{ + return this->onGetVariationDesignPosition(coordinates, coordinateCount); +} + int SkTypeface::countTables() const { return this->onGetTableTags(nullptr); } diff --git a/src/fonts/SkGScalerContext.cpp b/src/fonts/SkGScalerContext.cpp index 8a0ac4cd64..3b9c660636 100644 --- a/src/fonts/SkGScalerContext.cpp +++ b/src/fonts/SkGScalerContext.cpp @@ -195,6 +195,12 @@ SkTypeface::LocalizedStrings* SkGTypeface::onCreateFamilyNameIterator() const { 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 3eb25a81da..562513c7bc 100644 --- a/src/fonts/SkGScalerContext.h +++ b/src/fonts/SkGScalerContext.h @@ -37,6 +37,8 @@ protected: 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 55c7fb30d4..3a292dcd79 100644 --- a/src/fonts/SkRandomScalerContext.cpp +++ b/src/fonts/SkRandomScalerContext.cpp @@ -242,6 +242,12 @@ SkTypeface::LocalizedStrings* SkRandomTypeface::onCreateFamilyNameIterator() con 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 076689d93a..c84b76470e 100644 --- a/src/fonts/SkRandomScalerContext.h +++ b/src/fonts/SkRandomScalerContext.h @@ -42,6 +42,8 @@ protected: 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 217e57c2a4..20cce91ab9 100644 --- a/src/fonts/SkTestScalerContext.h +++ b/src/fonts/SkTestScalerContext.h @@ -91,6 +91,12 @@ protected: 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 47790f3644..e9acadcaff 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 @@ FT_MemoryRec_ gFTMemory = { nullptr, sk_ft_alloc, sk_ft_free, sk_ft_realloc }; 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 @@ public: // 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 @@ public: 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 @@ private: // 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,69 +230,21 @@ static void unref_ft_library() { } } -class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base { -public: - SkScalerContext_FreeType(sk_sp<SkTypeface>, - const SkScalerContextEffects&, - const SkDescriptor* desc); - virtual ~SkScalerContext_FreeType(); - - bool success() const { - return fFTSize != nullptr && fFace != nullptr; - } - -protected: - unsigned generateGlyphCount() override; - uint16_t generateCharToGlyph(SkUnichar uni) override; - void generateAdvance(SkGlyph* glyph) override; - void generateMetrics(SkGlyph* glyph) override; - void generateImage(const SkGlyph& glyph) override; - void generatePath(SkGlyphID glyphID, SkPath* path) override; - void generateFontMetrics(SkPaint::FontMetrics*) override; - SkUnichar generateGlyphToChar(uint16_t glyph) override; - -private: - FT_Face fFace; // Shared face from gFaceRecHead. - FT_Size fFTSize; // The size on the fFace for this scaler. - FT_Int fStrikeIndex; - - /** The rest of the matrix after FreeType handles the size. - * With outline font rasterization this is handled by FreeType with FT_Set_Transform. - * With bitmap only fonts this matrix must be applied to scale the bitmap. - */ - SkMatrix fMatrix22Scalar; - /** Same as fMatrix22Scalar, but in FreeType units and space. */ - FT_Matrix fMatrix22; - /** The actual size requested. */ - SkVector fScale; - - uint32_t fLoadGlyphFlags; - bool fDoLinearMetrics; - bool fLCDIsVert; - - FT_Error setupSize(); - void getBBoxForCurrentGlyph(SkGlyph* glyph, FT_BBox* bbox, - bool snapToPixelBoundary = false); - bool getCBoxForLetter(char letter, FT_BBox* bbox); - // Caller must lock gFTMutex before calling this function. - void updateGlyphIfLCD(SkGlyph* glyph); - // Caller must lock gFTMutex before calling this function. - // update FreeType2 glyph slot with glyph emboldened - void emboldenIfNeeded(FT_Face face, FT_GlyphSlot glyph); - bool shouldSubpixelBitmap(const SkGlyph&, const SkMatrix&); -}; - -/////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// struct SkFaceRec { SkFaceRec* fNext; - FT_Face fFace; + 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; + SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID); }; @@ -270,7 +269,7 @@ extern "C" { } SkFaceRec::SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID) - : fNext(nullptr), fSkStream(std::move(stream)), fRefCnt(1), fFontID(fontID) + : fNext(nullptr), fSkStream(std::move(stream)), fRefCnt(1), fFontID(fontID), fAxesCount(0) { sk_bzero(&fFTStream, sizeof(fFTStream)); fFTStream.size = fSkStream->getLength(); @@ -279,22 +278,23 @@ SkFaceRec::SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID) 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)) { +static void ft_face_setup_axes(SkFaceRec* rec, const SkFontData& data) { + if (!(rec->fFace->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)); + 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", - face->family_name, variations->num_axis, data.getAxisCount())); + rec->fFace->family_name, variations->num_axis, data.getAxisCount())); return; } ) @@ -303,27 +303,33 @@ static void ft_face_setup_axes(FT_Face face, const SkFontData& data) { for (int i = 0; i < data.getAxisCount(); ++i) { coords[i] = data.getAxis()[i]; } - if (FT_Set_Var_Design_Coordinates(face, data.getAxisCount(), coords.get())) { + 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", - face->family_name)); + 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 0 on failure +// Will return nullptr on failure // Caller must lock gFTMutex before calling this function. -static FT_Face ref_ft_face(const SkTypeface* typeface) { +static SkFaceRec* 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; + SkFaceRec* cachedRec = gFaceRecHead; + while (cachedRec) { + if (cachedRec->fFontID == fontID) { + SkASSERT(cachedRec->fFace); + cachedRec->fRefCnt += 1; + return cachedRec; } - rec = rec->fNext; + cachedRec = cachedRec->fNext; } std::unique_ptr<SkFontData> data = typeface->makeFontData(); @@ -331,7 +337,7 @@ static FT_Face ref_ft_face(const SkTypeface* typeface) { return nullptr; } - rec = new SkFaceRec(data->detachStream(), fontID); + std::unique_ptr<SkFaceRec> rec(new SkFaceRec(data->detachStream(), fontID)); FT_Open_Args args; memset(&args, 0, sizeof(args)); @@ -345,15 +351,18 @@ static FT_Face ref_ft_face(const SkTypeface* typeface) { 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; + { + 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->fFace, *data); + 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. @@ -362,31 +371,29 @@ static FT_Face ref_ft_face(const SkTypeface* typeface) { // 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); + FT_Select_Charmap(rec->fFace.get(), FT_ENCODING_MS_SYMBOL); } rec->fNext = gFaceRecHead; - gFaceRecHead = rec; - return rec->fFace; + gFaceRecHead = rec.get(); + return rec.release(); } // Caller must lock gFTMutex before calling this function. -extern void unref_ft_face(FT_Face face); -void unref_ft_face(FT_Face face) { +static void unref_ft_face(SkFaceRec* faceRec) { gFTMutex.assertHeld(); SkFaceRec* rec = gFaceRecHead; SkFaceRec* prev = nullptr; while (rec) { SkFaceRec* next = rec->fNext; - if (rec->fFace == face) { + if (rec->fFace == faceRec->fFace) { if (--rec->fRefCnt == 0) { if (prev) { prev->fNext = next; } else { gFaceRecHead = next; } - FT_Done_Face(face); delete rec; } return; @@ -399,26 +406,85 @@ void unref_ft_face(FT_Face face) { class AutoFTAccess { public: - AutoFTAccess(const SkTypeface* tf) : fFace(nullptr) { + AutoFTAccess(const SkTypeface* tf) : fFaceRec(nullptr) { gFTMutex.acquire(); if (!ref_ft_library()) { sk_throw(); } - fFace = ref_ft_face(tf); + fFaceRec = ref_ft_face(tf); } ~AutoFTAccess() { - if (fFace) { - unref_ft_face(fFace); + if (fFaceRec) { + unref_ft_face(fFaceRec); } unref_ft_library(); gFTMutex.release(); } - FT_Face face() { return fFace; } + FT_Face face() { return fFaceRec ? fFaceRec->fFace.get() : nullptr; } + int getAxesCount() { return fFaceRec ? fFaceRec->fAxesCount : 0; } + SkFixed* getAxes() { return fFaceRec ? fFaceRec->fAxes.get() : nullptr; } private: - FT_Face fFace; + SkFaceRec* fFaceRec; +}; + +/////////////////////////////////////////////////////////////////////////// + +class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base { +public: + SkScalerContext_FreeType(sk_sp<SkTypeface>, + const SkScalerContextEffects&, + const SkDescriptor* desc); + virtual ~SkScalerContext_FreeType(); + + bool success() const { + return fFTSize != nullptr && fFace != nullptr; + } + +protected: + unsigned generateGlyphCount() override; + uint16_t generateCharToGlyph(SkUnichar uni) override; + void generateAdvance(SkGlyph* glyph) override; + void generateMetrics(SkGlyph* glyph) override; + void generateImage(const SkGlyph& glyph) override; + void generatePath(SkGlyphID glyphID, SkPath* path) override; + void generateFontMetrics(SkPaint::FontMetrics*) override; + SkUnichar generateGlyphToChar(uint16_t glyph) override; + +private: + 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; + + /** The rest of the matrix after FreeType handles the size. + * With outline font rasterization this is handled by FreeType with FT_Set_Transform. + * With bitmap only fonts this matrix must be applied to scale the bitmap. + */ + SkMatrix fMatrix22Scalar; + /** Same as fMatrix22Scalar, but in FreeType units and space. */ + FT_Matrix fMatrix22; + /** The actual size requested. */ + SkVector fScale; + + uint32_t fLoadGlyphFlags; + bool fDoLinearMetrics; + bool fLCDIsVert; + + FT_Error setupSize(); + void getBBoxForCurrentGlyph(SkGlyph* glyph, FT_BBox* bbox, + bool snapToPixelBoundary = false); + bool getCBoxForLetter(char letter, FT_BBox* bbox); + // Caller must lock gFTMutex before calling this function. + void updateGlyphIfLCD(SkGlyph* glyph); + // Caller must lock gFTMutex before calling this function. + // update FreeType2 glyph slot with glyph emboldened + void emboldenIfNeeded(FT_Face face, FT_GlyphSlot glyph); + bool shouldSubpixelBitmap(const SkGlyph&, const SkMatrix&); }; /////////////////////////////////////////////////////////////////////////// @@ -746,11 +812,10 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(sk_sp<SkTypeface> typeface, 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 +901,11 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(sk_sp<SkTypeface> typeface, } 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 +917,37 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(sk_sp<SkTypeface> typeface, 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 +964,12 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(sk_sp<SkTypeface> typeface, // 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 +980,7 @@ SkScalerContext_FreeType::~SkScalerContext_FreeType() { FT_Done_Size(fFTSize); } - if (fFace != nullptr) { - unref_ft_face(fFace); - } + fFaceRec = nullptr; unref_ft_library(); } @@ -1500,6 +1564,51 @@ SkTypeface::LocalizedStrings* SkTypeface_FreeType::onCreateFamilyNameIterator() 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 ((face->face_index & 0xFFFF) == 0) { + // The font has axes, they cannot be retrieved, but no named instance was specified. + return 0; + } else { + // The font has axes, they cannot be retrieved, and some named axis was specified. + return -1; + } + + return variations->num_axis; +} + int SkTypeface_FreeType::onGetTableTags(SkFontTableTag tags[]) const { AutoFTAccess fta(this); FT_Face face = fta.face(); @@ -1730,7 +1839,7 @@ bool SkTypeface_FreeType::Scanner::scanFont( /*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 +1848,11 @@ bool SkTypeface_FreeType::Scanner::scanFont( 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 +1860,7 @@ bool SkTypeface_FreeType::Scanner::scanFont( (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 +1872,8 @@ bool SkTypeface_FreeType::Scanner::scanFont( 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 867e139c21..b9e8b13d7f 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 @@ public: 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 @@ protected: 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 7a46d40ec6..5ec6b6e600 100644 --- a/src/ports/SkFontHost_mac.cpp +++ b/src/ports/SkFontHost_mac.cpp @@ -492,6 +492,8 @@ protected: 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; @@ -1695,13 +1697,14 @@ static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) } 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 +1769,74 @@ std::unique_ptr<SkFontData> SkTypeface_Mac::onMakeFontData() const { return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0); } +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.10 and under for CGFontCreateWithDataProvider fonts. + // When this happens, there is no API to provide the tag. + // On 10.12 and later, this only returns non-default variations. + UniqueCFRef<CFDictionaryRef> ctVariations(CTFontCopyVariation(fFontRef.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; +} + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -2259,52 +2330,23 @@ protected: return create_from_dataProvider(std::move(pr)); } - 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(¶mAxisCount); + const SkFontArguments::VariationPosition position = args.getVariationDesignPosition(); UniqueCFRef<CFMutableDictionaryRef> dict( CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, @@ -2312,24 +2354,25 @@ protected: &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 +2380,9 @@ protected: // 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 +2403,10 @@ protected: } 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,7 +2416,7 @@ protected: } 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); UniqueCFRef<CGDataProviderRef> provider(SkCreateDataProviderFromStream(std::move(s))); if (!provider) { @@ -2383,7 +2427,7 @@ protected: 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 +2446,7 @@ protected: 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) { diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index e6e07159c4..6950a227d8 100644 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -262,15 +262,19 @@ protected: 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 { diff --git a/src/ports/SkFontMgr_FontConfigInterface.cpp b/src/ports/SkFontMgr_FontConfigInterface.cpp index 81c4868e5d..6264710008 100644 --- a/src/ports/SkFontMgr_FontConfigInterface.cpp +++ b/src/ports/SkFontMgr_FontConfigInterface.cpp @@ -222,7 +222,7 @@ protected: 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 @@ protected: 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(¶mAxisCount); 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 d4d7967dc5..a180215e88 100644 --- a/src/ports/SkFontMgr_android.cpp +++ b/src/ports/SkFontMgr_android.cpp @@ -201,8 +201,11 @@ public: } 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 @@ protected: 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(¶mAxisCount); 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 e5fdcd0dbf..e50a73946a 100644 --- a/src/ports/SkFontMgr_android_parser.cpp +++ b/src/ports/SkFontMgr_android_parser.cpp @@ -167,8 +167,8 @@ static const TagHandler axisHandler = { 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 @@ static const TagHandler axisHandler = { } } 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 efd8144f14..75b31c300e 100644 --- a/src/ports/SkFontMgr_android_parser.h +++ b/src/ports/SkFontMgr_android_parser.h @@ -73,7 +73,7 @@ struct FontFileInfo { 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 4e4887d27d..91a590827c 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* bareStream, int } 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 @@ SkTypeface* SkFontMgr_Custom::onCreateFromStream(SkStreamAsset* s, 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(¶mAxisCount); + 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 9149378a50..f8d083c049 100644 --- a/src/ports/SkFontMgr_custom.h +++ b/src/ports/SkFontMgr_custom.h @@ -144,7 +144,7 @@ protected: 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 63d720b390..85230b394e 100644 --- a/src/ports/SkFontMgr_fontconfig.cpp +++ b/src/ports/SkFontMgr_fontconfig.cpp @@ -899,25 +899,24 @@ protected: 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(¶mAxisCount); 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 1119841e00..ffc49f3d86 100644 --- a/src/ports/SkTypeface_win_dw.h +++ b/src/ports/SkTypeface_win_dw.h @@ -104,15 +104,19 @@ protected: 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 92dbd951c0..cbcfb3be2a 100644 --- a/tests/FontMgrAndroidParserTest.cpp +++ b/tests/FontMgrAndroidParserTest.cpp @@ -90,13 +90,13 @@ void DumpLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* label) { 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 50e2d5a606..b6a0cc5a74 100644 --- a/tests/FontMgrTest.cpp +++ b/tests/FontMgrTest.cpp @@ -150,6 +150,12 @@ static void test_matchStyleCSS3(skiatest::Reporter* reporter) { 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 2a3b32d2cf..51e2cdd6a7 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,76 @@ DEF_TEST(TypefaceStyle, reporter) { } } +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; + 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 == 1); +} + DEF_TEST(Typeface, reporter) { sk_sp<SkTypeface> t1(SkTypeface::MakeFromName(nullptr, SkFontStyle())); @@ -134,6 +207,11 @@ protected: 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 89b64e4ed9..d543dac347 100644 --- a/third_party/freetype2/BUILD.gn +++ b/third_party/freetype2/BUILD.gn @@ -17,6 +17,7 @@ if (skia_use_system_freetype2) { } } 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 = [ |