Remove need to populate font database on OS X to get fallback families
Populating the whole database takes a while, and it's very easy to trigger the fallback family code path through eg. matching or getting the default font family from QFont. Instead of relying on populate to resolve family name to a PostScript name (which was required when using CTFontCreateWithName), we instead use the CTFontDescriptorCreateWithAttributes() function to create a descriptor based on the family name, and then use CTFontCreateWithFontDescriptor(). The other way around, we use CTFontDescriptorCreateWithNameAndSize, and then pull out the family name from the descriptor. The need for creating a CTFont for private fonts (eg '.Apple Symbols Fallback') does not seem necessary anymore, as tested on 10.7-10.9. The disadvantage of creating font descriptors instead of re-using the data computed by population is that we're doing the same work twice, but the end result is making the font database more lazy, and the 80% use-case is assumed to be that you're only interested in the fallback of a small number of fonts, which means you don't want to populate all of the fonts in the system (taking about 1100ms on the test system). Looking up the fallback of a single family or style now takes about 15-25ms. Task-number: QTBUG-37165 Change-Id: I6b904dbe796a3f236919d778d0168fdef9a20e69 Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com> Reviewed-by: Simon Hausmann <simon.hausmann@digia.com> Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
This commit is contained in:
parent
800232e1d3
commit
c466f2ed46
@ -199,12 +199,6 @@ void QCoreTextFontDatabase::populateFontDatabase()
|
||||
[pool release];
|
||||
}
|
||||
|
||||
void QCoreTextFontDatabase::invalidate()
|
||||
{
|
||||
psNameToFamily.clear();
|
||||
familyNameToPsName.clear();
|
||||
}
|
||||
|
||||
void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
|
||||
{
|
||||
QString foundryName = QStringLiteral("CoreText");
|
||||
@ -271,12 +265,6 @@ void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
|
||||
QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch,
|
||||
true /* antialiased */, true /* scalable */,
|
||||
pixelSize, fixedPitch, writingSystems, (void *) font);
|
||||
|
||||
// We need to map back and forth between PostScript-names and family-names for fallback list construction
|
||||
CFStringRef psName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontNameAttribute);
|
||||
psNameToFamily[QCFString::toQString((NSString *) psName)] = familyName;
|
||||
familyNameToPsName[familyName] = QCFString::toQString((NSString *) psName);
|
||||
CFRelease(psName);
|
||||
}
|
||||
|
||||
void QCoreTextFontDatabase::releaseHandle(void *handle)
|
||||
@ -356,25 +344,15 @@ QFont::StyleHint styleHintFromNSString(NSString *style)
|
||||
return QFont::AnyStyle;
|
||||
}
|
||||
|
||||
static QString familyNameFromPostScriptName(QHash<QString, QString> &psNameToFamily,
|
||||
NSString *psName)
|
||||
static QString familyNameFromPostScriptName(NSString *psName)
|
||||
{
|
||||
QString name = QCFString::toQString(psName);
|
||||
if (psNameToFamily.contains(name))
|
||||
return psNameToFamily[name];
|
||||
else {
|
||||
// Some of the font name in DefaultFontFallbacks.plist are hidden fonts like AquaHiraKaku,
|
||||
// their family name begins with a dot, like ".AquaHiraKaku" or ".Apple Symbols Fallback",
|
||||
// the only way (I've found) to get it are actually creating a CTFont with them. We only
|
||||
// need to do it once though.
|
||||
QCFType<CTFontRef> font = CTFontCreateWithName((CFStringRef) psName, 12.0, NULL);
|
||||
if (font) {
|
||||
QCFString family = CTFontCopyFamilyName(font);
|
||||
psNameToFamily[name] = family;
|
||||
return family;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
QCFType<CTFontDescriptorRef> fontDescriptor = (CTFontDescriptorRef) CTFontDescriptorCreateWithNameAndSize((CFStringRef)psName, 12.0);
|
||||
QCFString familyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(fontDescriptor, kCTFontFamilyNameAttribute, 0);
|
||||
QString name = QCFString::toQString(familyName);
|
||||
if (name.isEmpty())
|
||||
qWarning() << "QCoreTextFontDatabase: Failed to resolve family name for PostScript name " << QCFString::toQString((CFStringRef)psName);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
|
||||
@ -395,12 +373,10 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
|
||||
if (fallbackLists.contains(family))
|
||||
return fallbackLists.value(family);
|
||||
|
||||
if (familyNameToPsName.isEmpty())
|
||||
const_cast<QCoreTextFontDatabase*>(this)->populateFontDatabase();
|
||||
|
||||
if (familyNameToPsName.contains(family)) {
|
||||
QCFType<CTFontRef> font = CTFontCreateWithName(QCFString(familyNameToPsName[family]), 12.0, NULL);
|
||||
if (font) {
|
||||
QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, QCFString(family));
|
||||
if (QCFType<CTFontDescriptorRef> fontDescriptor = CTFontDescriptorCreateWithAttributes(attributes)) {
|
||||
if (QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(fontDescriptor, 12.0, 0)) {
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"];
|
||||
|
||||
@ -432,10 +408,6 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
|
||||
static bool didPopulateStyleFallbacks = false;
|
||||
if (!didPopulateStyleFallbacks) {
|
||||
#if defined(Q_OS_MACX)
|
||||
// Ensure we have the psNameToFamily mapping set up
|
||||
if (psNameToFamily.isEmpty())
|
||||
const_cast<QCoreTextFontDatabase*>(this)->populateFontDatabase();
|
||||
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"];
|
||||
|
||||
@ -451,10 +423,10 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
|
||||
NSArray *langs = [(NSArray *) item sortedArrayUsingFunction: languageMapSort
|
||||
context: languages];
|
||||
for (NSArray *map in langs)
|
||||
fallbackList.append(familyNameFromPostScriptName(psNameToFamily, [map objectAtIndex: 1]));
|
||||
fallbackList.append(familyNameFromPostScriptName([map objectAtIndex: 1]));
|
||||
}
|
||||
else if ([item isKindOfClass: [NSString class]])
|
||||
fallbackList.append(familyNameFromPostScriptName(psNameToFamily, item));
|
||||
fallbackList.append(familyNameFromPostScriptName(item));
|
||||
}
|
||||
|
||||
if (QCoreTextFontEngine::supportsColorGlyphs())
|
||||
|
@ -72,7 +72,6 @@ public:
|
||||
QCoreTextFontDatabase();
|
||||
~QCoreTextFontDatabase();
|
||||
void populateFontDatabase();
|
||||
void invalidate() Q_DECL_OVERRIDE;
|
||||
|
||||
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle);
|
||||
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
|
||||
@ -86,8 +85,6 @@ private:
|
||||
void populateFromDescriptor(CTFontDescriptorRef font);
|
||||
|
||||
mutable QString defaultFontName;
|
||||
mutable QHash<QString, QString> psNameToFamily;
|
||||
mutable QHash<QString, QString> familyNameToPsName;
|
||||
|
||||
void removeApplicationFonts();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user