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:
parent
17fc188aec
commit
5ad2e1cea1
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user