Prevent repeated and unnecessary font population QCoreTextFontDatabase

The platform font database is populated from QFontDatabase, through the
static initializeDb() function, whenever the font database determines
that the platform database has not been initialized (by checking if the
font database is empty).

There are other clients of QPlatformFontDatabase though, such as QFont,
which uses the platform font database to check for the default family.
The CoreText implementation of determining the default family relies
on data that is computed during font population, and hence does an
internal (self-triggered) populate.

To prevent repeated populates as a result of calling QFont::defaultFamily()
we guard the populate by a similar isEmpty() check as QFontDatabase does,
but to ensure that this check works in the case of an invalidated font
database, we need to propagate the font database invalidation down to
the platform font database.

Change-Id: I8d06c6f6fc5da6353c087335859eaca008c2f6a6
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
This commit is contained in:
Tor Arne Vestbø 2014-03-04 16:27:38 +01:00 committed by The Qt Project
parent 9f1089531d
commit 3fec94fd07
5 changed files with 42 additions and 18 deletions

View File

@ -420,6 +420,7 @@ void QFontDatabasePrivate::invalidate()
{
QFontCache::instance()->clear();
free();
QGuiApplicationPrivate::platformIntegration()->fontDatabase()->invalidate();
emit static_cast<QGuiApplication *>(QCoreApplication::instance())->fontDatabaseChanged();
}

View File

@ -275,6 +275,16 @@ void QPlatformFontDatabase::populateFontDatabase()
}
}
/*!
This function is called whenever the font database is invalidated.
Reimplement this function to clear any internal data structures that
will need to be rebuilt at the next call to populateFontDatabase().
*/
void QPlatformFontDatabase::invalidate()
{
}
/*!
Returns a multi font engine in the specified \a script to encapsulate \a fontEngine with the
option to fall back to the fonts given by \a fallbacks if \a fontEngine does not support

View File

@ -96,6 +96,8 @@ class Q_GUI_EXPORT QPlatformFontDatabase
public:
virtual ~QPlatformFontDatabase();
virtual void populateFontDatabase();
virtual void invalidate();
virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script);
virtual QFontEngine *fontEngine(const QFontDef &fontDef, void *handle);
virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const;

View File

@ -199,6 +199,12 @@ void QCoreTextFontDatabase::populateFontDatabase()
[pool release];
}
void QCoreTextFontDatabase::invalidate()
{
psNameToFamily.clear();
familyNameToPsName.clear();
}
void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
{
QString foundryName = QStringLiteral("CoreText");
@ -389,29 +395,31 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
if (fallbackLists.contains(family))
return fallbackLists.value(family);
if (!familyNameToPsName.contains(family))
if (familyNameToPsName.isEmpty())
const_cast<QCoreTextFontDatabase*>(this)->populateFontDatabase();
QCFType<CTFontRef> font = CTFontCreateWithName(QCFString(familyNameToPsName[family]), 12.0, NULL);
if (font) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"];
if (familyNameToPsName.contains(family)) {
QCFType<CTFontRef> font = CTFontCreateWithName(QCFString(familyNameToPsName[family]), 12.0, NULL);
if (font) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"];
QCFType<CFArrayRef> cascadeList = (CFArrayRef) CTFontCopyDefaultCascadeListForLanguages(font, (CFArrayRef) languages);
if (cascadeList) {
QStringList fallbackList;
const int numCascades = CFArrayGetCount(cascadeList);
for (int i = 0; i < numCascades; ++i) {
CTFontDescriptorRef fontFallback = (CTFontDescriptorRef) CFArrayGetValueAtIndex(cascadeList, i);
QCFString fallbackFamilyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(fontFallback, kCTFontFamilyNameAttribute, NULL);
fallbackList.append(QCFString::toQString(fallbackFamilyName));
QCFType<CFArrayRef> cascadeList = (CFArrayRef) CTFontCopyDefaultCascadeListForLanguages(font, (CFArrayRef) languages);
if (cascadeList) {
QStringList fallbackList;
const int numCascades = CFArrayGetCount(cascadeList);
for (int i = 0; i < numCascades; ++i) {
CTFontDescriptorRef fontFallback = (CTFontDescriptorRef) CFArrayGetValueAtIndex(cascadeList, i);
QCFString fallbackFamilyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(fontFallback, kCTFontFamilyNameAttribute, NULL);
fallbackList.append(QCFString::toQString(fallbackFamilyName));
}
fallbackLists[family] = fallbackList;
}
fallbackLists[family] = fallbackList;
}
}
if (fallbackLists.contains(family))
return fallbackLists.value(family);
if (fallbackLists.contains(family))
return fallbackLists.value(family);
}
}
#endif
}
@ -425,7 +433,8 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
if (!didPopulateStyleFallbacks) {
#if defined(Q_OS_MACX)
// Ensure we have the psNameToFamily mapping set up
const_cast<QCoreTextFontDatabase*>(this)->populateFontDatabase();
if (psNameToFamily.isEmpty())
const_cast<QCoreTextFontDatabase*>(this)->populateFontDatabase();
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"];

View File

@ -72,6 +72,8 @@ 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);
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const;