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>
This commit is contained in:
Ben Wagner 2017-02-24 11:15:26 -05:00 committed by Skia Commit-Bot
parent 9fe1b22249
commit fc497343cb
29 changed files with 843 additions and 410 deletions

View File

@ -335,8 +335,8 @@ optional("fontmgr_android") {
enabled = fontmgr_android_enabled enabled = fontmgr_android_enabled
deps = [ deps = [
":typeface_freetype",
"//third_party/expat", "//third_party/expat",
"//third_party/freetype2",
] ]
sources = [ sources = [
"src/ports/SkFontMgr_android.cpp", "src/ports/SkFontMgr_android.cpp",
@ -349,7 +349,7 @@ optional("fontmgr_custom") {
enabled = is_linux && skia_use_freetype && !skia_use_fontconfig enabled = is_linux && skia_use_freetype && !skia_use_fontconfig
deps = [ deps = [
"//third_party/freetype2", ":typeface_freetype",
] ]
sources = [ sources = [
"src/ports/SkFontMgr_custom.cpp", "src/ports/SkFontMgr_custom.cpp",
@ -365,8 +365,8 @@ optional("fontmgr_fontconfig") {
enabled = skia_use_freetype && skia_use_fontconfig enabled = skia_use_freetype && skia_use_fontconfig
deps = [ deps = [
":typeface_freetype",
"//third_party:fontconfig", "//third_party:fontconfig",
"//third_party/freetype2",
] ]
sources = [ sources = [
"src/ports/SkFontConfigInterface.cpp", "src/ports/SkFontConfigInterface.cpp",
@ -382,7 +382,7 @@ optional("fontmgr_fuchsia") {
enabled = is_fuchsia && skia_use_freetype enabled = is_fuchsia && skia_use_freetype
deps = [ deps = [
"//third_party/freetype2", ":typeface_freetype",
] ]
sources = [ sources = [
"src/ports/SkFontMgr_custom.cpp", "src/ports/SkFontMgr_custom.cpp",
@ -581,7 +581,6 @@ component("skia") {
":sse41", ":sse41",
":sse42", ":sse42",
":ssse3", ":ssse3",
":typeface_freetype",
":webp", ":webp",
":xml", ":xml",
] ]

View File

@ -49,9 +49,12 @@ protected:
SkFourByteTag tag = SkSetFourByteTag('w','g','h','t'); SkFourByteTag tag = SkSetFourByteTag('w','g','h','t');
SkScalar styleValue = SkDoubleToScalar(0.5 + (5*j + i) * ((2.0 - 0.5) / (2 * 5))); 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( paint.setTypeface(sk_sp<SkTypeface>(fontMgr->createFromStream(
distortable->duplicate(), SkFontMgr::FontParameters().setAxes(axes, 1)))); distortable->duplicate(),
SkFontArguments().setVariationDesignPosition(position))));
SkAutoCanvasRestore acr(canvas, true); SkAutoCanvasRestore acr(canvas, true);
canvas->translate(SkIntToScalar(30 + i * 100), SkIntToScalar(20)); canvas->translate(SkIntToScalar(30 + i * 100), SkIntToScalar(20));

View File

@ -398,6 +398,7 @@ skia_core_sources = [
"$_include/core/SkDrawLooper.h", "$_include/core/SkDrawLooper.h",
"$_include/core/SkFlattenable.h", "$_include/core/SkFlattenable.h",
"$_include/core/SkFlattenableSerialization.h", "$_include/core/SkFlattenableSerialization.h",
"$_include/core/SkFontArguments.h",
"$_include/core/SkFontLCDConfig.h", "$_include/core/SkFontLCDConfig.h",
"$_include/core/SkFontStyle.h", "$_include/core/SkFontStyle.h",
"$_include/core/SkGraphics.h", "$_include/core/SkGraphics.h",

View File

@ -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

View File

@ -11,6 +11,7 @@
#include "../private/SkBitmaskEnum.h" #include "../private/SkBitmaskEnum.h"
#include "../private/SkOnce.h" #include "../private/SkOnce.h"
#include "../private/SkWeakRefCnt.h" #include "../private/SkWeakRefCnt.h"
#include "SkFontArguments.h"
#include "SkFontStyle.h" #include "SkFontStyle.h"
#include "SkRect.h" #include "SkRect.h"
#include "SkString.h" #include "SkString.h"
@ -77,6 +78,20 @@ public:
*/ */
bool isFixedPitch() const { return fIsFixedPitch; } 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 /** Return a 32bit value for this typeface, unique for the underlying font
data. Will never return 0. data. Will never return 0.
*/ */
@ -96,16 +111,16 @@ public:
/** Returns the default typeface, which is never nullptr. */ /** Returns the default typeface, which is never nullptr. */
static sk_sp<SkTypeface> MakeDefault(Style style = SkTypeface::kNormal); static sk_sp<SkTypeface> MakeDefault(Style style = SkTypeface::kNormal);
/** Creates a new reference to the typeface that most closely matches the /** Creates a new reference to the typeface that most closely matches the
requested familyName and fontStyle. This method allows extended font requested familyName and fontStyle. This method allows extended font
face specifiers as in the SkFontStyle type. Will never return null. face specifiers as in the SkFontStyle type. Will never return null.
@param familyName May be NULL. The name of the font family. @param familyName May be NULL. The name of the font family.
@param fontStyle The style of the typeface. @param fontStyle The style of the typeface.
@return reference to the closest-matching typeface. Call must call @return reference to the closest-matching typeface. Call must call
unref() when they are done. 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. /** 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. Use this to pick a new style from the same family of the existing typeface.
@ -341,6 +356,11 @@ protected:
// TODO: make pure virtual. // TODO: make pure virtual.
virtual std::unique_ptr<SkFontData> onMakeFontData() const; virtual std::unique_ptr<SkFontData> onMakeFontData() const;
// TODO: make pure virtual.
virtual int onGetVariationDesignPosition(
SkFontArguments::VariationPosition::Coordinate coordinates[],
int coordinateCount) const;
virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0; virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0;
virtual int onCharsToGlyphs(const void* chars, Encoding, SkGlyphID glyphs[], virtual int onCharsToGlyphs(const void* chars, Encoding, SkGlyphID glyphs[],

View File

@ -8,9 +8,9 @@
#ifndef SkFontMgr_DEFINED #ifndef SkFontMgr_DEFINED
#define SkFontMgr_DEFINED #define SkFontMgr_DEFINED
#include "SkFontArguments.h"
#include "SkFontStyle.h" #include "SkFontStyle.h"
#include "SkRefCnt.h" #include "SkRefCnt.h"
#include "SkScalar.h"
#include "SkTypes.h" #include "SkTypes.h"
class SkData; class SkData;
@ -102,51 +102,10 @@ public:
*/ */
SkTypeface* createFromStream(SkStreamAsset*, int ttcIndex = 0) const; SkTypeface* createFromStream(SkStreamAsset*, int ttcIndex = 0) const;
struct FontParameters { // deprecated, use SkFontArguments instead.
struct Axis { using FontParameters = SkFontArguments;
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;
};
/* Experimental, API subject to change. */ /* 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. * Create a typeface from the specified font data.
@ -187,7 +146,7 @@ protected:
virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) const = 0; virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) const = 0;
virtual SkTypeface* onCreateFromStream(SkStreamAsset*, int ttcIndex) const = 0; virtual SkTypeface* onCreateFromStream(SkStreamAsset*, int ttcIndex) const = 0;
// TODO: make pure virtual. // 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* onCreateFromFontData(std::unique_ptr<SkFontData>) const;
virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const = 0; virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const = 0;

View File

@ -132,11 +132,11 @@ SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, int ttcIndex) con
return this->onCreateFromStream(stream, ttcIndex); 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) { if (nullptr == stream) {
return nullptr; return nullptr;
} }
return this->onCreateFromStream(stream, params); return this->onCreateFromStream(stream, args);
} }
SkTypeface* SkFontMgr::createFromFontData(std::unique_ptr<SkFontData> data) const { 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. // This implementation is temporary until it can be made pure virtual.
SkTypeface* SkFontMgr::onCreateFromStream(SkStreamAsset* stream, const FontParameters& p) const { SkTypeface* SkFontMgr::onCreateFromStream(SkStreamAsset* stream, const SkFontArguments& args) const{
return this->createFromStream(stream, p.getCollectionIndex()); return this->createFromStream(stream, args.getCollectionIndex());
} }
// This implementation is temporary until it can be made pure virtual. // This implementation is temporary until it can be made pure virtual.

View File

@ -73,6 +73,11 @@ protected:
SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override { SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override {
return new EmptyLocalizedStrings; return new EmptyLocalizedStrings;
} }
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
int coordinateCount) const override
{
return 0;
}
int onGetTableTags(SkFontTableTag tags[]) const override { return 0; } int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override {
return 0; 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 { int SkTypeface::countTables() const {
return this->onGetTableTags(nullptr); return this->onGetTableTags(nullptr);
} }
@ -239,6 +250,13 @@ std::unique_ptr<SkFontData> SkTypeface::onMakeFontData() const {
return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0); return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0);
}; };
// This implementation is temporary until this method can be made pure virtual.
int SkTypeface::onGetVariationDesignPosition(
SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
{
return -1;
}
int SkTypeface::charsToGlyphs(const void* chars, Encoding encoding, int SkTypeface::charsToGlyphs(const void* chars, Encoding encoding,
uint16_t glyphs[], int glyphCount) const { uint16_t glyphs[], int glyphCount) const {
if (glyphCount <= 0) { if (glyphCount <= 0) {

View File

@ -195,6 +195,12 @@ SkTypeface::LocalizedStrings* SkGTypeface::onCreateFamilyNameIterator() const {
return fProxy->createFamilyNameIterator(); return fProxy->createFamilyNameIterator();
} }
int SkGTypeface::onGetVariationDesignPosition(
SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
{
return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount);
}
int SkGTypeface::onGetTableTags(SkFontTableTag tags[]) const { int SkGTypeface::onGetTableTags(SkFontTableTag tags[]) const {
return fProxy->getTableTags(tags); return fProxy->getTableTags(tags);
} }

View File

@ -37,6 +37,8 @@ protected:
void onGetFamilyName(SkString* familyName) const override; void onGetFamilyName(SkString* familyName) const override;
SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
int coordinateCount) const override;
int onGetTableTags(SkFontTableTag tags[]) const override; int onGetTableTags(SkFontTableTag tags[]) const override;
size_t onGetTableData(SkFontTableTag, size_t offset, size_t onGetTableData(SkFontTableTag, size_t offset,
size_t length, void* data) const override; size_t length, void* data) const override;

View File

@ -242,6 +242,12 @@ SkTypeface::LocalizedStrings* SkRandomTypeface::onCreateFamilyNameIterator() con
return fProxy->createFamilyNameIterator(); return fProxy->createFamilyNameIterator();
} }
int SkRandomTypeface::onGetVariationDesignPosition(
SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
{
return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount);
}
int SkRandomTypeface::onGetTableTags(SkFontTableTag tags[]) const { int SkRandomTypeface::onGetTableTags(SkFontTableTag tags[]) const {
return fProxy->getTableTags(tags); return fProxy->getTableTags(tags);
} }

View File

@ -42,6 +42,8 @@ protected:
void onGetFamilyName(SkString* familyName) const override; void onGetFamilyName(SkString* familyName) const override;
SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
int coordinateCount) const override;
int onGetTableTags(SkFontTableTag tags[]) const override; int onGetTableTags(SkFontTableTag tags[]) const override;
size_t onGetTableData(SkFontTableTag, size_t offset, size_t onGetTableData(SkFontTableTag, size_t offset,
size_t length, void* data) const override; size_t length, void* data) const override;

View File

@ -91,6 +91,12 @@ protected:
void onGetFamilyName(SkString* familyName) const override; void onGetFamilyName(SkString* familyName) const override;
SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() 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 { int onGetTableTags(SkFontTableTag tags[]) const override {
return 0; return 0;
} }

View File

@ -27,9 +27,6 @@
#include "SkTemplates.h" #include "SkTemplates.h"
#include <memory> #include <memory>
#if defined(SK_CAN_USE_DLOPEN)
#include <dlfcn.h>
#endif
#include <ft2build.h> #include <ft2build.h>
#include FT_ADVANCES_H #include FT_ADVANCES_H
#include FT_BITMAP_H #include FT_BITMAP_H
@ -44,6 +41,20 @@
#include FT_TYPE1_TABLES_H #include FT_TYPE1_TABLES_H
#include FT_XFREE86_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 // FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
// were introduced in FreeType 2.5.0. // were introduced in FreeType 2.5.0.
// The following may be removed once FreeType 2.5.0 is required to build. // 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 { class FreeTypeLibrary : SkNoncopyable {
public: public:
FreeTypeLibrary() : fLibrary(nullptr), fIsLCDSupported(false), fLCDExtra(0) { FreeTypeLibrary()
: fGetVarDesignCoordinates(nullptr)
, fLibrary(nullptr)
, fIsLCDSupported(false)
, fLCDExtra(0)
{
if (FT_New_Library(&gFTMemory, &fLibrary)) { if (FT_New_Library(&gFTMemory, &fLibrary)) {
return; return;
} }
FT_Add_Default_Modules(fLibrary); 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. // Setup LCD filtering. This reduces color fringes for LCD smoothed glyphs.
// Default { 0x10, 0x40, 0x70, 0x40, 0x10 } adds up to 0x110, simulating ink spread. // Default { 0x10, 0x40, 0x70, 0x40, 0x10 } adds up to 0x110, simulating ink spread.
// SetLcdFilter must be called before SetLcdFilterWeights. // SetLcdFilter must be called before SetLcdFilterWeights.
@ -102,23 +138,26 @@ public:
// Adds to 0x110 simulating ink spread, but provides better results than default. // Adds to 0x110 simulating ink spread, but provides better results than default.
static unsigned char gGaussianLikeHeavyWeights[] = { 0x1A, 0x43, 0x56, 0x43, 0x1A, }; 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); 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. //The FreeType library is already loaded, so symbols are available in process.
void* self = dlopen(nullptr, RTLD_LAZY); void* self = dlopen(nullptr, RTLD_LAZY);
if (self) { if (self) {
FT_Library_SetLcdFilterWeightsProc setLcdFilterWeights; FT_Library_SetLcdFilterWeightsProc setLcdFilterWeights;
//The following cast is non-standard, but safe for POSIX. // The following cast is non-standard, but safe for POSIX.
*reinterpret_cast<void**>(&setLcdFilterWeights) = // Cannot write this with reinterpret_cast, because clang has not implemented DR573.
dlsym(self, "FT_Library_SetLcdFilterWeights"); // 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); dlclose(self);
if (setLcdFilterWeights) { if (setLcdFilterWeights) {
setLcdFilterWeights(fLibrary, gGaussianLikeHeavyWeights); setLcdFilterWeights(fLibrary, gGaussianLikeHeavyWeights);
} }
} }
# endif # endif
#endif #endif
} }
} }
@ -132,6 +171,13 @@ public:
bool isLCDSupported() { return fIsLCDSupported; } bool isLCDSupported() { return fIsLCDSupported; }
int lcdExtra() { return fLCDExtra; } 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: private:
FT_Library fLibrary; FT_Library fLibrary;
bool fIsLCDSupported; bool fIsLCDSupported;
@ -144,7 +190,8 @@ private:
// OpenSuse >= 11.4 (previous deprecated January 2012 / Nov 2013 for Evergreen 11.2) // OpenSuse >= 11.4 (previous deprecated January 2012 / Nov 2013 for Evergreen 11.2)
// Fedora >= 14 (good) // Fedora >= 14 (good)
// Android >= Gingerbread (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; struct SkFaceRec;
@ -183,6 +230,223 @@ static void unref_ft_library() {
} }
} }
///////////////////////////////////////////////////////////////////////////
struct SkFaceRec {
SkFaceRec* fNext;
std::unique_ptr<FT_FaceRec, SkFunctionWrapper<FT_Error, FT_FaceRec, FT_Done_Face>> fFace;
FT_StreamRec fFTStream;
std::unique_ptr<SkStreamAsset> fSkStream;
uint32_t fRefCnt;
uint32_t fFontID;
// FreeType prior to 2.7.1 does not implement retreiving variation design metrics.
// Cache the variation design metrics used to create the font if the user specifies them.
SkAutoSTMalloc<4, SkFixed> fAxes;
int fAxesCount;
// FreeType from 2.6.1 (14d6b5d7) until 2.7.0 (ee3f36f6b38) uses font_index for both font index
// and named variation index on input, but masks the named variation index part on output.
// Manually keep track of when a named variation is requested for 2.6.1 until 2.7.1.
bool fNamedVariationSpecified;
SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID);
};
extern "C" {
static unsigned long sk_ft_stream_io(FT_Stream ftStream,
unsigned long offset,
unsigned char* buffer,
unsigned long count)
{
SkStreamAsset* stream = static_cast<SkStreamAsset*>(ftStream->descriptor.pointer);
if (count) {
if (!stream->seek(offset)) {
return 0;
}
count = stream->read(buffer, count);
}
return count;
}
static void sk_ft_stream_close(FT_Stream) {}
}
SkFaceRec::SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID)
: fNext(nullptr), fSkStream(std::move(stream)), fRefCnt(1), fFontID(fontID)
, fAxesCount(0), fNamedVariationSpecified(false)
{
sk_bzero(&fFTStream, sizeof(fFTStream));
fFTStream.size = fSkStream->getLength();
fFTStream.descriptor.pointer = fSkStream.get();
fFTStream.read = sk_ft_stream_io;
fFTStream.close = sk_ft_stream_close;
}
static void ft_face_setup_axes(SkFaceRec* rec, const SkFontData& data) {
if (!(rec->fFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
return;
}
// If a named variation is requested, don't overwrite the named variation's position.
if (data.getIndex() > 0xFFFF) {
rec->fNamedVariationSpecified = true;
return;
}
SkDEBUGCODE(
FT_MM_Var* variations = nullptr;
if (FT_Get_MM_Var(rec->fFace.get(), &variations)) {
SkDEBUGF(("INFO: font %s claims variations, but none found.\n",
rec->fFace->family_name));
return;
}
SkAutoFree autoFreeVariations(variations);
if (static_cast<FT_UInt>(data.getAxisCount()) != variations->num_axis) {
SkDEBUGF(("INFO: font %s has %d variations, but %d were specified.\n",
rec->fFace->family_name, variations->num_axis, data.getAxisCount()));
return;
}
)
SkAutoSTMalloc<4, FT_Fixed> coords(data.getAxisCount());
for (int i = 0; i < data.getAxisCount(); ++i) {
coords[i] = data.getAxis()[i];
}
if (FT_Set_Var_Design_Coordinates(rec->fFace.get(), data.getAxisCount(), coords.get())) {
SkDEBUGF(("INFO: font %s has variations, but specified variations could not be set.\n",
rec->fFace->family_name));
return;
}
rec->fAxesCount = data.getAxisCount();
rec->fAxes.reset(rec->fAxesCount);
for (int i = 0; i < rec->fAxesCount; ++i) {
rec->fAxes[i] = data.getAxis()[i];
}
}
// Will return nullptr on failure
// Caller must lock gFTMutex before calling this function.
static SkFaceRec* ref_ft_face(const SkTypeface* typeface) {
gFTMutex.assertHeld();
const SkFontID fontID = typeface->uniqueID();
SkFaceRec* cachedRec = gFaceRecHead;
while (cachedRec) {
if (cachedRec->fFontID == fontID) {
SkASSERT(cachedRec->fFace);
cachedRec->fRefCnt += 1;
return cachedRec;
}
cachedRec = cachedRec->fNext;
}
std::unique_ptr<SkFontData> data = typeface->makeFontData();
if (nullptr == data || !data->hasStream()) {
return nullptr;
}
std::unique_ptr<SkFaceRec> rec(new SkFaceRec(data->detachStream(), fontID));
FT_Open_Args args;
memset(&args, 0, sizeof(args));
const void* memoryBase = rec->fSkStream->getMemoryBase();
if (memoryBase) {
args.flags = FT_OPEN_MEMORY;
args.memory_base = (const FT_Byte*)memoryBase;
args.memory_size = rec->fSkStream->getLength();
} else {
args.flags = FT_OPEN_STREAM;
args.stream = &rec->fFTStream;
}
{
FT_Face rawFace;
FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rawFace);
if (err) {
SkDEBUGF(("ERROR: unable to open font '%x'\n", fontID));
return nullptr;
}
rec->fFace.reset(rawFace);
}
SkASSERT(rec->fFace);
ft_face_setup_axes(rec.get(), *data);
// FreeType will set the charmap to the "most unicode" cmap if it exists.
// If there are no unicode cmaps, the charmap is set to nullptr.
// However, "symbol" cmaps should also be considered "fallback unicode" cmaps
// because they are effectively private use area only (even if they aren't).
// This is the last on the fallback list at
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
if (!rec->fFace->charmap) {
FT_Select_Charmap(rec->fFace.get(), FT_ENCODING_MS_SYMBOL);
}
rec->fNext = gFaceRecHead;
gFaceRecHead = rec.get();
return rec.release();
}
// Caller must lock gFTMutex before calling this function.
static void unref_ft_face(SkFaceRec* faceRec) {
gFTMutex.assertHeld();
SkFaceRec* rec = gFaceRecHead;
SkFaceRec* prev = nullptr;
while (rec) {
SkFaceRec* next = rec->fNext;
if (rec->fFace == faceRec->fFace) {
if (--rec->fRefCnt == 0) {
if (prev) {
prev->fNext = next;
} else {
gFaceRecHead = next;
}
delete rec;
}
return;
}
prev = rec;
rec = next;
}
SkDEBUGFAIL("shouldn't get here, face not in list");
}
class AutoFTAccess {
public:
AutoFTAccess(const SkTypeface* tf) : fFaceRec(nullptr) {
gFTMutex.acquire();
if (!ref_ft_library()) {
sk_throw();
}
fFaceRec = ref_ft_face(tf);
}
~AutoFTAccess() {
if (fFaceRec) {
unref_ft_face(fFaceRec);
}
unref_ft_library();
gFTMutex.release();
}
FT_Face face() { return fFaceRec ? fFaceRec->fFace.get() : nullptr; }
int getAxesCount() { return fFaceRec ? fFaceRec->fAxesCount : 0; }
SkFixed* getAxes() { return fFaceRec ? fFaceRec->fAxes.get() : nullptr; }
bool isNamedVariationSpecified() {
return fFaceRec ? fFaceRec->fNamedVariationSpecified : false;
}
private:
SkFaceRec* fFaceRec;
};
///////////////////////////////////////////////////////////////////////////
class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base { class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base {
public: public:
SkScalerContext_FreeType(sk_sp<SkTypeface>, SkScalerContext_FreeType(sk_sp<SkTypeface>,
@ -205,7 +469,10 @@ protected:
SkUnichar generateGlyphToChar(uint16_t glyph) override; SkUnichar generateGlyphToChar(uint16_t glyph) override;
private: private:
FT_Face fFace; // Shared face from gFaceRecHead. using UnrefFTFace = SkFunctionWrapper<void, SkFaceRec, unref_ft_face>;
std::unique_ptr<SkFaceRec, UnrefFTFace> fFaceRec;
FT_Face fFace; // Borrowed face from gFaceRecHead.
FT_Size fFTSize; // The size on the fFace for this scaler. FT_Size fFTSize; // The size on the fFace for this scaler.
FT_Int fStrikeIndex; FT_Int fStrikeIndex;
@ -235,192 +502,6 @@ private:
bool shouldSubpixelBitmap(const SkGlyph&, const SkMatrix&); bool shouldSubpixelBitmap(const SkGlyph&, const SkMatrix&);
}; };
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
struct SkFaceRec {
SkFaceRec* fNext;
FT_Face fFace;
FT_StreamRec fFTStream;
std::unique_ptr<SkStreamAsset> fSkStream;
uint32_t fRefCnt;
uint32_t fFontID;
SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID);
};
extern "C" {
static unsigned long sk_ft_stream_io(FT_Stream ftStream,
unsigned long offset,
unsigned char* buffer,
unsigned long count)
{
SkStreamAsset* stream = static_cast<SkStreamAsset*>(ftStream->descriptor.pointer);
if (count) {
if (!stream->seek(offset)) {
return 0;
}
count = stream->read(buffer, count);
}
return count;
}
static void sk_ft_stream_close(FT_Stream) {}
}
SkFaceRec::SkFaceRec(std::unique_ptr<SkStreamAsset> stream, uint32_t fontID)
: fNext(nullptr), fSkStream(std::move(stream)), fRefCnt(1), fFontID(fontID)
{
sk_bzero(&fFTStream, sizeof(fFTStream));
fFTStream.size = fSkStream->getLength();
fFTStream.descriptor.pointer = fSkStream.get();
fFTStream.read = sk_ft_stream_io;
fFTStream.close = sk_ft_stream_close;
}
static void ft_face_setup_axes(FT_Face face, const SkFontData& data) {
if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
return;
}
SkDEBUGCODE(
FT_MM_Var* variations = nullptr;
if (FT_Get_MM_Var(face, &variations)) {
SkDEBUGF(("INFO: font %s claims variations, but none found.\n", face->family_name));
return;
}
SkAutoFree autoFreeVariations(variations);
if (static_cast<FT_UInt>(data.getAxisCount()) != variations->num_axis) {
SkDEBUGF(("INFO: font %s has %d variations, but %d were specified.\n",
face->family_name, variations->num_axis, data.getAxisCount()));
return;
}
)
SkAutoSTMalloc<4, FT_Fixed> coords(data.getAxisCount());
for (int i = 0; i < data.getAxisCount(); ++i) {
coords[i] = data.getAxis()[i];
}
if (FT_Set_Var_Design_Coordinates(face, data.getAxisCount(), coords.get())) {
SkDEBUGF(("INFO: font %s has variations, but specified variations could not be set.\n",
face->family_name));
return;
}
}
// Will return 0 on failure
// Caller must lock gFTMutex before calling this function.
static FT_Face ref_ft_face(const SkTypeface* typeface) {
gFTMutex.assertHeld();
const SkFontID fontID = typeface->uniqueID();
SkFaceRec* rec = gFaceRecHead;
while (rec) {
if (rec->fFontID == fontID) {
SkASSERT(rec->fFace);
rec->fRefCnt += 1;
return rec->fFace;
}
rec = rec->fNext;
}
std::unique_ptr<SkFontData> data = typeface->makeFontData();
if (nullptr == data || !data->hasStream()) {
return nullptr;
}
rec = new SkFaceRec(data->detachStream(), fontID);
FT_Open_Args args;
memset(&args, 0, sizeof(args));
const void* memoryBase = rec->fSkStream->getMemoryBase();
if (memoryBase) {
args.flags = FT_OPEN_MEMORY;
args.memory_base = (const FT_Byte*)memoryBase;
args.memory_size = rec->fSkStream->getLength();
} else {
args.flags = FT_OPEN_STREAM;
args.stream = &rec->fFTStream;
}
FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rec->fFace);
if (err) {
SkDEBUGF(("ERROR: unable to open font '%x'\n", fontID));
delete rec;
return nullptr;
}
SkASSERT(rec->fFace);
ft_face_setup_axes(rec->fFace, *data);
// FreeType will set the charmap to the "most unicode" cmap if it exists.
// If there are no unicode cmaps, the charmap is set to nullptr.
// However, "symbol" cmaps should also be considered "fallback unicode" cmaps
// because they are effectively private use area only (even if they aren't).
// This is the last on the fallback list at
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
if (!rec->fFace->charmap) {
FT_Select_Charmap(rec->fFace, FT_ENCODING_MS_SYMBOL);
}
rec->fNext = gFaceRecHead;
gFaceRecHead = rec;
return rec->fFace;
}
// Caller must lock gFTMutex before calling this function.
extern void unref_ft_face(FT_Face face);
void unref_ft_face(FT_Face face) {
gFTMutex.assertHeld();
SkFaceRec* rec = gFaceRecHead;
SkFaceRec* prev = nullptr;
while (rec) {
SkFaceRec* next = rec->fNext;
if (rec->fFace == face) {
if (--rec->fRefCnt == 0) {
if (prev) {
prev->fNext = next;
} else {
gFaceRecHead = next;
}
FT_Done_Face(face);
delete rec;
}
return;
}
prev = rec;
rec = next;
}
SkDEBUGFAIL("shouldn't get here, face not in list");
}
class AutoFTAccess {
public:
AutoFTAccess(const SkTypeface* tf) : fFace(nullptr) {
gFTMutex.acquire();
if (!ref_ft_library()) {
sk_throw();
}
fFace = ref_ft_face(tf);
}
~AutoFTAccess() {
if (fFace) {
unref_ft_face(fFace);
}
unref_ft_library();
gFTMutex.release();
}
FT_Face face() { return fFace; }
private:
FT_Face fFace;
};
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
static bool canEmbed(FT_Face face) { static bool canEmbed(FT_Face face) {
@ -746,11 +827,10 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(sk_sp<SkTypeface> typeface,
sk_throw(); sk_throw();
} }
fFaceRec.reset(ref_ft_face(this->getTypeface()));
// load the font file // load the font file
using UnrefFTFace = SkFunctionWrapper<void, skstd::remove_pointer_t<FT_Face>, unref_ft_face>; if (nullptr == fFaceRec) {
using FT_FaceRef = skstd::remove_pointer_t<FT_Face>;
std::unique_ptr<FT_FaceRef, UnrefFTFace> ftFace(ref_ft_face(this->getTypeface()));
if (nullptr == ftFace) {
SkDEBUGF(("Could not create FT_Face.\n")); SkDEBUGF(("Could not create FT_Face.\n"));
return; 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>; 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_Size size;
FT_Error err = FT_New_Size(ftFace.get(), &size); FT_Error err = FT_New_Size(fFaceRec->fFace.get(), &size);
if (err != 0) { 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 nullptr;
} }
return size; return size;
@ -852,36 +932,37 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(sk_sp<SkTypeface> typeface,
FT_Error err = FT_Activate_Size(ftSize.get()); FT_Error err = FT_Activate_Size(ftSize.get());
if (err != 0) { 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; return;
} }
if (FT_IS_SCALABLE(ftFace)) { if (FT_IS_SCALABLE(fFaceRec->fFace)) {
err = FT_Set_Char_Size(ftFace.get(), scaleX, scaleY, 72, 72); err = FT_Set_Char_Size(fFaceRec->fFace.get(), scaleX, scaleY, 72, 72);
if (err != 0) { if (err != 0) {
SkDEBUGF(("FT_Set_CharSize(%s, %f, %f) returned 0x%x.\n", 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; return;
} }
} else if (FT_HAS_FIXED_SIZES(ftFace)) { } else if (FT_HAS_FIXED_SIZES(fFaceRec->fFace)) {
fStrikeIndex = chooseBitmapStrike(ftFace.get(), scaleY); fStrikeIndex = chooseBitmapStrike(fFaceRec->fFace.get(), scaleY);
if (fStrikeIndex == -1) { 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; return;
} }
err = FT_Select_Size(ftFace.get(), fStrikeIndex); err = FT_Select_Size(fFaceRec->fFace.get(), fStrikeIndex);
if (err != 0) { if (err != 0) {
SkDEBUGF(("FT_Select_Size(%s, %d) returned 0x%x.\n", SkDEBUGF(("FT_Select_Size(%s, %d) returned 0x%x.\n",
ftFace->family_name, fStrikeIndex, err)); fFaceRec->fFace->family_name, fStrikeIndex, err));
fStrikeIndex = -1; fStrikeIndex = -1;
return; return;
} }
// A non-ideal size was picked, so recompute the matrix. // A non-ideal size was picked, so recompute the matrix.
// This adjusts for the difference between FT_Set_Char_Size and FT_Select_Size. // This adjusts for the difference between FT_Set_Char_Size and FT_Select_Size.
fMatrix22Scalar.preScale(fScale.x() / ftFace->size->metrics.x_ppem, fMatrix22Scalar.preScale(fScale.x() / fFaceRec->fFace->size->metrics.x_ppem,
fScale.y() / ftFace->size->metrics.y_ppem); fScale.y() / fFaceRec->fFace->size->metrics.y_ppem);
fMatrix22.xx = SkScalarToFixed(fMatrix22Scalar.getScaleX()); fMatrix22.xx = SkScalarToFixed(fMatrix22Scalar.getScaleX());
fMatrix22.xy = SkScalarToFixed(-fMatrix22Scalar.getSkewX()); fMatrix22.xy = SkScalarToFixed(-fMatrix22Scalar.getSkewX());
fMatrix22.yx = SkScalarToFixed(-fMatrix22Scalar.getSkewY()); 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. // Force this flag off for bitmap only fonts.
fLoadGlyphFlags &= ~FT_LOAD_NO_BITMAP; fLoadGlyphFlags &= ~FT_LOAD_NO_BITMAP;
} else { } 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; return;
} }
fFTSize = ftSize.release(); fFTSize = ftSize.release();
fFace = ftFace.release(); fFace = fFaceRec->fFace.get();
fDoLinearMetrics = linearMetrics; fDoLinearMetrics = linearMetrics;
} }
@ -914,9 +995,7 @@ SkScalerContext_FreeType::~SkScalerContext_FreeType() {
FT_Done_Size(fFTSize); FT_Done_Size(fFTSize);
} }
if (fFace != nullptr) { fFaceRec = nullptr;
unref_ft_face(fFace);
}
unref_ft_library(); unref_ft_library();
} }
@ -1500,6 +1579,51 @@ SkTypeface::LocalizedStrings* SkTypeface_FreeType::onCreateFamilyNameIterator()
return nameIter; 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 { int SkTypeface_FreeType::onGetTableTags(SkFontTableTag tags[]) const {
AutoFTAccess fta(this); AutoFTAccess fta(this);
FT_Face face = fta.face(); FT_Face face = fta.face();
@ -1730,7 +1854,7 @@ bool SkTypeface_FreeType::Scanner::scanFont(
/*static*/ void SkTypeface_FreeType::Scanner::computeAxisValues( /*static*/ void SkTypeface_FreeType::Scanner::computeAxisValues(
AxisDefinitions axisDefinitions, AxisDefinitions axisDefinitions,
const SkFontMgr::FontParameters::Axis* requestedAxes, int requestedAxisCount, const SkFontArguments::VariationPosition position,
SkFixed* axisValues, SkFixed* axisValues,
const SkString& name) const SkString& name)
{ {
@ -1739,11 +1863,11 @@ bool SkTypeface_FreeType::Scanner::scanFont(
const SkScalar axisMin = SkFixedToScalar(axisDefinition.fMinimum); const SkScalar axisMin = SkFixedToScalar(axisDefinition.fMinimum);
const SkScalar axisMax = SkFixedToScalar(axisDefinition.fMaximum); const SkScalar axisMax = SkFixedToScalar(axisDefinition.fMaximum);
axisValues[i] = axisDefinition.fDefault; axisValues[i] = axisDefinition.fDefault;
for (int j = 0; j < requestedAxisCount; ++j) { for (int j = 0; j < position.coordinateCount; ++j) {
const SkFontMgr::FontParameters::Axis& axisSpecified = requestedAxes[j]; const auto& coordinate = position.coordinates[j];
if (axisDefinition.fTag == axisSpecified.fTag) { if (axisDefinition.fTag == coordinate.axis) {
const SkScalar axisValue = SkTPin(axisSpecified.fStyleValue, axisMin, axisMax); const SkScalar axisValue = SkTPin(coordinate.value, axisMin, axisMax);
if (axisSpecified.fStyleValue != axisValue) { if (coordinate.value != axisValue) {
SkDEBUGF(("Requested font axis value out of range: " SkDEBUGF(("Requested font axis value out of range: "
"%s '%c%c%c%c' %f; pinned to %f.\n", "%s '%c%c%c%c' %f; pinned to %f.\n",
name.c_str(), name.c_str(),
@ -1751,7 +1875,7 @@ bool SkTypeface_FreeType::Scanner::scanFont(
(axisDefinition.fTag >> 16) & 0xFF, (axisDefinition.fTag >> 16) & 0xFF,
(axisDefinition.fTag >> 8) & 0xFF, (axisDefinition.fTag >> 8) & 0xFF,
(axisDefinition.fTag ) & 0xFF, (axisDefinition.fTag ) & 0xFF,
SkScalarToDouble(axisSpecified.fStyleValue), SkScalarToDouble(coordinate.value),
SkScalarToDouble(axisValue))); SkScalarToDouble(axisValue)));
} }
axisValues[i] = SkScalarToFixed(axisValue); axisValues[i] = SkScalarToFixed(axisValue);
@ -1763,8 +1887,8 @@ bool SkTypeface_FreeType::Scanner::scanFont(
SkDEBUGCODE( SkDEBUGCODE(
// Check for axis specified, but not matched in font. // Check for axis specified, but not matched in font.
for (int i = 0; i < requestedAxisCount; ++i) { for (int i = 0; i < position.coordinateCount; ++i) {
SkFourByteTag skTag = requestedAxes[i].fTag; SkFourByteTag skTag = position.coordinates[i].axis;
bool found = false; bool found = false;
for (int j = 0; j < axisDefinitions.count(); ++j) { for (int j = 0; j < axisDefinitions.count(); ++j) {
if (skTag == axisDefinitions[j].fTag) { if (skTag == axisDefinitions[j].fTag) {

View File

@ -17,8 +17,11 @@
#include "SkFontMgr.h" #include "SkFontMgr.h"
#include <ft2build.h> // These are forward declared to avoid pimpl but also hide the FreeType implementation.
#include FT_FREETYPE_H 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 { class SkScalerContext_FreeType_Base : public SkScalerContext {
protected: protected:
@ -59,7 +62,7 @@ public:
AxisDefinitions* axes) const; AxisDefinitions* axes) const;
static void computeAxisValues( static void computeAxisValues(
AxisDefinitions axisDefinitions, AxisDefinitions axisDefinitions,
const SkFontMgr::FontParameters::Axis* requestedAxis, int requestedAxisCount, const SkFontArguments::VariationPosition position,
SkFixed* axisValues, SkFixed* axisValues,
const SkString& name); const SkString& name);
@ -88,6 +91,8 @@ protected:
LocalizedStrings* onCreateFamilyNameIterator() const override; LocalizedStrings* onCreateFamilyNameIterator() const override;
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
int coordinateCount) const override;
int onGetTableTags(SkFontTableTag tags[]) const override; int onGetTableTags(SkFontTableTag tags[]) const override;
size_t onGetTableData(SkFontTableTag, size_t offset, size_t onGetTableData(SkFontTableTag, size_t offset,
size_t length, void* data) const override; size_t length, void* data) const override;

View File

@ -492,6 +492,8 @@ protected:
int onGetUPEM() const override; int onGetUPEM() const override;
SkStreamAsset* onOpenStream(int* ttcIndex) const override; SkStreamAsset* onOpenStream(int* ttcIndex) const override;
std::unique_ptr<SkFontData> onMakeFontData() 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; void onGetFamilyName(SkString* familyName) const override;
SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
int onGetTableTags(SkFontTableTag tags[]) const override; int onGetTableTags(SkFontTableTag tags[]) const override;
@ -1374,7 +1376,10 @@ void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element
// Returns nullptr on failure // Returns nullptr on failure
// Call must still manage its ownership of provider // Call must still manage its ownership of provider
static SkTypeface* create_from_dataProvider(UniqueCFRef<CGDataProviderRef> provider) { static SkTypeface* create_from_dataProvider(UniqueCFRef<CGDataProviderRef> provider, int ttcIndex) {
if (ttcIndex != 0) {
return nullptr;
}
UniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get())); UniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
if (!cg) { if (!cg) {
return nullptr; return nullptr;
@ -1695,13 +1700,14 @@ static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context)
} }
self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble); 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) SkAutoSTMalloc<4, SkFixed>* axisValues)
{ {
// CTFontCopyVariationAxes and CTFontCopyVariation do not work when applied to fonts which // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when
// started life with CGFontCreateWithDataProvider (they simply always return nullptr). // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always
// As a result, we are limited to CGFontCopyVariationAxes and CGFontCopyVariations. // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and
UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, nullptr)); // CGFontCopyVariations here until support for 10.10 and earlier is removed.
UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
if (!cgFont) { if (!cgFont) {
return false; return false;
} }
@ -1766,6 +1772,126 @@ std::unique_ptr<SkFontData> SkTypeface_Mac::onMakeFontData() const {
return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0); return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0);
} }
/** Creates a CT variation dictionary {tag, value} from a CG variation dictionary {name, value}. */
static UniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionaryRef cgVariations,
CFArrayRef ctAxes) {
UniqueCFRef<CFMutableDictionaryRef> ctVariations(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
CFIndex axisCount = CFArrayGetCount(ctAxes);
for (CFIndex i = 0; i < axisCount; ++i) {
CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes, i);
if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
return nullptr;
}
CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
// The assumption is that values produced by kCTFontVariationAxisNameKey and
// kCGFontVariationAxisName will always be equal.
CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
return nullptr;
}
CFTypeRef axisValue = CFDictionaryGetValue(cgVariations, axisName);
if (!axisValue || CFGetTypeID(axisValue) != CFNumberGetTypeID()) {
return nullptr;
}
CFTypeRef axisTag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) {
return nullptr;
}
CFDictionaryAddValue(ctVariations.get(), axisTag, axisValue);
}
return std::move(ctVariations);
}
int SkTypeface_Mac::onGetVariationDesignPosition(
SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
{
// The CGFont variation data does not contain the tag.
// This call always returns nullptr on 10.10 and under for CGFontCreateWithDataProvider fonts.
// When this happens, there is no API to provide the tag.
UniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get()));
if (!ctAxes) {
return -1;
}
CFIndex axisCount = CFArrayGetCount(ctAxes.get());
if (!coordinates || coordinateCount < axisCount) {
return axisCount;
}
// This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts.
// When this happens, try converting the CG variation to a CT variation.
// On 10.12 and later, this only returns non-default variations.
UniqueCFRef<CFDictionaryRef> ctVariations(CTFontCopyVariation(fFontRef.get()));
if (!ctVariations) {
// When 10.11 and earlier are no longer supported, the following code can be replaced with
// return -1 and ct_variation_from_cg_variation can be removed.
UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
if (!cgFont) {
return -1;
}
UniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get()));
if (!cgVariations) {
return -1;
}
ctVariations = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get());
if (!ctVariations) {
return -1;
}
}
for (int i = 0; i < axisCount; ++i) {
CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
return -1;
}
CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
return -1;
}
CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
int64_t tagLong;
if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
return -1;
}
coordinates[i].axis = tagLong;
CGFloat variationCGFloat;
CFTypeRef variationValue = CFDictionaryGetValue(ctVariations.get(), tagNumber);
if (variationValue) {
if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) {
return -1;
}
CFNumberRef variationNumber = static_cast<CFNumberRef>(variationValue);
if (!CFNumberGetValue(variationNumber, kCFNumberCGFloatType, &variationCGFloat)) {
return -1;
}
} else {
CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
if (!def || CFGetTypeID(def) != CFNumberGetTypeID()) {
return -1;
}
CFNumberRef defNumber = static_cast<CFNumberRef>(def);
if (!CFNumberGetValue(defNumber, kCFNumberCGFloatType, &variationCGFloat)) {
return -1;
}
}
coordinates[i].value = CGToScalar(variationCGFloat);
}
return axisCount;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -2247,7 +2373,7 @@ protected:
if (!pr) { if (!pr) {
return nullptr; return nullptr;
} }
return create_from_dataProvider(std::move(pr)); return create_from_dataProvider(std::move(pr), ttcIndex);
} }
SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override { SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
@ -2256,55 +2382,26 @@ protected:
if (!pr) { if (!pr) {
return nullptr; return nullptr;
} }
return create_from_dataProvider(std::move(pr)); return create_from_dataProvider(std::move(pr), ttcIndex);
} }
static CFNumberRef get_tag_for_name(CFStringRef name, CFArrayRef ctAxes) { /** Creates a dictionary suitable for setting the axes on a CGFont. */
CFIndex ctAxisCount = CFArrayGetCount(ctAxes); static UniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, const SkFontArguments& args) {
for (int i = 0; i < ctAxisCount; ++i) { // The CGFont variation data is keyed by name, but lacks the tag.
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.
// The CTFont variation data is keyed by tag, and also has the name. // 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 // CTFont variation dictionary runs into bugs. So use the CTFont variation data
// to match names to tags to create the appropriate CGFont. // to match names to tags to create the appropriate CGFont.
UniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr)); 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())); UniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct.get()));
if (!ctAxes || CFArrayGetCount(ctAxes.get()) != axisCount) { if (!ctAxes) {
return nullptr; return nullptr;
} }
CFIndex axisCount = CFArrayGetCount(ctAxes.get());
int paramAxisCount; const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
UniqueCFRef<CFMutableDictionaryRef> dict( UniqueCFRef<CFMutableDictionaryRef> dict(
CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
@ -2312,24 +2409,25 @@ protected:
&kCFTypeDictionaryValueCallBacks)); &kCFTypeDictionaryValueCallBacks));
for (int i = 0; i < axisCount; ++i) { for (int i = 0; i < axisCount; ++i) {
CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes.get(), i); CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
return nullptr; return nullptr;
} }
CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); 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()) { if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
return nullptr; return nullptr;
} }
CFNumberRef tagNumber = CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
get_tag_for_name(static_cast<CFStringRef>(axisName), ctAxes.get()); if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
if (!tagNumber) { return nullptr;
// Could not find a tag to go with the name of this index.
// This would be a bug in CG/CT.
continue;
} }
CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
int64_t tagLong; int64_t tagLong;
if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
return nullptr; return nullptr;
@ -2337,9 +2435,9 @@ protected:
// The variation axes can be set to any value, but cg will effectively pin them. // The variation axes can be set to any value, but cg will effectively pin them.
// Pin them here to normalize. // Pin them here to normalize.
CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue); CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue); CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisDefaultValue); CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
!max || CFGetTypeID(max) != CFNumberGetTypeID() || !max || CFGetTypeID(max) != CFNumberGetTypeID() ||
!def || CFGetTypeID(def) != CFNumberGetTypeID()) !def || CFGetTypeID(def) != CFNumberGetTypeID())
@ -2360,9 +2458,10 @@ protected:
} }
double value = defDouble; double value = defDouble;
for (int j = 0; j < paramAxisCount; ++j) { for (int j = 0; j < position.coordinateCount; ++j) {
if (paramAxes[j].fTag == tagLong) { if (position.coordinates[j].axis == tagLong) {
value = SkTPin(SkScalarToDouble(paramAxes[j].fStyleValue),minDouble,maxDouble); value = SkTPin(SkScalarToDouble(position.coordinates[j].value),
minDouble, maxDouble);
break; break;
} }
} }
@ -2372,8 +2471,11 @@ protected:
} }
return std::move(dict); 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); std::unique_ptr<SkStreamAsset> s(bs);
if (args.getCollectionIndex() != 0) {
return nullptr;
}
UniqueCFRef<CGDataProviderRef> provider(SkCreateDataProviderFromStream(std::move(s))); UniqueCFRef<CGDataProviderRef> provider(SkCreateDataProviderFromStream(std::move(s)));
if (!provider) { if (!provider) {
return nullptr; return nullptr;
@ -2383,7 +2485,7 @@ protected:
return nullptr; 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 // 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 // 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. // data. The original CGFontRef must be kept alive until the copy will no longer be used.
@ -2402,6 +2504,7 @@ protected:
return create_from_CTFontRef(std::move(ct), std::move(cg), true); 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) { static UniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, SkFontData* fontData) {
UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg)); UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
if (!cgAxes) { if (!cgAxes) {
@ -2456,6 +2559,9 @@ protected:
return std::move(dict); return std::move(dict);
} }
SkTypeface* onCreateFromFontData(std::unique_ptr<SkFontData> fontData) const override { SkTypeface* onCreateFromFontData(std::unique_ptr<SkFontData> fontData) const override {
if (fontData->getIndex() != 0) {
return nullptr;
}
UniqueCFRef<CGDataProviderRef> provider( UniqueCFRef<CGDataProviderRef> provider(
SkCreateDataProviderFromStream(fontData->detachStream())); SkCreateDataProviderFromStream(fontData->detachStream()));
if (!provider) { if (!provider) {
@ -2490,7 +2596,7 @@ protected:
if (!pr) { if (!pr) {
return nullptr; return nullptr;
} }
return create_from_dataProvider(std::move(pr)); return create_from_dataProvider(std::move(pr), ttcIndex);
} }
SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override { SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override {

View File

@ -262,15 +262,19 @@ protected:
SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
PerGlyphInfo, const uint32_t*, uint32_t) const override; PerGlyphInfo, const uint32_t*, uint32_t) const override;
void onGetFontDescriptor(SkFontDescriptor*, bool*) const override; void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
virtual int onCharsToGlyphs(const void* chars, Encoding encoding, int onCharsToGlyphs(const void* chars, Encoding encoding,
uint16_t glyphs[], int glyphCount) const override; uint16_t glyphs[], int glyphCount) const override;
int onCountGlyphs() const override; int onCountGlyphs() const override;
int onGetUPEM() const override; int onGetUPEM() const override;
void onGetFamilyName(SkString* familyName) const override; void onGetFamilyName(SkString* familyName) const override;
SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() 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; int onGetTableTags(SkFontTableTag tags[]) const override;
virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
size_t length, void* data) const override;
}; };
class FontMemResourceTypeface : public LogFontTypeface { class FontMemResourceTypeface : public LogFontTypeface {
@ -2455,17 +2459,20 @@ protected:
SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override { SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
std::unique_ptr<SkStreamAsset> stream(bareStream); std::unique_ptr<SkStreamAsset> stream(bareStream);
if (ttcIndex != 0) {
return nullptr;
}
return create_from_stream(stream.get()); return create_from_stream(stream.get());
} }
SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override { SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
// could be in base impl // could be in base impl
return this->createFromStream(new SkMemoryStream(sk_ref_sp(data))); return this->createFromStream(new SkMemoryStream(sk_ref_sp(data)), ttcIndex);
} }
SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
// could be in base impl // could be in base impl
return this->createFromStream(SkStream::MakeFromFile(path).release()); return this->createFromStream(SkStream::MakeFromFile(path).release(), ttcIndex);
} }
SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override { SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override {

View File

@ -222,7 +222,7 @@ protected:
return SkTypeface_FCI::Create(std::move(fontData), std::move(name), style, isFixedPitch); 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; using Scanner = SkTypeface_FreeType::Scanner;
std::unique_ptr<SkStreamAsset> stream(s); std::unique_ptr<SkStreamAsset> stream(s);
const size_t length = stream->getLength(); const size_t length = stream->getLength();
@ -237,19 +237,18 @@ protected:
SkFontStyle style; SkFontStyle style;
SkString name; SkString name;
Scanner::AxisDefinitions axisDefinitions; Scanner::AxisDefinitions axisDefinitions;
if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(), if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(),
&name, &style, &isFixedPitch, &axisDefinitions)) &name, &style, &isFixedPitch, &axisDefinitions))
{ {
return nullptr; return nullptr;
} }
int paramAxisCount;
const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); 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), auto fontData = skstd::make_unique<SkFontData>(std::move(stream),
params.getCollectionIndex(), args.getCollectionIndex(),
axisValues.get(), axisValues.get(),
axisDefinitions.count()); axisDefinitions.count());
return SkTypeface_FCI::Create(std::move(fontData), std::move(name), style, isFixedPitch); return SkTypeface_FCI::Create(std::move(fontData), std::move(name), style, isFixedPitch);

View File

@ -201,8 +201,11 @@ public:
} }
SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
Scanner::computeAxisValues(axisDefinitions, SkFontArguments::VariationPosition position = {
fontFile.fAxes.begin(), fontFile.fAxes.count(), fontFile.fVariationDesignPosition.begin(),
fontFile.fVariationDesignPosition.count()
};
Scanner::computeAxisValues(axisDefinitions, position,
axisValues, familyName); axisValues, familyName);
fStyles.push_back().reset(new SkTypeface_AndroidSystem( fStyles.push_back().reset(new SkTypeface_AndroidSystem(
@ -428,25 +431,24 @@ protected:
return new SkTypeface_AndroidStream(std::move(data), style, isFixedPitch, name); 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; using Scanner = SkTypeface_FreeType::Scanner;
std::unique_ptr<SkStreamAsset> stream(s); std::unique_ptr<SkStreamAsset> stream(s);
bool isFixedPitch; bool isFixedPitch;
SkFontStyle style; SkFontStyle style;
SkString name; SkString name;
Scanner::AxisDefinitions axisDefinitions; Scanner::AxisDefinitions axisDefinitions;
if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(), if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(),
&name, &style, &isFixedPitch, &axisDefinitions)) &name, &style, &isFixedPitch, &axisDefinitions))
{ {
return nullptr; return nullptr;
} }
int paramAxisCount;
const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); 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()); axisValues.get(), axisDefinitions.count());
return new SkTypeface_AndroidStream(std::move(data), style, isFixedPitch, name); return new SkTypeface_AndroidStream(std::move(data), style, isFixedPitch, name);
} }

View File

@ -167,8 +167,8 @@ static const TagHandler axisHandler = {
if (valueLen == 4) { if (valueLen == 4) {
axisTag = SkSetFourByteTag(value[0], value[1], value[2], value[3]); axisTag = SkSetFourByteTag(value[0], value[1], value[2], value[3]);
axisTagIsValid = true; axisTagIsValid = true;
for (int j = 0; j < file.fAxes.count() - 1; ++j) { for (int j = 0; j < file.fVariationDesignPosition.count() - 1; ++j) {
if (file.fAxes[j].fTag == axisTag) { if (file.fVariationDesignPosition[j].axis == axisTag) {
axisTagIsValid = false; axisTagIsValid = false;
SK_FONTCONFIGPARSER_WARNING("'%c%c%c%c' axis specified more than once", SK_FONTCONFIGPARSER_WARNING("'%c%c%c%c' axis specified more than once",
(axisTag >> 24) & 0xFF, (axisTag >> 24) & 0xFF,
@ -189,9 +189,9 @@ static const TagHandler axisHandler = {
} }
} }
if (axisTagIsValid && axisStyleValueIsValid) { if (axisTagIsValid && axisStyleValueIsValid) {
SkFontMgr::FontParameters::Axis& axis = file.fAxes.push_back(); auto& coordinate = file.fVariationDesignPosition.push_back();
axis.fTag = axisTag; coordinate.axis = axisTag;
axis.fStyleValue = SkFixedToScalar(axisStyleValue); coordinate.value = SkFixedToScalar(axisStyleValue);
} }
}, },
/*end*/nullptr, /*end*/nullptr,

View File

@ -73,7 +73,7 @@ struct FontFileInfo {
int fIndex; int fIndex;
int fWeight; int fWeight;
enum class Style { kAuto, kNormal, kItalic } fStyle; enum class Style { kAuto, kNormal, kItalic } fStyle;
SkTArray<SkFontMgr::FontParameters::Axis, true> fAxes; SkTArray<SkFontArguments::VariationPosition::Coordinate, true> fVariationDesignPosition;
}; };
/** /**

View File

@ -5,6 +5,7 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "SkFontArguments.h"
#include "SkFontDescriptor.h" #include "SkFontDescriptor.h"
#include "SkFontHost_FreeType_common.h" #include "SkFontHost_FreeType_common.h"
#include "SkFontMgr.h" #include "SkFontMgr.h"
@ -200,7 +201,7 @@ SkTypeface* SkFontMgr_Custom::onCreateFromStream(SkStreamAsset* bareStream, int
} }
SkTypeface* SkFontMgr_Custom::onCreateFromStream(SkStreamAsset* s, SkTypeface* SkFontMgr_Custom::onCreateFromStream(SkStreamAsset* s,
const FontParameters& params) const const SkFontArguments& args) const
{ {
using Scanner = SkTypeface_FreeType::Scanner; using Scanner = SkTypeface_FreeType::Scanner;
std::unique_ptr<SkStreamAsset> stream(s); std::unique_ptr<SkStreamAsset> stream(s);
@ -208,19 +209,18 @@ SkTypeface* SkFontMgr_Custom::onCreateFromStream(SkStreamAsset* s,
SkFontStyle style; SkFontStyle style;
SkString name; SkString name;
Scanner::AxisDefinitions axisDefinitions; Scanner::AxisDefinitions axisDefinitions;
if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(), if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(),
&name, &style, &isFixedPitch, &axisDefinitions)) &name, &style, &isFixedPitch, &axisDefinitions))
{ {
return nullptr; return nullptr;
} }
int paramAxisCount; const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); 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(), auto data = skstd::make_unique<SkFontData>(std::move(stream), args.getCollectionIndex(),
axisValues.get(), axisDefinitions.count()); axisValues.get(), axisDefinitions.count());
return new SkTypeface_Stream(std::move(data), style, isFixedPitch, false, name); return new SkTypeface_Stream(std::move(data), style, isFixedPitch, false, name);
} }

View File

@ -144,7 +144,7 @@ protected:
const SkFontStyle& fontStyle) const override; const SkFontStyle& fontStyle) const override;
SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override; SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override;
SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, 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* onCreateFromFontData(std::unique_ptr<SkFontData> data) const override;
SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override; SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override;
SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override; SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override;

View File

@ -899,25 +899,24 @@ protected:
return new SkTypeface_stream(std::move(data), std::move(name), style, isFixedWidth); 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; using Scanner = SkTypeface_FreeType::Scanner;
std::unique_ptr<SkStreamAsset> stream(s); std::unique_ptr<SkStreamAsset> stream(s);
bool isFixedPitch; bool isFixedPitch;
SkFontStyle style; SkFontStyle style;
SkString name; SkString name;
Scanner::AxisDefinitions axisDefinitions; Scanner::AxisDefinitions axisDefinitions;
if (!fScanner.scanFont(stream.get(), params.getCollectionIndex(), if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(),
&name, &style, &isFixedPitch, &axisDefinitions)) &name, &style, &isFixedPitch, &axisDefinitions))
{ {
return nullptr; return nullptr;
} }
int paramAxisCount;
const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); 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()); axisValues.get(), axisDefinitions.count());
return new SkTypeface_stream(std::move(data), std::move(name), style, isFixedPitch); return new SkTypeface_stream(std::move(data), std::move(name), style, isFixedPitch);
} }

View File

@ -104,15 +104,19 @@ protected:
SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
PerGlyphInfo, const uint32_t*, uint32_t) const override; PerGlyphInfo, const uint32_t*, uint32_t) const override;
void onGetFontDescriptor(SkFontDescriptor*, bool*) const override; void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
virtual int onCharsToGlyphs(const void* chars, Encoding encoding, int onCharsToGlyphs(const void* chars, Encoding encoding,
uint16_t glyphs[], int glyphCount) const override; uint16_t glyphs[], int glyphCount) const override;
int onCountGlyphs() const override; int onCountGlyphs() const override;
int onGetUPEM() const override; int onGetUPEM() const override;
void onGetFamilyName(SkString* familyName) const override; void onGetFamilyName(SkString* familyName) const override;
SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() 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; int onGetTableTags(SkFontTableTag tags[]) const override;
virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
size_t length, void* data) const override;
private: private:
typedef SkTypeface INHERITED; typedef SkTypeface INHERITED;

View File

@ -90,13 +90,13 @@ void DumpLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* label) {
for (int j = 0; j < fontFamilies[i]->fFonts.count(); ++j) { for (int j = 0; j < fontFamilies[i]->fFonts.count(); ++j) {
const FontFileInfo& ffi = fontFamilies[i]->fFonts[j]; const FontFileInfo& ffi = fontFamilies[i]->fFonts[j];
SkDebugf(" file (%d) %s#%d", ffi.fWeight, ffi.fFileName.c_str(), ffi.fIndex); 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", SkDebugf(" @'%c%c%c%c'=%f",
(axis.fTag >> 24) & 0xFF, (coordinate.axis >> 24) & 0xFF,
(axis.fTag >> 16) & 0xFF, (coordinate.axis >> 16) & 0xFF,
(axis.fTag >> 8) & 0xFF, (coordinate.axis >> 8) & 0xFF,
(axis.fTag ) & 0xFF, (coordinate.axis ) & 0xFF,
axis.fStyleValue); coordinate.value);
} }
SkDebugf("\n"); SkDebugf("\n");
} }

View File

@ -150,6 +150,12 @@ static void test_matchStyleCSS3(skiatest::Reporter* reporter) {
SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override { SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override {
return new EmptyLocalizedStrings; return new EmptyLocalizedStrings;
} }
int onGetVariationDesignPosition(
SkFontArguments::VariationPosition::Coordinate coordinates[],
int coordinateCount) const override
{
return 0;
}
int onGetTableTags(SkFontTableTag tags[]) const override { return 0; } int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override {
return 0; return 0;

View File

@ -6,6 +6,9 @@
*/ */
#include "SkData.h" #include "SkData.h"
#include "SkFixed.h"
#include "SkFontMgr.h"
#include "SkMakeUnique.h"
#include "SkOTTable_OS_2.h" #include "SkOTTable_OS_2.h"
#include "SkSFNTHeader.h" #include "SkSFNTHeader.h"
#include "SkStream.h" #include "SkStream.h"
@ -87,6 +90,77 @@ 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;
// The first named variation position in Distortable is 'Thin'.
params.setCollectionIndex(0x00010000);
sk_sp<SkTypeface> typeface(fm->createFromStream(distortable.release(), params));
if (!typeface) {
// FreeType is the only weird thing that supports this, Skia just needs to make sure if it
// gets one of these things make sense.
return;
}
int count = typeface->getVariationDesignPosition(nullptr, 0);
if (!(count == 1)) {
REPORT_FAILURE(reporter, "count == 1", SkString());
return;
}
SkFontArguments::VariationPosition::Coordinate positionRead[1];
count = typeface->getVariationDesignPosition(positionRead, SK_ARRAY_COUNT(positionRead));
if (count == -1) {
return;
}
if (!(count == 1)) {
REPORT_FAILURE(reporter, "count == 1", SkString());
return;
}
REPORTER_ASSERT(reporter, positionRead[0].axis == SkSetFourByteTag('w','g','h','t'));
REPORTER_ASSERT(reporter, positionRead[0].value == 0.5);
}
DEF_TEST(Typeface, reporter) { DEF_TEST(Typeface, reporter) {
sk_sp<SkTypeface> t1(SkTypeface::MakeFromName(nullptr, SkFontStyle())); sk_sp<SkTypeface> t1(SkTypeface::MakeFromName(nullptr, SkFontStyle()));
@ -134,6 +208,11 @@ protected:
SK_ABORT("unimplemented"); SK_ABORT("unimplemented");
return nullptr; return nullptr;
} }
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
int coordinateCount) const override
{
return 0;
}
int onGetTableTags(SkFontTableTag tags[]) 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; } size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; }
}; };

View File

@ -17,6 +17,7 @@ if (skia_use_system_freetype2) {
} }
} else { } else {
third_party("freetype2") { 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" ] public_include_dirs = [ "../externals/freetype/include" ]
deps = [ deps = [