Bug 1455569 - Handle variation settings of system-installed variation fonts when creating CTFont from CGFont on High Sierra. r=lsalzman

This commit is contained in:
Jonathan Kew 2018-04-20 17:18:03 +01:00
Родитель 21bd76217a
Коммит 4b2b2d4c9f
9 изменённых файлов: 152 добавлений и 46 удалений

Просмотреть файл

@ -75,7 +75,8 @@ bool ScaledFontMac::sSymbolLookupDone = false;
// Helper to create a CTFont from a CGFont, copying any variations that were
// set on the original CGFont.
static CTFontRef
CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize)
CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize,
bool aInstalledFont)
{
// Avoid calling potentially buggy variation APIs on pre-Sierra macOS
// versions (see bug 1331683).
@ -85,30 +86,50 @@ CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize)
// the extra work here -- and this seems to avoid Core Text crashiness
// seen in bug 1454094.
//
// So we only need to do this "the hard way" on Sierra; on other releases,
// just let the standard CTFont function do its thing.
if (!nsCocoaFeatures::OnSierraExactly()) {
return CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr, nullptr);
}
// However, for installed fonts it seems we DO need to copy the variations
// explicitly even on 10.13, otherwise fonts fail to render (as in bug
// 1455494) when non-default values are used. Fortunately, the crash
// mentioned above occurs with data fonts, not (AFAICT) with system-
// installed fonts.
//
// So we only need to do this "the hard way" on Sierra, and for installed
// fonts on HighSierra+; otherwise, just let the standard CTFont function
// do its thing.
//
// NOTE in case this ever needs further adjustment: there is similar logic
// in four places in the tree (sadly):
// CreateCTFontFromCGFontWithVariations in gfxMacFont.cpp
// CreateCTFontFromCGFontWithVariations in ScaledFontMac.cpp
// CreateCTFontFromCGFontWithVariations in cairo-quartz-font.c
// ctfont_create_exact_copy in SkFontHost_mac.cpp
CFDictionaryRef vars = CGFontCopyVariations(aCGFont);
CTFontRef ctFont;
if (vars) {
CFDictionaryRef varAttr =
CFDictionaryCreate(nullptr,
(const void**)&kCTFontVariationAttribute,
(const void**)&vars, 1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease(vars);
if (nsCocoaFeatures::OnSierraExactly() ||
(aInstalledFont && nsCocoaFeatures::OnHighSierraOrLater())) {
CFDictionaryRef vars = CGFontCopyVariations(aCGFont);
if (vars) {
CFDictionaryRef varAttr =
CFDictionaryCreate(nullptr,
(const void**)&kCTFontVariationAttribute,
(const void**)&vars, 1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease(vars);
CTFontDescriptorRef varDesc = CTFontDescriptorCreateWithAttributes(varAttr);
CFRelease(varAttr);
CTFontDescriptorRef varDesc =
CTFontDescriptorCreateWithAttributes(varAttr);
CFRelease(varAttr);
ctFont = CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr, varDesc);
CFRelease(varDesc);
ctFont = CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr,
varDesc);
CFRelease(varDesc);
} else {
ctFont = CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr,
nullptr);
}
} else {
ctFont = CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr, nullptr);
ctFont = CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr,
nullptr);
}
return ctFont;
}
@ -139,7 +160,9 @@ ScaledFontMac::ScaledFontMac(CGFontRef aFont,
if (CTFontDrawGlyphsPtr != nullptr) {
// only create mCTFont if we're going to be using the CTFontDrawGlyphs API
mCTFont = CreateCTFontFromCGFontWithVariations(aFont, aSize);
auto unscaledMac = static_cast<UnscaledFontMac*>(aUnscaledFont.get());
bool dataFont = unscaledMac->IsDataFont();
mCTFont = CreateCTFontFromCGFontWithVariations(aFont, aSize, !dataFont);
} else {
mCTFont = nullptr;
}
@ -160,7 +183,10 @@ SkTypeface* ScaledFontMac::GetSkTypeface()
if (mCTFont) {
mTypeface = SkCreateTypefaceFromCTFont(mCTFont);
} else {
CTFontRef fontFace = CreateCTFontFromCGFontWithVariations(mFont, mSize);
auto unscaledMac = static_cast<UnscaledFontMac*>(GetUnscaledFont().get());
bool dataFont = unscaledMac->IsDataFont();
CTFontRef fontFace =
CreateCTFontFromCGFontWithVariations(mFont, mSize, !dataFont);
mTypeface = SkCreateTypefaceFromCTFont(fontFace);
CFRelease(fontFace);
}

Просмотреть файл

@ -40,6 +40,8 @@ public:
bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override;
bool IsDataFont() const { return mIsDataFont; }
already_AddRefed<ScaledFont>
CreateScaledFont(Float aGlyphSize,
const uint8_t* aInstanceData,

Просмотреть файл

@ -353,6 +353,17 @@ CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize)
//
// So we only need to do this "the hard way" on Sierra; on other releases,
// just let the standard CTFont function do its thing.
//
// NOTE in case this ever needs further adjustment: there is similar logic
// in four places in the tree (sadly):
// CreateCTFontFromCGFontWithVariations in gfxMacFont.cpp
// CreateCTFontFromCGFontWithVariations in ScaledFontMac.cpp
// CreateCTFontFromCGFontWithVariations in cairo-quartz-font.c
// ctfont_create_exact_copy in SkFontHost_mac.cpp
//
// XXX Does this need to behave differently for installed fonts on High
// Sierra, as in other similar places (bug 1455569)?
if (!Gecko_OnSierraExactly()) {
return CTFontCreateWithGraphicsFont(aCGFont, aSize, NULL, NULL);
}

Просмотреть файл

@ -757,6 +757,7 @@ private:
// CGFont.
#ifdef MOZ_SKIA
extern "C" bool Gecko_OnSierraExactly();
extern "C" bool Gecko_OnHighSierraOrLater();
#endif
static UniqueCFRef<CTFontRef> ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize,
const CGAffineTransform* transform)
@ -781,9 +782,41 @@ static UniqueCFRef<CTFontRef> ctfont_create_exact_copy(CTFontRef baseFont, CGFlo
// the extra work here -- and this seems to avoid Core Text crashiness
// seen in bug 1454094.
//
// So we only need to do this "the hard way" on Sierra; on other releases,
// just let the standard CTFont function do its thing.
if (Gecko_OnSierraExactly())
// However, for installed fonts it seems we DO need to copy the variations
// explicitly even on 10.13, otherwise fonts fail to render (as in bug
// 1455494) when non-default values are used. Fortunately, the crash
// mentioned above occurs with data fonts, not (AFAICT) with system-
// installed fonts.
//
// So we only need to do this "the hard way" on Sierra, and for installed
// fonts on HighSierra+; otherwise, just let the standard CTFont function
// do its thing.
//
// NOTE in case this ever needs further adjustment: there is similar logic
// in four places in the tree (sadly):
// CreateCTFontFromCGFontWithVariations in gfxMacFont.cpp
// CreateCTFontFromCGFontWithVariations in ScaledFontMac.cpp
// CreateCTFontFromCGFontWithVariations in cairo-quartz-font.c
// ctfont_create_exact_copy in SkFontHost_mac.cpp
// To figure out if a font is installed locally or used from a @font-face
// resource, we check whether its descriptor can provide a URL. This will
// be present for installed fonts, but not for those activated from an
// in-memory resource.
auto IsInstalledFont = [](CTFontRef aFont) {
CTFontDescriptorRef desc = CTFontCopyFontDescriptor(aFont);
CFTypeRef attr = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
CFRelease(desc);
bool result = false;
if (attr) {
result = true;
CFRelease(attr);
}
return result;
};
if (Gecko_OnSierraExactly() ||
(Gecko_OnHighSierraOrLater() && IsInstalledFont(baseFont)))
#endif
{
// Not UniqueCFRef<> because CGFontCopyVariations can return null!

Просмотреть файл

@ -666,8 +666,11 @@ CTFontRef
gfxCoreTextShaper::CreateCTFontWithFeatures(CGFloat aSize,
CTFontDescriptorRef aDescriptor)
{
const gfxFontEntry* fe = mFont->GetFontEntry();
bool isInstalledFont = !fe->IsUserFont() || fe->IsLocalUserFont();
CGFontRef cgFont = static_cast<gfxMacFont*>(mFont)->GetCGFontRef();
return gfxMacFont::CreateCTFontFromCGFontWithVariations(cgFont, aSize,
isInstalledFont,
aDescriptor);
}

Просмотреть файл

@ -421,6 +421,7 @@ gfxMacFont::GetCharWidth(CFDataRef aCmap, char16_t aUniChar,
CTFontRef
gfxMacFont::CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont,
CGFloat aSize,
bool aInstalledFont,
CTFontDescriptorRef aFontDesc)
{
// Avoid calling potentially buggy variation APIs on pre-Sierra macOS
@ -431,34 +432,53 @@ gfxMacFont::CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont,
// the extra work here -- and this seems to avoid Core Text crashiness
// seen in bug 1454094.
//
// So we only need to do this "the hard way" on Sierra; on other releases,
// just let the standard CTFont function do its thing.
if (!nsCocoaFeatures::OnSierraExactly()) {
return CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr, aFontDesc);
}
// However, for installed fonts it seems we DO need to copy the variations
// explicitly even on 10.13, otherwise fonts fail to render (as in bug
// 1455494) when non-default values are used. Fortunately, the crash
// mentioned above occurs with data fonts, not (AFAICT) with system-
// installed fonts.
//
// So we only need to do this "the hard way" on Sierra, and on HighSierra
// for system-installed fonts; in other cases just let the standard CTFont
// function do its thing.
//
// NOTE in case this ever needs further adjustment: there is similar logic
// in four places in the tree (sadly):
// CreateCTFontFromCGFontWithVariations in gfxMacFont.cpp
// CreateCTFontFromCGFontWithVariations in ScaledFontMac.cpp
// CreateCTFontFromCGFontWithVariations in cairo-quartz-font.c
// ctfont_create_exact_copy in SkFontHost_mac.cpp
CFDictionaryRef variations = ::CGFontCopyVariations(aCGFont);
CTFontRef ctFont;
if (variations) {
CFDictionaryRef varAttr =
::CFDictionaryCreate(nullptr,
(const void**)&kCTFontVariationAttribute,
(const void**)&variations, 1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
::CFRelease(variations);
if (nsCocoaFeatures::OnSierraExactly() ||
(aInstalledFont && nsCocoaFeatures::OnHighSierraOrLater())) {
CFDictionaryRef variations = ::CGFontCopyVariations(aCGFont);
if (variations) {
CFDictionaryRef varAttr =
::CFDictionaryCreate(nullptr,
(const void**)&kCTFontVariationAttribute,
(const void**)&variations, 1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
::CFRelease(variations);
CTFontDescriptorRef varDesc = aFontDesc
? ::CTFontDescriptorCreateCopyWithAttributes(aFontDesc, varAttr)
: ::CTFontDescriptorCreateWithAttributes(varAttr);
::CFRelease(varAttr);
CTFontDescriptorRef varDesc = aFontDesc
? ::CTFontDescriptorCreateCopyWithAttributes(aFontDesc, varAttr)
: ::CTFontDescriptorCreateWithAttributes(varAttr);
::CFRelease(varAttr);
ctFont = ::CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr, varDesc);
::CFRelease(varDesc);
ctFont = ::CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr,
varDesc);
::CFRelease(varDesc);
} else {
ctFont = ::CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr,
aFontDesc);
}
} else {
ctFont = ::CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr,
aFontDesc);
}
return ctFont;
}
@ -476,7 +496,10 @@ gfxMacFont::GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID)
}
if (!mCTFont) {
mCTFont = CreateCTFontFromCGFontWithVariations(mCGFont, mAdjustedSize);
bool isInstalledFont =
!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont();
mCTFont = CreateCTFontFromCGFontWithVariations(mCGFont, mAdjustedSize,
isInstalledFont);
if (!mCTFont) { // shouldn't happen, but let's be safe
NS_WARNING("failed to create CTFontRef to measure glyph width");
return 0;

Просмотреть файл

@ -68,6 +68,7 @@ public:
static CTFontRef
CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont,
CGFloat aSize,
bool aInstalledFont,
CTFontDescriptorRef aFontDesc = nullptr);
protected:

Просмотреть файл

@ -45,6 +45,7 @@ private:
// C-callable helper for cairo-quartz-font.c and SkFontHost_mac.cpp
extern "C" {
bool Gecko_OnSierraExactly();
bool Gecko_OnHighSierraOrLater();
}
#endif // nsCocoaFeatures_h_

Просмотреть файл

@ -188,6 +188,12 @@ Gecko_OnSierraExactly()
return nsCocoaFeatures::OnSierraExactly();
}
bool
Gecko_OnHighSierraOrLater()
{
return nsCocoaFeatures::OnHighSierraOrLater();
}
/* static */ bool
nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix)
{