Populate application fonts via font descriptors on Apple platforms

Instead of registering the font via CTFontManagerRegister we just create
a font descriptor for the data/URL and populate that like normal system
fonts. This makes the code more similar to how we deal with other fonts,
shaves off a ms during font registration due to not registering the font,
and fixes an issue on iOS where CTFontManagerRegister would invalidate
earlier populated system font descriptors.

Task-number: QTBUG-56765
Change-Id: I002a65075b15837c9a2d22573020d4c834111837
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
Tor Arne Vestbø 2017-03-20 19:31:29 +01:00
parent 17fc188aec
commit 5ad2e1cea1
2 changed files with 22 additions and 56 deletions

View File

@ -199,10 +199,6 @@ static CFArrayRef availableFamilyNames()
void QCoreTextFontDatabase::populateFontDatabase()
{
// The caller (QFontDB) expects the db to be populate only with system fonts, so we need
// to make sure that any previously registered app fonts become invisible.
removeApplicationFonts();
QCFType<CFArrayRef> familyNames = availableFamilyNames();
const int numberOfFamilies = CFArrayGetCount(familyNames);
for (int i = 0; i < numberOfFamilies; ++i) {
@ -585,21 +581,19 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
}
template <>
CFArrayRef QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::createDescriptorArrayForFont(CTFontRef font, const QString &fileName)
CFArrayRef QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::createDescriptorArrayForDescriptor(CTFontDescriptorRef descriptor, const QString &fileName)
{
Q_UNUSED(fileName)
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font);
CFArrayAppendValue(array, descriptor);
return array;
}
#ifndef QT_NO_FREETYPE
template <>
CFArrayRef QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::createDescriptorArrayForFont(CTFontRef font, const QString &fileName)
CFArrayRef QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::createDescriptorArrayForDescriptor(CTFontDescriptorRef descriptor, const QString &fileName)
{
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font);
// The physical font source URL (usually a local file or Qt resource) is only required for
// FreeType, when using non-system fonts, and needs some hackery to attach in a format
@ -630,43 +624,35 @@ CFArrayRef QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::createDescriptorAr
QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
{
QCFType<CFArrayRef> fonts;
QStringList families;
CFErrorRef error = 0;
if (!fontData.isEmpty()) {
QByteArray* fontDataCopy = new QByteArray(fontData);
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider);
if (cgFont) {
if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) {
QCFType<CTFontRef> font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL);
fonts = createDescriptorArrayForFont(font, fileName);
m_applicationFonts.append(QVariant::fromValue(QCFType<CGFontRef>::constructFromGet(cgFont)));
}
if (QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider)) {
QCFType<CTFontRef> ctFont = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL);
QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(ctFont);
fonts = createDescriptorArrayForDescriptor(descriptor, fileName);
}
} else {
QCFType<CFURLRef> fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false);
if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error)) {
fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL);
m_applicationFonts.append(QVariant::fromValue(QCFType<CFURLRef>::constructFromGet(fontURL)));
}
QCFType<CFURLRef> fontURL = QUrl::fromLocalFile(fileName).toCFURL();
fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL);
}
if (error) {
NSLog(@"Unable to register font: %@", error);
CFRelease(error);
if (!fonts)
return QStringList();
QStringList families;
const int numFonts = CFArrayGetCount(fonts);
for (int i = 0; i < numFonts; ++i) {
CTFontDescriptorRef fontDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fonts, i));
populateFromDescriptor(fontDescriptor);
QCFType<CFStringRef> familyName = CFStringRef(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute));
families.append(QString::fromCFString(familyName));
}
if (fonts) {
const int numFonts = CFArrayGetCount(fonts);
for (int i = 0; i < numFonts; ++i) {
CTFontDescriptorRef fontDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fonts, i));
populateFromDescriptor(fontDescriptor);
QCFType<CFStringRef> familyName = CFStringRef(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute));
families.append(QCFString(familyName));
}
}
// Note: We don't do font matching via CoreText for application fonts, so we don't
// need to enable font matching for them via CTFontManagerEnableFontDescriptors.
return families;
}
@ -846,22 +832,5 @@ QList<int> QCoreTextFontDatabase::standardSizes() const
return ret;
}
void QCoreTextFontDatabase::removeApplicationFonts()
{
if (m_applicationFonts.isEmpty())
return;
for (const QVariant &font : qAsConst(m_applicationFonts)) {
CFErrorRef error;
if (font.canConvert(qMetaTypeId<QCFType<CGFontRef> >())) {
CTFontManagerUnregisterGraphicsFont(font.value<QCFType<CGFontRef> >(), &error);
} else if (font.canConvert(qMetaTypeId<QCFType<CFURLRef> >())) {
CTFontManagerUnregisterFontsForURL(font.value<QCFType<CFURLRef> >(), kCTFontManagerScopeProcess, &error);
}
}
m_applicationFonts.clear();
}
QT_END_NAMESPACE

View File

@ -91,13 +91,10 @@ public:
private:
void populateFromDescriptor(CTFontDescriptorRef font, const QString &familyName = QString());
virtual CFArrayRef createDescriptorArrayForFont(CTFontRef font, const QString &fileName) = 0;
virtual CFArrayRef createDescriptorArrayForDescriptor(CTFontDescriptorRef descriptor, const QString &fileName) = 0;
mutable QString defaultFontName;
void removeApplicationFonts();
QVector<QVariant> m_applicationFonts;
mutable QSet<CTFontDescriptorRef> m_systemFontDescriptors;
mutable QHash<QPlatformTheme::Font, QFont *> m_themeFonts;
};
@ -112,7 +109,7 @@ public:
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
protected:
CFArrayRef createDescriptorArrayForFont(CTFontRef font, const QString &fileName) override;
CFArrayRef createDescriptorArrayForDescriptor(CTFontDescriptorRef descriptor, const QString &fileName) override;
};
QT_END_NAMESPACE