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:
parent
9fe1b22249
commit
fc497343cb
9
BUILD.gn
9
BUILD.gn
@ -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",
|
||||||
]
|
]
|
||||||
|
@ -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));
|
||||||
|
@ -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",
|
||||||
|
79
include/core/SkFontArguments.h
Normal file
79
include/core/SkFontArguments.h
Normal 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
|
@ -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[],
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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(¶mAxisCount);
|
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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(¶mAxisCount);
|
|
||||||
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);
|
||||||
|
@ -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(¶mAxisCount);
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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(¶mAxisCount);
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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(¶mAxisCount);
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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; }
|
||||||
};
|
};
|
||||||
|
1
third_party/freetype2/BUILD.gn
vendored
1
third_party/freetype2/BUILD.gn
vendored
@ -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 = [
|
||||||
|
Loading…
Reference in New Issue
Block a user