diff options
author | Ben Wagner <bungeman@google.com> | 2017-02-24 11:15:26 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-02-24 16:59:05 +0000 |
commit | fc497343cbcbd526f77da913ae2feca0e1b1b866 (patch) | |
tree | 98d57a95e80467c180b74f698072ea04c674af27 /src/ports/SkFontHost_FreeType.cpp | |
parent | 9fe1b22249171087a0f01c67369559f6fd491540 (diff) |
Add SkTypeface::getVariationDesignPosition.
Allow users to query a typeface's position in variation design space.
Change-Id: Id7cae439e795b8c9586394f11359fb7fe55e1c0b
Reviewed-on: https://skia-review.googlesource.com/8861
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
Diffstat (limited to 'src/ports/SkFontHost_FreeType.cpp')
-rw-r--r-- | src/ports/SkFontHost_FreeType.cpp | 390 |
1 files changed, 257 insertions, 133 deletions
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 47790f3644..1feea4d198 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,26 @@ 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; + + // FreeType from 2.6.1 (14d6b5d7) until 2.7.0 (ee3f36f6b38) uses font_index for both font index + // and named variation index on input, but masks the named variation index part on output. + // Manually keep track of when a named variation is requested for 2.6.1 until 2.7.1. + bool fNamedVariationSpecified; + SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID); }; @@ -271,6 +275,7 @@ extern "C" { SkFaceRec::SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID) : fNext(nullptr), fSkStream(std::move(stream)), fRefCnt(1), fFontID(fontID) + , fAxesCount(0), fNamedVariationSpecified(false) { sk_bzero(&fFTStream, sizeof(fFTStream)); fFTStream.size = fSkStream->getLength(); @@ -279,22 +284,29 @@ 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; + } + + // If a named variation is requested, don't overwrite the named variation's position. + if (data.getIndex() > 0xFFFF) { + rec->fNamedVariationSpecified = true; return; } SkDEBUGCODE( FT_MM_Var* variations = nullptr; - if (FT_Get_MM_Var(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 +315,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 +349,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 +363,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 +383,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 +418,88 @@ 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; } + bool isNamedVariationSpecified() { + return fFaceRec ? fFaceRec->fNamedVariationSpecified : false; + } + +private: + 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: - FT_Face fFace; + 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 +827,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 +916,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 +932,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 +979,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 +995,7 @@ SkScalerContext_FreeType::~SkScalerContext_FreeType() { FT_Done_Size(fFTSize); } - if (fFace != nullptr) { - unref_ft_face(fFace); - } + fFaceRec = nullptr; unref_ft_library(); } @@ -1500,6 +1579,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 (fta.isNamedVariationSpecified()) { + // The font has axes, they cannot be retrieved, and some named axis was specified. + return -1; + } else { + // The font has axes, they cannot be retrieved, but no named instance was specified. + return 0; + } + + return variations->num_axis; +} + int SkTypeface_FreeType::onGetTableTags(SkFontTableTag tags[]) const { AutoFTAccess fta(this); FT_Face face = fta.face(); @@ -1730,7 +1854,7 @@ 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 +1863,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 +1875,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 +1887,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) { |