Cache result of CTFontCopyVariationAxes.

CTFontCopyVariationAxes appears to be extremely slow due to localizing
the name of the axis. WebKit moved to using the internal SPI
CTFontCopyVariationAxesInternal to avoid this cost. Since Skia would
like to avoid using internal SPI, just cache this information per
typeface to avoid the cost of calling it as often.

Bug: https://github.com/flutter/flutter/issues/100523
Bug: https://bugs.webkit.org/show_bug.cgi?id=232690
Change-Id: I175e34e9aa526d58e6b7a4ff54cb13d1ef8a9fd9
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/524760
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
Ben Wagner 2022-03-25 15:22:00 -04:00 committed by SkCQ
parent 55ec347276
commit e85afc2b18
4 changed files with 39 additions and 17 deletions

View File

@ -563,7 +563,8 @@ protected:
return nullptr; return nullptr;
} }
CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(ct.get(), args); SkUniqueCFRef<CFArrayRef> axes(CTFontCopyVariationAxes(ct.get()));
CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(ct.get(), axes.get(), args);
SkUniqueCFRef<CTFontRef> ctVariant; SkUniqueCFRef<CTFontRef> ctVariant;
if (ctVariation.variation) { if (ctVariation.variation) {

View File

@ -718,8 +718,8 @@ void SkScalerContext_Mac::generateFontMetrics(SkFontMetrics* metrics) {
metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag; metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag; metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fCTFont.get())); CFArrayRef ctAxes = ((SkTypeface_Mac*)this->getTypeface())->getVariationAxes();
if (ctAxes && CFArrayGetCount(ctAxes.get()) > 0) { if (ctAxes && CFArrayGetCount(ctAxes) > 0) {
// The bounds are only valid for the default variation. // The bounds are only valid for the default variation.
metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag; metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag;
} }

View File

@ -566,8 +566,8 @@ std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics(
} }
} }
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ctFont.get())); CFArrayRef ctAxes = this->getVariationAxes();
if (ctAxes && CFArrayGetCount(ctAxes.get()) > 0) { if (ctAxes && CFArrayGetCount(ctAxes) > 0) {
info->fFlags |= SkAdvancedTypefaceMetrics::kVariable_FontFlag; info->fFlags |= SkAdvancedTypefaceMetrics::kVariable_FontFlag;
} }
@ -787,14 +787,21 @@ bool SkTypeface_Mac::onGlyphMaskNeedsCurrentColor() const {
return this->fHasColorGlyphs; return this->fHasColorGlyphs;
} }
CFArrayRef SkTypeface_Mac::getVariationAxes() const {
fInitVariationAxes([this]{
fVariationAxes.reset(CTFontCopyVariationAxes(fFontRef.get()));
});
return fVariationAxes.get();
}
int SkTypeface_Mac::onGetVariationDesignPosition( int SkTypeface_Mac::onGetVariationDesignPosition(
SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
{ {
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get())); CFArrayRef ctAxes = this->getVariationAxes();
if (!ctAxes) { if (!ctAxes) {
return -1; return -1;
} }
CFIndex axisCount = CFArrayGetCount(ctAxes.get()); CFIndex axisCount = CFArrayGetCount(ctAxes);
if (!coordinates || coordinateCount < axisCount) { if (!coordinates || coordinateCount < axisCount) {
return axisCount; return axisCount;
} }
@ -807,7 +814,7 @@ int SkTypeface_Mac::onGetVariationDesignPosition(
for (int i = 0; i < axisCount; ++i) { for (int i = 0; i < axisCount; ++i) {
CFDictionaryRef axisInfoDict; CFDictionaryRef axisInfoDict;
if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes.get(), i), &axisInfoDict, "Axis")) { if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict, "Axis")) {
return -1; return -1;
} }
@ -1119,15 +1126,15 @@ int SkTypeface_Mac::onCountGlyphs() const {
} }
/** Creates a dictionary suitable for setting the axes on a CTFont. */ /** Creates a dictionary suitable for setting the axes on a CTFont. */
CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, const SkFontArguments& args) { CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, CFArrayRef ctAxes,
const SkFontArguments& args) {
OpszVariation opsz; OpszVariation opsz;
constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z'); constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z');
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct));
if (!ctAxes) { if (!ctAxes) {
return CTFontVariation(); return CTFontVariation();
} }
CFIndex axisCount = CFArrayGetCount(ctAxes.get()); CFIndex axisCount = CFArrayGetCount(ctAxes);
// On 10.12 and later, this only returns non-default variations. // On 10.12 and later, this only returns non-default variations.
SkUniqueCFRef<CFDictionaryRef> oldCtVariation(CTFontCopyVariation(ct)); SkUniqueCFRef<CFDictionaryRef> oldCtVariation(CTFontCopyVariation(ct));
@ -1142,7 +1149,7 @@ CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, const SkFontArgum
for (int i = 0; i < axisCount; ++i) { for (int i = 0; i < axisCount; ++i) {
CFDictionaryRef axisInfoDict; CFDictionaryRef axisInfoDict;
if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes.get(), i), &axisInfoDict, "Axis")) { if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict, "Axis")) {
return CTFontVariation(); return CTFontVariation();
} }
@ -1224,7 +1231,9 @@ CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, const SkFontArgum
} }
sk_sp<SkTypeface> SkTypeface_Mac::onMakeClone(const SkFontArguments& args) const { sk_sp<SkTypeface> SkTypeface_Mac::onMakeClone(const SkFontArguments& args) const {
CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(fFontRef.get(), args); CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(fFontRef.get(),
this->getVariationAxes(),
args);
SkUniqueCFRef<CTFontRef> ctVariant; SkUniqueCFRef<CTFontRef> ctVariant;
if (ctVariation.variation) { if (ctVariation.variation) {
@ -1273,11 +1282,11 @@ sk_sp<SkTypeface> SkTypeface_Mac::onMakeClone(const SkFontArguments& args) const
int SkTypeface_Mac::onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], int SkTypeface_Mac::onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
int parameterCount) const int parameterCount) const
{ {
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get())); CFArrayRef ctAxes = this->getVariationAxes();
if (!ctAxes) { if (!ctAxes) {
return -1; return -1;
} }
CFIndex axisCount = CFArrayGetCount(ctAxes.get()); CFIndex axisCount = CFArrayGetCount(ctAxes);
if (!parameters || parameterCount < axisCount) { if (!parameters || parameterCount < axisCount) {
return axisCount; return axisCount;
@ -1289,7 +1298,7 @@ int SkTypeface_Mac::onGetVariationDesignParameters(SkFontParameters::Variation::
for (int i = 0; i < axisCount; ++i) { for (int i = 0; i < axisCount; ++i) {
CFDictionaryRef axisInfoDict; CFDictionaryRef axisInfoDict;
if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes.get(), i), &axisInfoDict, "Axis")) { if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict, "Axis")) {
return -1; return -1;
} }

View File

@ -55,7 +55,8 @@ struct CTFontVariation {
OpszVariation opsz; OpszVariation opsz;
}; };
CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, const SkFontArguments& args); CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, CFArrayRef ctAxes,
const SkFontArguments& args);
SkUniqueCFRef<CTFontRef> SkCTFontCreateExactCopy(CTFontRef baseFont, CGFloat textSize, SkUniqueCFRef<CTFontRef> SkCTFontCreateExactCopy(CTFontRef baseFont, CGFloat textSize,
OpszVariation opsz); OpszVariation opsz);
@ -91,6 +92,15 @@ public:
const OpszVariation fOpszVariation; const OpszVariation fOpszVariation;
const bool fHasColorGlyphs; const bool fHasColorGlyphs;
/**
* CTFontCopyVariationAxes provides the localized name of all axes, making it very slow.
* This is unfortunate, its result is needed just to see if there are any axes at all.
* To avoid calling internal APIs cache the result of CTFontCopyVariationAxes.
* https://github.com/WebKit/WebKit/commit/1842365d413ed87868e7d33d4fad1691fa3a8129
* https://bugs.webkit.org/show_bug.cgi?id=232690
*/
CFArrayRef getVariationAxes() const;
protected: protected:
int onGetUPEM() const override; int onGetUPEM() const override;
std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override; std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override;
@ -121,8 +131,10 @@ protected:
private: private:
mutable std::unique_ptr<SkStreamAsset> fStream; mutable std::unique_ptr<SkStreamAsset> fStream;
mutable SkUniqueCFRef<CFArrayRef> fVariationAxes;
bool fIsFromStream; bool fIsFromStream;
mutable SkOnce fInitStream; mutable SkOnce fInitStream;
mutable SkOnce fInitVariationAxes;
using INHERITED = SkTypeface; using INHERITED = SkTypeface;
}; };