From 5ad2e1cea1b2c08950c91174840f542806954d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 20 Mar 2017 19:31:29 +0100 Subject: 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 --- .../fontdatabases/mac/qcoretextfontdatabase.mm | 71 ++++++---------------- .../fontdatabases/mac/qcoretextfontdatabase_p.h | 7 +-- 2 files changed, 22 insertions(+), 56 deletions(-) diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index ce9b61ba4c..d0b28b856b 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -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 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::createDescriptorArrayForFont(CTFontRef font, const QString &fileName) +CFArrayRef QCoreTextFontDatabaseEngineFactory::createDescriptorArrayForDescriptor(CTFontDescriptorRef descriptor, const QString &fileName) { Q_UNUSED(fileName) CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - QCFType descriptor = CTFontCopyFontDescriptor(font); CFArrayAppendValue(array, descriptor); return array; } #ifndef QT_NO_FREETYPE template <> -CFArrayRef QCoreTextFontDatabaseEngineFactory::createDescriptorArrayForFont(CTFontRef font, const QString &fileName) +CFArrayRef QCoreTextFontDatabaseEngineFactory::createDescriptorArrayForDescriptor(CTFontDescriptorRef descriptor, const QString &fileName) { CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - QCFType 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,44 +624,36 @@ CFArrayRef QCoreTextFontDatabaseEngineFactory::createDescriptorAr QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) { QCFType fonts; - QStringList families; - CFErrorRef error = 0; if (!fontData.isEmpty()) { QByteArray* fontDataCopy = new QByteArray(fontData); QCFType dataProvider = CGDataProviderCreateWithData(fontDataCopy, fontDataCopy->constData(), fontDataCopy->size(), releaseFontData); - QCFType cgFont = CGFontCreateWithDataProvider(dataProvider); - if (cgFont) { - if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) { - QCFType font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL); - fonts = createDescriptorArrayForFont(font, fileName); - m_applicationFonts.append(QVariant::fromValue(QCFType::constructFromGet(cgFont))); - } + if (QCFType cgFont = CGFontCreateWithDataProvider(dataProvider)) { + QCFType ctFont = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL); + QCFType descriptor = CTFontCopyFontDescriptor(ctFont); + fonts = createDescriptorArrayForDescriptor(descriptor, fileName); } } else { - QCFType fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false); - if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error)) { - fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL); - m_applicationFonts.append(QVariant::fromValue(QCFType::constructFromGet(fontURL))); - } + QCFType fontURL = QUrl::fromLocalFile(fileName).toCFURL(); + fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL); } - if (error) { - NSLog(@"Unable to register font: %@", error); - CFRelease(error); - } + if (!fonts) + return QStringList(); - if (fonts) { - const int numFonts = CFArrayGetCount(fonts); - for (int i = 0; i < numFonts; ++i) { - CTFontDescriptorRef fontDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fonts, i)); - populateFromDescriptor(fontDescriptor); - QCFType familyName = CFStringRef(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute)); - families.append(QCFString(familyName)); - } + QStringList families; + const int numFonts = CFArrayGetCount(fonts); + for (int i = 0; i < numFonts; ++i) { + CTFontDescriptorRef fontDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fonts, i)); + populateFromDescriptor(fontDescriptor); + QCFType familyName = CFStringRef(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute)); + families.append(QString::fromCFString(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 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 >())) { - CTFontManagerUnregisterGraphicsFont(font.value >(), &error); - } else if (font.canConvert(qMetaTypeId >())) { - CTFontManagerUnregisterFontsForURL(font.value >(), kCTFontManagerScopeProcess, &error); - } - } - - m_applicationFonts.clear(); -} - QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h index 8edf60b5fa..11ea0bea02 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h @@ -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 m_applicationFonts; mutable QSet m_systemFontDescriptors; mutable QHash 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 -- cgit v1.2.3