aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/fontscalerdistortable.cpp9
-rw-r--r--include/ports/SkFontMgr.h51
-rw-r--r--src/core/SkFontMgr.cpp12
-rw-r--r--src/ports/SkFontHost_FreeType.cpp54
-rw-r--r--src/ports/SkFontHost_FreeType_common.h8
-rw-r--r--src/ports/SkFontHost_mac.cpp139
-rw-r--r--src/ports/SkFontMgr_android.cpp63
-rw-r--r--src/ports/SkFontMgr_fontconfig.cpp23
8 files changed, 334 insertions, 25 deletions
diff --git a/gm/fontscalerdistortable.cpp b/gm/fontscalerdistortable.cpp
index a207f967fd..f83365bb3e 100644
--- a/gm/fontscalerdistortable.cpp
+++ b/gm/fontscalerdistortable.cpp
@@ -41,6 +41,7 @@ protected:
SkPaint paint;
paint.setAntiAlias(true);
paint.setLCDRenderText(true);
+ SkAutoTUnref<SkFontMgr> fontMgr(SkFontMgr::RefDefault());
SkAutoTDelete<SkStreamAsset> distortable(GetResourceAsStream("/fonts/Distortable.ttf"));
if (!distortable) {
@@ -54,9 +55,11 @@ protected:
SkScalar x = SkIntToScalar(10);
SkScalar y = SkIntToScalar(20);
- SkFixed axis = SkDoubleToFixed(0.5 + (5*j + i) * ((2.0 - 0.5) / (2 * 5)));
- SkAutoTUnref<SkTypeface> typeface(SkTypeface::CreateFromFontData(
- new SkFontData(distortable->duplicate(), 0, &axis, 1)));
+ SkFourByteTag tag = SkSetFourByteTag('w','g','h','t');
+ SkScalar styleValue = SkDoubleToScalar(0.5 + (5*j + i) * ((2.0 - 0.5) / (2 * 5)));
+ SkFontMgr::FontParameters::Axis axes[] = { { tag, styleValue } };
+ SkAutoTUnref<SkTypeface> typeface(fontMgr->createFromStream(
+ distortable->duplicate(), SkFontMgr::FontParameters().setAxes(axes, 1)));
paint.setTypeface(typeface);
SkAutoCanvasRestore acr(canvas, true);
diff --git a/include/ports/SkFontMgr.h b/include/ports/SkFontMgr.h
index 96a8501c48..3e6c785be9 100644
--- a/include/ports/SkFontMgr.h
+++ b/include/ports/SkFontMgr.h
@@ -8,8 +8,10 @@
#ifndef SkFontMgr_DEFINED
#define SkFontMgr_DEFINED
-#include "SkRefCnt.h"
#include "SkFontStyle.h"
+#include "SkRefCnt.h"
+#include "SkScalar.h"
+#include "SkTypes.h"
class SkData;
class SkFontData;
@@ -100,6 +102,52 @@ public:
*/
SkTypeface* createFromStream(SkStreamAsset*, int ttcIndex = 0) const;
+ struct FontParameters {
+ struct Axis {
+ SkFourByteTag fTag;
+ SkScalar fStyleValue;
+ };
+
+ FontParameters() : fCollectionIndex(0), fAxisCount(0), fAxes(nullptr) {}
+
+ /** Specify the index of the desired font.
+ *
+ * Font formats like ttc, dfont, cff, cid, pfr, t42, t1, and fon may actually be indexed
+ * collections of fonts.
+ */
+ FontParameters& setCollectionIndex(int collectionIndex) {
+ fCollectionIndex = collectionIndex;
+ return *this;
+ }
+
+ /** Specify the GX variation axis values.
+ *
+ * Any axes not specified will use the default value. Specified axes not present in the
+ * font will be ignored.
+ *
+ * @param axes not copied. This pointer must remain valid for life of FontParameters.
+ */
+ FontParameters& setAxes(const Axis* axes, int axisCount) {
+ fAxisCount = axisCount;
+ fAxes = axes;
+ return *this;
+ }
+
+ int getCollectionIndex() const {
+ return fCollectionIndex;
+ }
+ const Axis* getAxes(int* axisCount) const {
+ *axisCount = fAxisCount;
+ return fAxes;
+ }
+ private:
+ int fCollectionIndex;
+ int fAxisCount;
+ const Axis* fAxes;
+ };
+ /* Experimental, API subject to change. */
+ SkTypeface* createFromStream(SkStreamAsset*, const FontParameters&) const;
+
/**
* Create a typeface from the specified font data.
* Takes ownership of the font data, so the caller should not reference it again.
@@ -144,6 +192,7 @@ protected:
virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) const = 0;
virtual SkTypeface* onCreateFromStream(SkStreamAsset*, int ttcIndex) const = 0;
// TODO: make pure virtual.
+ virtual SkTypeface* onCreateFromStream(SkStreamAsset*, const FontParameters&) const;
virtual SkTypeface* onCreateFromFontData(SkFontData*) const;
virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const = 0;
diff --git a/src/core/SkFontMgr.cpp b/src/core/SkFontMgr.cpp
index 5246916463..ab04250c03 100644
--- a/src/core/SkFontMgr.cpp
+++ b/src/core/SkFontMgr.cpp
@@ -132,6 +132,13 @@ SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, int ttcIndex) con
return this->onCreateFromStream(stream, ttcIndex);
}
+SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, const FontParameters& params) const {
+ if (nullptr == stream) {
+ return nullptr;
+ }
+ return this->onCreateFromStream(stream, params);
+}
+
SkTypeface* SkFontMgr::createFromFontData(SkFontData* data) const {
if (nullptr == data) {
return nullptr;
@@ -140,6 +147,11 @@ SkTypeface* SkFontMgr::createFromFontData(SkFontData* data) const {
}
// This implementation is temporary until it can be made pure virtual.
+SkTypeface* SkFontMgr::onCreateFromStream(SkStreamAsset* stream, const FontParameters& p) const {
+ return this->createFromStream(stream, p.getCollectionIndex());
+}
+
+// This implementation is temporary until it can be made pure virtual.
SkTypeface* SkFontMgr::onCreateFromFontData(SkFontData* data) const {
SkTypeface* ret = this->createFromStream(data->detachStream(), data->getIndex());
delete data;
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index e8b72b5e09..ffac0ca974 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -1741,3 +1741,57 @@ bool SkTypeface_FreeType::Scanner::scanFont(
FT_Done_Face(face);
return true;
}
+
+/*static*/ void SkTypeface_FreeType::Scanner::computeAxisValues(
+ AxisDefinitions axisDefinitions,
+ const SkFontMgr::FontParameters::Axis* requestedAxes, int requestedAxisCount,
+ SkFixed* axisValues,
+ const SkString& name)
+{
+ for (int i = 0; i < axisDefinitions.count(); ++i) {
+ const Scanner::AxisDefinition& axisDefinition = axisDefinitions[i];
+ axisValues[i] = axisDefinition.fDefault;
+ for (int j = 0; j < requestedAxisCount; ++j) {
+ const SkFontMgr::FontParameters::Axis& axisSpecified = requestedAxes[j];
+ if (axisDefinition.fTag == axisSpecified.fTag) {
+ SkFixed axisValue = SkScalarToFixed(axisSpecified.fStyleValue);
+ axisValues[i] = SkTPin(axisValue, axisDefinition.fMinimum, axisDefinition.fMaximum);
+ if (axisValues[i] != axisValue) {
+ SkDEBUGF(("Requested font axis value out of range: "
+ "%s '%c%c%c%c' %f; pinned to %f.\n",
+ name.c_str(),
+ (axisDefinition.fTag >> 24) & 0xFF,
+ (axisDefinition.fTag >> 16) & 0xFF,
+ (axisDefinition.fTag >> 8) & 0xFF,
+ (axisDefinition.fTag ) & 0xFF,
+ SkScalarToDouble(axisSpecified.fStyleValue),
+ SkFixedToDouble(axisValues[i])));
+ }
+ break;
+ }
+ }
+ // TODO: warn on defaulted axis?
+ }
+
+ SkDEBUGCODE(
+ // Check for axis specified, but not matched in font.
+ for (int i = 0; i < requestedAxisCount; ++i) {
+ SkFourByteTag skTag = requestedAxes[i].fTag;
+ bool found = false;
+ for (int j = 0; j < axisDefinitions.count(); ++j) {
+ if (skTag == axisDefinitions[j].fTag) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ SkDEBUGF(("Requested font axis not found: %s '%c%c%c%c'\n",
+ name.c_str(),
+ (skTag >> 24) & 0xFF,
+ (skTag >> 16) & 0xFF,
+ (skTag >> 8) & 0xFF,
+ (skTag) & 0xFF));
+ }
+ }
+ )
+}
diff --git a/src/ports/SkFontHost_FreeType_common.h b/src/ports/SkFontHost_FreeType_common.h
index a9ca42b35f..99b43dccca 100644
--- a/src/ports/SkFontHost_FreeType_common.h
+++ b/src/ports/SkFontHost_FreeType_common.h
@@ -15,6 +15,8 @@
#include "SkTypeface.h"
#include "SkTypes.h"
+#include "SkFontMgr.h"
+
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -55,6 +57,12 @@ public:
bool scanFont(SkStream* stream, int ttcIndex,
SkString* name, SkFontStyle* style, bool* isFixedPitch,
AxisDefinitions* axes) const;
+ static void computeAxisValues(
+ AxisDefinitions axisDefinitions,
+ const SkFontMgr::FontParameters::Axis* requestedAxis, int requestedAxisCount,
+ SkFixed* axisValues,
+ const SkString& name);
+
private:
FT_Face openFace(SkStream* stream, int ttcIndex, FT_Stream ftStream) const;
FT_Library fLibrary;
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp
index 1d68c433bf..c4e80b67c0 100644
--- a/src/ports/SkFontHost_mac.cpp
+++ b/src/ports/SkFontHost_mac.cpp
@@ -2371,6 +2371,145 @@ protected:
return create_from_dataProvider(pr);
}
+ static CFNumberRef get_tag_for_name(CFStringRef name, CFArrayRef ctAxes) {
+ CFIndex ctAxisCount = CFArrayGetCount(ctAxes);
+ for (int i = 0; i < ctAxisCount; ++i) {
+ CFTypeRef ctAxisInfo = CFArrayGetValueAtIndex(ctAxes, i);
+ if (CFDictionaryGetTypeID() != CFGetTypeID(ctAxisInfo)) {
+ return nullptr;
+ }
+ CFDictionaryRef ctAxisInfoDict = static_cast<CFDictionaryRef>(ctAxisInfo);
+
+ CFTypeRef ctAxisName = CFDictionaryGetValue(ctAxisInfoDict,
+ kCTFontVariationAxisNameKey);
+ if (!ctAxisName || CFGetTypeID(ctAxisName) != CFStringGetTypeID()) {
+ return nullptr;
+ }
+
+ if (CFEqual(name, ctAxisName)) {
+ CFTypeRef tag = CFDictionaryGetValue(ctAxisInfoDict,
+ kCTFontVariationAxisIdentifierKey);
+ if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
+ return nullptr;
+ }
+ return static_cast<CFNumberRef>(tag);
+ }
+ }
+ return nullptr;
+ }
+ static CFDictionaryRef get_axes(CGFontRef cg, const FontParameters& params) {
+ AutoCFRelease<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
+ if (!cgAxes) {
+ return nullptr;
+ }
+ CFIndex axisCount = CFArrayGetCount(cgAxes);
+
+ // 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.
+ // We would like to work with CTFont variaitons, but creating a CTFont font with
+ // CTFont variation dictionary runs into bugs. So use the CTFont variation data
+ // to match names to tags to create the appropriate CGFont.
+ AutoCFRelease<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr));
+ AutoCFRelease<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct));
+ if (!ctAxes || CFArrayGetCount(ctAxes) != axisCount) {
+ return nullptr;
+ }
+
+ int paramAxisCount;
+ const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
+
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ for (int i = 0; i < axisCount; ++i) {
+ CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes, i);
+ if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
+ return nullptr;
+ }
+ CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
+
+ CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName);
+ if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
+ return nullptr;
+ }
+
+ CFNumberRef tagNumber = get_tag_for_name(static_cast<CFStringRef>(axisName), ctAxes);
+ if (!tagNumber) {
+ // Could not find a tag to go with the name of this index.
+ // This would be a bug in CG/CT.
+ continue;
+ }
+ int64_t tagLong;
+ if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
+ return nullptr;
+ }
+
+ // The variation axes can be set to any value, but cg will effectively pin them.
+ // Pin them here to normalize.
+ CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue);
+ CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue);
+ CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisDefaultValue);
+ if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
+ !max || CFGetTypeID(max) != CFNumberGetTypeID() ||
+ !def || CFGetTypeID(def) != CFNumberGetTypeID())
+ {
+ return nullptr;
+ }
+ CFNumberRef minNumber = static_cast<CFNumberRef>(min);
+ CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
+ CFNumberRef defNumber = static_cast<CFNumberRef>(def);
+ double minDouble;
+ double maxDouble;
+ double defDouble;
+ if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) ||
+ !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) ||
+ !CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble))
+ {
+ return nullptr;
+ }
+
+ double value = defDouble;
+ for (int j = 0; j < paramAxisCount; ++j) {
+ if (paramAxes[j].fTag == tagLong) {
+ value = SkTPin(SkScalarToDouble(paramAxes[j].fStyleValue),minDouble,maxDouble);
+ break;
+ }
+ }
+ CFNumberRef valueNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType,
+ &value);
+ CFDictionaryAddValue(dict, axisName, valueNumber);
+ CFRelease(valueNumber);
+ }
+ return dict;
+ }
+ SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override {
+ AutoCFRelease<CGDataProviderRef> provider(SkCreateDataProviderFromStream(s));
+ if (nullptr == provider) {
+ return nullptr;
+ }
+ AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider));
+ if (nullptr == cg) {
+ return nullptr;
+ }
+
+ AutoCFRelease<CFDictionaryRef> cgVariations(get_axes(cg, params));
+ // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
+ // created from a data provider does not appear to have any ownership of the underlying
+ // data. The original CGFontRef must be kept alive until the copy will no longer be used.
+ AutoCFRelease<CGFontRef> cgVariant;
+ if (cgVariations) {
+ cgVariant.reset(CGFontCreateCopyWithVariations(cg, cgVariations));
+ } else {
+ cgVariant.reset(cg.detach());
+ }
+
+ CTFontRef ct = CTFontCreateWithGraphicsFont(cgVariant, 0, nullptr, nullptr);
+ if (!ct) {
+ return nullptr;
+ }
+ return NewFromFontRef(ct, cg.detach(), nullptr, true);
+ }
+
static CFDictionaryRef get_axes(CGFontRef cg, SkFontData* fontData) {
AutoCFRelease<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
if (!cgAxes) {
diff --git a/src/ports/SkFontMgr_android.cpp b/src/ports/SkFontMgr_android.cpp
index 11244c55ee..afa7873454 100644
--- a/src/ports/SkFontMgr_android.cpp
+++ b/src/ports/SkFontMgr_android.cpp
@@ -6,7 +6,6 @@
*/
#include "SkTypes.h"
-#if defined(SK_BUILD_FOR_ANDROID)
#include "SkFixed.h"
#include "SkFontDescriptor.h"
@@ -208,26 +207,27 @@ public:
}
SkDEBUGCODE(
- // Check for axis specified, but not matched in font.
- for (int i = 0; i < fontFile.fAxes.count(); ++i) {
- SkFourByteTag skTag = fontFile.fAxes[i].fTag;
- bool found = false;
- for (int j = 0; j < axisDefinitions.count(); ++j) {
- if (skTag == axisDefinitions[j].fTag) {
- found = true;
- break;
- }
+ // Check for axis specified, but not matched in font.
+ for (int i = 0; i < fontFile.fAxes.count(); ++i) {
+ SkFourByteTag skTag = fontFile.fAxes[i].fTag;
+ bool found = false;
+ for (int j = 0; j < axisDefinitions.count(); ++j) {
+ if (skTag == axisDefinitions[j].fTag) {
+ found = true;
+ break;
}
- if (!found) {
- SkDEBUGF(("Requested font axis not found: %s '%c%c%c%c'\n",
- familyName.c_str(), (skTag >> 24) & 0xFF,
- (skTag >> 16) & 0xFF, (skTag >> 8) & 0xFF, (skTag)&0xFF));
- }
- })
+ }
+ if (!found) {
+ SkDEBUGF(("Requested font axis not found: %s '%c%c%c%c'\n",
+ familyName.c_str(), (skTag >> 24) & 0xFF,
+ (skTag >> 16) & 0xFF, (skTag >> 8) & 0xFF, (skTag)&0xFF));
+ }
+ }
+ )
- fStyles.push_back().reset(new SkTypeface_AndroidSystem(
- pathName, ttcIndex, axisValues.get(), axisDefinitions.count(), style,
- isFixedWidth, familyName, lang, variant));
+ fStyles.push_back().reset(new SkTypeface_AndroidSystem(
+ pathName, ttcIndex, axisValues.get(), axisDefinitions.count(), style,
+ isFixedWidth, familyName, lang, variant));
}
}
@@ -476,6 +476,29 @@ protected:
return new SkTypeface_AndroidStream(data, style, isFixedPitch, name);
}
+ SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override {
+ using Scanner = SkTypeface_FreeType::Scanner;
+ SkAutoTDelete<SkStreamAsset> stream(s);
+ bool isFixedPitch;
+ SkFontStyle style;
+ SkString name;
+ Scanner::AxisDefinitions axisDefinitions;
+ if (!fScanner.scanFont(stream, params.getCollectionIndex(), &name, &style, &isFixedPitch,
+ &axisDefinitions))
+ {
+ return nullptr;
+ }
+
+ int paramAxisCount;
+ const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
+ SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
+ Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name);
+
+ SkFontData* data(new SkFontData(stream.detach(), params.getCollectionIndex(),
+ axisValues.get(), axisDefinitions.count()));
+ return new SkTypeface_AndroidStream(data, style, isFixedPitch, name);
+ }
+
SkTypeface* onCreateFromFontData(SkFontData* data) const override {
SkStreamAsset* stream(data->getStream());
bool isFixedPitch;
@@ -589,5 +612,3 @@ SkFontMgr* SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom) {
return new SkFontMgr_Android(custom);
}
-
-#endif//defined(SK_BUILD_FOR_ANDROID)
diff --git a/src/ports/SkFontMgr_fontconfig.cpp b/src/ports/SkFontMgr_fontconfig.cpp
index 88d4de5929..6a40e5080d 100644
--- a/src/ports/SkFontMgr_fontconfig.cpp
+++ b/src/ports/SkFontMgr_fontconfig.cpp
@@ -834,6 +834,29 @@ protected:
isFixedWidth);
}
+ SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override {
+ using Scanner = SkTypeface_FreeType::Scanner;
+ SkAutoTDelete<SkStreamAsset> stream(s);
+ bool isFixedPitch;
+ SkFontStyle style;
+ SkString name;
+ Scanner::AxisDefinitions axisDefinitions;
+ if (!fScanner.scanFont(stream, params.getCollectionIndex(), &name, &style, &isFixedPitch,
+ &axisDefinitions))
+ {
+ return nullptr;
+ }
+
+ int paramAxisCount;
+ const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
+ SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
+ Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name);
+
+ SkFontData* data(new SkFontData(stream.detach(), params.getCollectionIndex(),
+ axisValues.get(), axisDefinitions.count()));
+ return new SkTypeface_stream(data, style, isFixedPitch);
+ }
+
SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
return this->createFromStream(new SkMemoryStream(data), ttcIndex);
}