Bug 1430820 - Cache any required feature-modified Core Text font instances in gfxCoreTextShaper, rather than re-creating them for each shaping call. r=jrmuizel

This commit is contained in:
Jonathan Kew 2018-03-29 21:53:55 +01:00
parent c6574d2c99
commit c2f3f60125
2 changed files with 85 additions and 173 deletions

View File

@ -18,12 +18,7 @@
using namespace mozilla;
// standard font descriptors that we construct the first time they're needed
CTFontDescriptorRef gfxCoreTextShaper::sDefaultFeaturesDescriptor = nullptr;
CTFontDescriptorRef gfxCoreTextShaper::sSmallCapsDescriptor = nullptr;
CTFontDescriptorRef gfxCoreTextShaper::sDisableLigaturesDescriptor = nullptr;
CTFontDescriptorRef gfxCoreTextShaper::sSmallCapDisableLigDescriptor = nullptr;
CTFontDescriptorRef gfxCoreTextShaper::sIndicFeaturesDescriptor = nullptr;
CTFontDescriptorRef gfxCoreTextShaper::sIndicDisableLigaturesDescriptor = nullptr;
CTFontDescriptorRef gfxCoreTextShaper::sFeaturesDescriptor[kMaxFontInstances];
// Helper to create a CFDictionary with the right attributes for shaping our
// text, including imposing the given directionality.
@ -45,7 +40,7 @@ gfxCoreTextShaper::CreateAttrDict(bool aRightToLeft)
&kCFTypeArrayCallBacks);
::CFRelease(dirNumber);
CFTypeRef attrs[] = { kCTFontAttributeName, kCTWritingDirectionAttributeName };
CFTypeRef values[] = { mCTFont, dirArray };
CFTypeRef values[] = { mCTFont[0], dirArray };
CFDictionaryRef attrDict =
::CFDictionaryCreate(kCFAllocatorDefault,
attrs, values, ArrayLength(attrs),
@ -60,9 +55,13 @@ gfxCoreTextShaper::gfxCoreTextShaper(gfxMacFont *aFont)
, mAttributesDictLTR(nullptr)
, mAttributesDictRTL(nullptr)
{
// Create our CTFontRef
mCTFont = CreateCTFontWithFeatures(aFont->GetAdjustedSize(),
GetDefaultFeaturesDescriptor());
for (size_t i = 0; i < kMaxFontInstances; i++) {
mCTFont[i] = nullptr;
}
// Create our default CTFontRef
mCTFont[0] =
CreateCTFontWithFeatures(aFont->GetAdjustedSize(),
GetFeaturesDescriptor(kDefaultFeatures));
}
gfxCoreTextShaper::~gfxCoreTextShaper()
@ -73,8 +72,10 @@ gfxCoreTextShaper::~gfxCoreTextShaper()
if (mAttributesDictRTL) {
::CFRelease(mAttributesDictRTL);
}
if (mCTFont) {
::CFRelease(mCTFont);
for (size_t i = 0; i < kMaxFontInstances; i++) {
if (mCTFont[i]) {
::CFRelease(mCTFont[i]);
}
}
}
@ -135,7 +136,7 @@ gfxCoreTextShaper::ShapeText(DrawTarget *aDrawTarget,
(isRightToLeft ? mAttributesDictRTL : mAttributesDictLTR) = attrObj;
}
CTFontRef tempCTFont = nullptr;
FeatureFlags featureFlags = kDefaultFeatures;
if (IsBuggyIndicScript(aScript)) {
// To work around buggy Indic AAT fonts shipped with OS X,
// we re-enable the Line Initial Smart Swashes feature that is needed
@ -143,36 +144,30 @@ gfxCoreTextShaper::ShapeText(DrawTarget *aDrawTarget,
// Affected fonts include Bangla MN, Bangla Sangam MN, Kannada MN,
// Kannada Sangam MN. See bugs 686225, 728557, 953231, 1145515.
// Also applies to Oriya and Khmer, see bug 1370927 and bug 1403166.
tempCTFont =
CreateCTFontWithFeatures(::CTFontGetSize(mCTFont),
aShapedText->DisableLigatures()
? GetIndicDisableLigaturesDescriptor()
: GetIndicFeaturesDescriptor());
} else if (aShapedText->DisableLigatures()) {
featureFlags |= kIndicFeatures;
}
if (aShapedText->DisableLigatures()) {
// For letterspacing (or maybe other situations) we need to make
// a copy of the CTFont with the ligature feature disabled.
tempCTFont =
CreateCTFontWithFeatures(::CTFontGetSize(mCTFont),
addSmallCaps
? GetSmallCapDisableLigDescriptor()
: GetDisableLigaturesDescriptor());
} else if (addSmallCaps) {
tempCTFont =
CreateCTFontWithFeatures(::CTFontGetSize(mCTFont),
GetSmallCapsDescriptor());
featureFlags |= kDisableLigatures;
}
if (addSmallCaps) {
featureFlags |= kAddSmallCaps;
}
// For the disabled-ligature, buggy-indic-font or small-caps case, replace
// the standard CTFont in the attribute dictionary with a tweaked version.
// the default CTFont in the attribute dictionary with a tweaked version.
CFMutableDictionaryRef mutableAttr = nullptr;
if (tempCTFont) {
mutableAttr = ::CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 2,
attrObj);
if (featureFlags != 0) {
if (!mCTFont[featureFlags]) {
mCTFont[featureFlags] =
CreateCTFontWithFeatures(mFont->GetAdjustedSize(),
GetFeaturesDescriptor(featureFlags));
}
mutableAttr =
::CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 2, attrObj);
::CFDictionaryReplaceValue(mutableAttr,
kCTFontAttributeName, tempCTFont);
// Having created the dict, we're finished with our temporary
// Indic and/or ligature-disabled or small-caps CTFontRef.
::CFRelease(tempCTFont);
kCTFontAttributeName, mCTFont[featureFlags]);
attrObj = mutableAttr;
}
@ -577,7 +572,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
CTFontDescriptorRef
gfxCoreTextShaper::CreateFontFeaturesDescriptor(
const std::pair<SInt16,SInt16> aFeatures[],
const std::pair<SInt16,SInt16>* aFeatures,
size_t aCount)
{
MOZ_ASSERT(aCount <= MAX_FEATURES);
@ -637,110 +632,34 @@ gfxCoreTextShaper::CreateFontFeaturesDescriptor(
}
CTFontDescriptorRef
gfxCoreTextShaper::GetDefaultFeaturesDescriptor()
gfxCoreTextShaper::GetFeaturesDescriptor(FeatureFlags aFeatureFlags)
{
if (sDefaultFeaturesDescriptor == nullptr) {
const std::pair<SInt16,SInt16> kDefaultFeatures[] = {
{ kSmartSwashType, kLineInitialSwashesOffSelector },
{ kSmartSwashType, kLineFinalSwashesOffSelector }
};
static_assert(ArrayLength(kDefaultFeatures) <= MAX_FEATURES,
"need to increase MAX_FEATURES");
sDefaultFeaturesDescriptor =
CreateFontFeaturesDescriptor(kDefaultFeatures,
ArrayLength(kDefaultFeatures));
MOZ_ASSERT(aFeatureFlags < kMaxFontInstances);
if (!sFeaturesDescriptor[aFeatureFlags]) {
typedef std::pair<SInt16,SInt16> FeatT;
AutoTArray<FeatT,MAX_FEATURES> features;
features.AppendElement(FeatT(kSmartSwashType,
kLineFinalSwashesOffSelector));
if ((aFeatureFlags & kIndicFeatures) == 0) {
features.AppendElement(FeatT(kSmartSwashType,
kLineInitialSwashesOffSelector));
}
if (aFeatureFlags & kAddSmallCaps) {
features.AppendElement(FeatT(kLetterCaseType,
kSmallCapsSelector));
features.AppendElement(FeatT(kLowerCaseType,
kLowerCaseSmallCapsSelector));
}
if (aFeatureFlags & kDisableLigatures) {
features.AppendElement(FeatT(kLigaturesType,
kCommonLigaturesOffSelector));
}
MOZ_ASSERT(features.Length() <= MAX_FEATURES);
sFeaturesDescriptor[aFeatureFlags] =
CreateFontFeaturesDescriptor(features.Elements(),
features.Length());
}
return sDefaultFeaturesDescriptor;
}
CTFontDescriptorRef
gfxCoreTextShaper::GetSmallCapsDescriptor()
{
if (sSmallCapsDescriptor == nullptr) {
const std::pair<SInt16,SInt16> kSmallCaps[] = {
{ kSmartSwashType, kLineInitialSwashesOffSelector },
{ kSmartSwashType, kLineFinalSwashesOffSelector },
{ kLetterCaseType, kSmallCapsSelector },
{ kLowerCaseType, kLowerCaseSmallCapsSelector }
};
static_assert(ArrayLength(kSmallCaps) <= MAX_FEATURES,
"need to increase MAX_FEATURES");
sSmallCapsDescriptor =
CreateFontFeaturesDescriptor(kSmallCaps,
ArrayLength(kSmallCaps));
}
return sSmallCapsDescriptor;
}
CTFontDescriptorRef
gfxCoreTextShaper::GetDisableLigaturesDescriptor()
{
if (sDisableLigaturesDescriptor == nullptr) {
const std::pair<SInt16,SInt16> kDisableLigatures[] = {
{ kSmartSwashType, kLineInitialSwashesOffSelector },
{ kSmartSwashType, kLineFinalSwashesOffSelector },
{ kLigaturesType, kCommonLigaturesOffSelector }
};
static_assert(ArrayLength(kDisableLigatures) <= MAX_FEATURES,
"need to increase MAX_FEATURES");
sDisableLigaturesDescriptor =
CreateFontFeaturesDescriptor(kDisableLigatures,
ArrayLength(kDisableLigatures));
}
return sDisableLigaturesDescriptor;
}
CTFontDescriptorRef
gfxCoreTextShaper::GetSmallCapDisableLigDescriptor()
{
if (sSmallCapDisableLigDescriptor == nullptr) {
const std::pair<SInt16,SInt16> kFeatures[] = {
{ kSmartSwashType, kLineInitialSwashesOffSelector },
{ kSmartSwashType, kLineFinalSwashesOffSelector },
{ kLigaturesType, kCommonLigaturesOffSelector },
{ kLetterCaseType, kSmallCapsSelector },
{ kLowerCaseType, kLowerCaseSmallCapsSelector }
};
static_assert(ArrayLength(kFeatures) <= MAX_FEATURES,
"need to increase MAX_FEATURES");
sSmallCapDisableLigDescriptor =
CreateFontFeaturesDescriptor(kFeatures,
ArrayLength(kFeatures));
}
return sSmallCapDisableLigDescriptor;
}
CTFontDescriptorRef
gfxCoreTextShaper::GetIndicFeaturesDescriptor()
{
if (sIndicFeaturesDescriptor == nullptr) {
const std::pair<SInt16,SInt16> kIndicFeatures[] = {
{ kSmartSwashType, kLineFinalSwashesOffSelector }
};
static_assert(ArrayLength(kIndicFeatures) <= MAX_FEATURES,
"need to increase MAX_FEATURES");
sIndicFeaturesDescriptor =
CreateFontFeaturesDescriptor(kIndicFeatures,
ArrayLength(kIndicFeatures));
}
return sIndicFeaturesDescriptor;
}
CTFontDescriptorRef
gfxCoreTextShaper::GetIndicDisableLigaturesDescriptor()
{
if (sIndicDisableLigaturesDescriptor == nullptr) {
const std::pair<SInt16,SInt16> kIndicDisableLigatures[] = {
{ kSmartSwashType, kLineFinalSwashesOffSelector },
{ kLigaturesType, kCommonLigaturesOffSelector }
};
static_assert(ArrayLength(kIndicDisableLigatures) <= MAX_FEATURES,
"need to increase MAX_FEATURES");
sIndicDisableLigaturesDescriptor =
CreateFontFeaturesDescriptor(kIndicDisableLigatures,
ArrayLength(kIndicDisableLigatures));
}
return sIndicDisableLigaturesDescriptor;
return sFeaturesDescriptor[aFeatureFlags];
}
CTFontRef
@ -755,20 +674,10 @@ gfxCoreTextShaper::CreateCTFontWithFeatures(CGFloat aSize,
void
gfxCoreTextShaper::Shutdown() // [static]
{
if (sIndicDisableLigaturesDescriptor != nullptr) {
::CFRelease(sIndicDisableLigaturesDescriptor);
sIndicDisableLigaturesDescriptor = nullptr;
}
if (sIndicFeaturesDescriptor != nullptr) {
::CFRelease(sIndicFeaturesDescriptor);
sIndicFeaturesDescriptor = nullptr;
}
if (sDisableLigaturesDescriptor != nullptr) {
::CFRelease(sDisableLigaturesDescriptor);
sDisableLigaturesDescriptor = nullptr;
}
if (sDefaultFeaturesDescriptor != nullptr) {
::CFRelease(sDefaultFeaturesDescriptor);
sDefaultFeaturesDescriptor = nullptr;
for (size_t i = 0; i < kMaxFontInstances; i++) {
if (sFeaturesDescriptor[i] != nullptr) {
::CFRelease(sFeaturesDescriptor[i]);
sFeaturesDescriptor[i] = nullptr;
}
}
}

View File

@ -30,8 +30,23 @@ public:
// clean up static objects that may have been cached
static void Shutdown();
// Flags used to track what AAT features should be enabled on the Core Text
// font instance. (Internal; only public so that we can use the
// MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS macro below.)
enum FeatureFlags : uint8_t {
kDefaultFeatures = 0x00,
// bit flags for non-default feature settings we might need
// to use, which will require separate font instances
kDisableLigatures = 0x01,
kAddSmallCaps = 0x02,
kIndicFeatures = 0x04,
// number of font instances, indexed by OR-ing the flags above
kMaxFontInstances = 8
};
protected:
CTFontRef mCTFont;
CTFontRef mCTFont[kMaxFontInstances];
// attributes for shaping text with LTR or RTL directionality
CFDictionaryRef mAttributesDictLTR;
@ -49,27 +64,15 @@ protected:
CFDictionaryRef CreateAttrDictWithoutDirection();
static CTFontDescriptorRef
CreateFontFeaturesDescriptor(const std::pair<SInt16,SInt16> aFeatures[],
CreateFontFeaturesDescriptor(const std::pair<SInt16,SInt16>* aFeatures,
size_t aCount);
static CTFontDescriptorRef GetDefaultFeaturesDescriptor();
static CTFontDescriptorRef GetSmallCapsDescriptor();
static CTFontDescriptorRef GetDisableLigaturesDescriptor();
static CTFontDescriptorRef GetSmallCapDisableLigDescriptor();
static CTFontDescriptorRef GetIndicFeaturesDescriptor();
static CTFontDescriptorRef GetIndicDisableLigaturesDescriptor();
static CTFontDescriptorRef GetFeaturesDescriptor(FeatureFlags aFeatureFlags);
// cached font descriptor, created the first time it's needed
static CTFontDescriptorRef sDefaultFeaturesDescriptor;
static CTFontDescriptorRef sSmallCapsDescriptor;
// cached descriptor for adding disable-ligatures setting to a font
static CTFontDescriptorRef sDisableLigaturesDescriptor;
static CTFontDescriptorRef sSmallCapDisableLigDescriptor;
// feature descriptors for buggy Indic AAT font workaround
static CTFontDescriptorRef sIndicFeaturesDescriptor;
static CTFontDescriptorRef sIndicDisableLigaturesDescriptor;
// cached font descriptors, created the first time they're needed
static CTFontDescriptorRef sFeaturesDescriptor[kMaxFontInstances];
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxCoreTextShaper::FeatureFlags)
#endif /* GFX_CORETEXTSHAPER_H */