Work around macOS 11 variation issue.

On macOS 11 cloning a system font with an opsz axis and not changing the
value of the opsz axis (either by setting it to the same value or not
specifying it at all) when setting a variation causes the variation to
be set but the cloned font will still compare CFEqual to the original
font. Work around this by setting the opsz to something which isn't the
desired value before setting the entire desired variation.

This may also incidentally improve the situation for fonts created from
data on macOS 10.15, since a similar issue occurs and the same work
around seems to apply.

Bug: skia:10968
Change-Id: I2240f905644b753e2389446d248c27b1e62cdcd1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/370917
Reviewed-by: Herb Derby <herb@google.com>
Reviewed-by: Dominik Röttsches <drott@chromium.org>
Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
Ben Wagner 2021-02-16 17:02:56 -05:00 committed by Skia Commit-Bot
parent 6e2dccb979
commit f11898aa0a
3 changed files with 62 additions and 18 deletions

View File

@ -267,7 +267,7 @@ static CTFontVariation ctvariation_from_skfontdata(CTFontRef ct, SkFontData* fon
CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
CFDictionaryAddValue(dict.get(), tagNumber, valueNumber.get());
}
return { SkUniqueCFRef<CFDictionaryRef>(std::move(dict)), opsz };
return { SkUniqueCFRef<CFDictionaryRef>(std::move(dict)), nullptr, opsz };
}
static sk_sp<SkData> skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream) {
@ -615,13 +615,13 @@ protected:
CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(ct.get(), args);
SkUniqueCFRef<CTFontRef> ctVariant;
if (ctVariation.dict) {
if (ctVariation.variation) {
SkUniqueCFRef<CFMutableDictionaryRef> attributes(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
CFDictionaryAddValue(attributes.get(),
kCTFontVariationAttribute, ctVariation.dict.get());
kCTFontVariationAttribute, ctVariation.variation.get());
SkUniqueCFRef<CTFontDescriptorRef> varDesc(
CTFontDescriptorCreateWithAttributes(attributes.get()));
ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get()));
@ -653,13 +653,13 @@ protected:
CTFontVariation ctVariation = ctvariation_from_skfontdata(ct.get(), fontData.get());
SkUniqueCFRef<CTFontRef> ctVariant;
if (ctVariation.dict) {
if (ctVariation.variation) {
SkUniqueCFRef<CFMutableDictionaryRef> attributes(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
CFDictionaryAddValue(attributes.get(),
kCTFontVariationAttribute, ctVariation.dict.get());
kCTFontVariationAttribute, ctVariation.variation.get());
SkUniqueCFRef<CTFontDescriptorRef> varDesc(
CTFontDescriptorCreateWithAttributes(attributes.get()));
ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get()));

View File

@ -1117,14 +1117,15 @@ CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, const SkFontArgum
CFIndex axisCount = CFArrayGetCount(ctAxes.get());
// On 10.12 and later, this only returns non-default variations.
SkUniqueCFRef<CFDictionaryRef> ctVariation(CTFontCopyVariation(ct));
SkUniqueCFRef<CFDictionaryRef> oldCtVariation(CTFontCopyVariation(ct));
const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
SkUniqueCFRef<CFMutableDictionaryRef> dict(
SkUniqueCFRef<CFMutableDictionaryRef> newCtVariation(
CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
SkUniqueCFRef<CFMutableDictionaryRef> wrongOpszVariation;
for (int i = 0; i < axisCount; ++i) {
CFDictionaryRef axisInfoDict;
@ -1158,12 +1159,16 @@ CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, const SkFontArgum
double value = defDouble;
// Then the current value.
if (ctVariation) {
CFTypeRef currentValue = CFDictionaryGetValue(ctVariation.get(), tagNumber);
if (currentValue) {
if (!SkCFNumberDynamicCast(currentValue, &value, nullptr, "Variation value")) {
bool haveCurrentDouble = false;
double currentDouble = 0;
if (oldCtVariation) {
CFTypeRef currentNumber = CFDictionaryGetValue(oldCtVariation.get(), tagNumber);
if (currentNumber) {
if (!SkCFNumberDynamicCast(currentNumber, &value, nullptr, "Variation value")) {
return CTFontVariation();
}
currentDouble = value;
haveCurrentDouble = true;
}
}
@ -1181,28 +1186,66 @@ CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, const SkFontArgum
}
if (tagLong == opszTag) {
opsz.value = value;
if (haveCurrentDouble && value == currentDouble) {
// Calculate a value strictly in range but different from currentValue.
double wrongOpszDouble = ((maxDouble - minDouble) / 2.0) + minDouble;
if (wrongOpszDouble == currentDouble) {
wrongOpszDouble = ((maxDouble - minDouble) / 4.0) + minDouble;
}
wrongOpszVariation.reset(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
SkUniqueCFRef<CFNumberRef> wrongOpszNumber(
CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &wrongOpszDouble));
CFDictionarySetValue(wrongOpszVariation.get(), tagNumber, wrongOpszNumber.get());
}
}
SkUniqueCFRef<CFNumberRef> valueNumber(
CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
CFDictionaryAddValue(dict.get(), tagNumber, valueNumber.get());
CFDictionaryAddValue(newCtVariation.get(), tagNumber, valueNumber.get());
}
return { SkUniqueCFRef<CFDictionaryRef>(std::move(dict)), opsz };
return { SkUniqueCFRef<CFDictionaryRef>(std::move(newCtVariation)),
SkUniqueCFRef<CFDictionaryRef>(std::move(wrongOpszVariation)),
opsz };
}
sk_sp<SkTypeface> SkTypeface_Mac::onMakeClone(const SkFontArguments& args) const {
CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(fFontRef.get(), args);
SkUniqueCFRef<CTFontRef> ctVariant;
if (ctVariation.dict) {
if (ctVariation.variation) {
SkUniqueCFRef<CFMutableDictionaryRef> attributes(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
CFDictionaryAddValue(attributes.get(),
kCTFontVariationAttribute, ctVariation.dict.get());
CTFontRef ctFont = fFontRef.get();
SkUniqueCFRef<CTFontRef> wrongOpszFont;
if (ctVariation.wrongOpszVariation) {
// On macOS 11 cloning a system font with an opsz axis and not changing the
// value of the opsz axis (either by setting it to the same value or not
// specifying it at all) when setting a variation causes the variation to
// be set but the cloned font will still compare CFEqual to the original
// font. Work around this by setting the opsz to something which isn't the
// desired value before setting the entire desired variation.
//
// A similar issue occurs with fonts from data on macOS 10.15 and the same
// work around seems to apply. This is less noticeable though since CFEqual
// isn't used on these fonts.
CFDictionarySetValue(attributes.get(),
kCTFontVariationAttribute, ctVariation.wrongOpszVariation.get());
SkUniqueCFRef<CTFontDescriptorRef> varDesc(
CTFontDescriptorCreateWithAttributes(attributes.get()));
wrongOpszFont.reset(CTFontCreateCopyWithAttributes(ctFont, 0, nullptr, varDesc.get()));
ctFont = wrongOpszFont.get();
}
CFDictionarySetValue(attributes.get(),
kCTFontVariationAttribute, ctVariation.variation.get());
SkUniqueCFRef<CTFontDescriptorRef> varDesc(
CTFontDescriptorCreateWithAttributes(attributes.get()));
ctVariant.reset(CTFontCreateCopyWithAttributes(fFontRef.get(), 0, nullptr, varDesc.get()));
ctVariant.reset(CTFontCreateCopyWithAttributes(ctFont, 0, nullptr, varDesc.get()));
} else {
ctVariant.reset((CTFontRef)CFRetain(fFontRef.get()));
}

View File

@ -50,7 +50,8 @@ struct OpszVariation {
};
struct CTFontVariation {
SkUniqueCFRef<CFDictionaryRef> dict;
SkUniqueCFRef<CFDictionaryRef> variation;
SkUniqueCFRef<CFDictionaryRef> wrongOpszVariation;
OpszVariation opsz;
};