Fix application font population on OS X
This patch fixes two issues that prevented the application font related tests of tst_QFontDatabase from passing: * The code for creating the font descriptor after the registration of an app font with file name using CTFontDescriptorCreateWithAttributes must create a dictionary with kCTFontURLAttribute as key and the CFURLRef pointing to the on-disk file as value. Unfortunately the code mixed up keys and values in the dictionary. * Registration of app fonts within QFontDatabase itself on Windows and Fontconfig platforms works by QFontDatabase calling addApplicationFont on the platform db after calling populateFontDatabase(). It assumes that addApplicationFont on the platform db is capable of registering the font right away. This part was also missing from the Mac implementation and this patch implements it by moving the common registration code from a CTFontDescriptorRef out into a separate method, called from populateFontDatabase() as well as addApplicationFont(). Task-number: QTBUG-23062 Change-Id: Ide5e6bf277d99f3cab50ee0d4631cc3fba6d0d45 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>bb10
parent
c6ccd27818
commit
3745b0ca12
|
|
@ -176,6 +176,10 @@ QCoreTextFontDatabase::~QCoreTextFontDatabase()
|
|||
|
||||
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();
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
QCFType<CTFontCollectionRef> collection = CTFontCollectionCreateFromAvailableFonts(0);
|
||||
|
|
@ -186,84 +190,89 @@ void QCoreTextFontDatabase::populateFontDatabase()
|
|||
if (! fonts)
|
||||
return;
|
||||
|
||||
QString foundryName = QLatin1String("CoreText");
|
||||
const int numFonts = CFArrayGetCount(fonts);
|
||||
for (int i = 0; i < numFonts; ++i) {
|
||||
CTFontDescriptorRef font = (CTFontDescriptorRef) CFArrayGetValueAtIndex(fonts, i);
|
||||
QCFString familyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(font, kCTFontFamilyNameAttribute, NULL);
|
||||
QCFString styleName = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontStyleNameAttribute, NULL);
|
||||
QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
|
||||
QFont::Weight weight = QFont::Normal;
|
||||
QFont::Style style = QFont::StyleNormal;
|
||||
QFont::Stretch stretch = QFont::Unstretched;
|
||||
bool fixedPitch = false;
|
||||
|
||||
if (styles) {
|
||||
if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) {
|
||||
Q_ASSERT(CFNumberIsFloatType(weightValue));
|
||||
double d;
|
||||
if (CFNumberGetValue(weightValue, kCFNumberDoubleType, &d))
|
||||
weight = (d > 0.0) ? QFont::Bold : QFont::Normal;
|
||||
}
|
||||
if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
|
||||
Q_ASSERT(CFNumberIsFloatType(italic));
|
||||
double d;
|
||||
if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) {
|
||||
if (d > 0.0)
|
||||
style = QFont::StyleItalic;
|
||||
}
|
||||
}
|
||||
if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) {
|
||||
int d;
|
||||
if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) {
|
||||
if (d & kCTFontMonoSpaceTrait)
|
||||
fixedPitch = true;
|
||||
if (d & kCTFontExpandedTrait)
|
||||
stretch = QFont::Expanded;
|
||||
else if (d & kCTFontCondensedTrait)
|
||||
stretch = QFont::Condensed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pixelSize = 0;
|
||||
if (QCFType<CFNumberRef> size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) {
|
||||
if (CFNumberIsFloatType(size)) {
|
||||
double d;
|
||||
CFNumberGetValue(size, kCFNumberDoubleType, &d);
|
||||
pixelSize = d;
|
||||
} else {
|
||||
CFNumberGetValue(size, kCFNumberIntType, &pixelSize);
|
||||
}
|
||||
}
|
||||
|
||||
QSupportedWritingSystems writingSystems;
|
||||
if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) {
|
||||
CFIndex length = CFArrayGetCount(languages);
|
||||
for (int i = 1; i < LanguageCount; ++i) {
|
||||
if (!languageForWritingSystem[i])
|
||||
continue;
|
||||
QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII);
|
||||
if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang))
|
||||
writingSystems.setSupported(QFontDatabase::WritingSystem(i));
|
||||
}
|
||||
}
|
||||
|
||||
CFRetain(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);
|
||||
populateFromDescriptor(font);
|
||||
}
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
|
||||
{
|
||||
QString foundryName = QStringLiteral("CoreText");
|
||||
QCFString familyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(font, kCTFontFamilyNameAttribute, NULL);
|
||||
QCFString styleName = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontStyleNameAttribute, NULL);
|
||||
QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
|
||||
QFont::Weight weight = QFont::Normal;
|
||||
QFont::Style style = QFont::StyleNormal;
|
||||
QFont::Stretch stretch = QFont::Unstretched;
|
||||
bool fixedPitch = false;
|
||||
|
||||
if (styles) {
|
||||
if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) {
|
||||
Q_ASSERT(CFNumberIsFloatType(weightValue));
|
||||
double d;
|
||||
if (CFNumberGetValue(weightValue, kCFNumberDoubleType, &d))
|
||||
weight = (d > 0.0) ? QFont::Bold : QFont::Normal;
|
||||
}
|
||||
if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
|
||||
Q_ASSERT(CFNumberIsFloatType(italic));
|
||||
double d;
|
||||
if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) {
|
||||
if (d > 0.0)
|
||||
style = QFont::StyleItalic;
|
||||
}
|
||||
}
|
||||
if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) {
|
||||
int d;
|
||||
if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) {
|
||||
if (d & kCTFontMonoSpaceTrait)
|
||||
fixedPitch = true;
|
||||
if (d & kCTFontExpandedTrait)
|
||||
stretch = QFont::Expanded;
|
||||
else if (d & kCTFontCondensedTrait)
|
||||
stretch = QFont::Condensed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pixelSize = 0;
|
||||
if (QCFType<CFNumberRef> size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) {
|
||||
if (CFNumberIsFloatType(size)) {
|
||||
double d;
|
||||
CFNumberGetValue(size, kCFNumberDoubleType, &d);
|
||||
pixelSize = d;
|
||||
} else {
|
||||
CFNumberGetValue(size, kCFNumberIntType, &pixelSize);
|
||||
}
|
||||
}
|
||||
|
||||
QSupportedWritingSystems writingSystems;
|
||||
if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) {
|
||||
CFIndex length = CFArrayGetCount(languages);
|
||||
for (int i = 1; i < LanguageCount; ++i) {
|
||||
if (!languageForWritingSystem[i])
|
||||
continue;
|
||||
QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII);
|
||||
if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang))
|
||||
writingSystems.setSupported(QFontDatabase::WritingSystem(i));
|
||||
}
|
||||
}
|
||||
|
||||
CFRetain(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)
|
||||
{
|
||||
CFRelease(CTFontDescriptorRef(handle));
|
||||
|
|
@ -473,6 +482,7 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData
|
|||
bool success = CTFontManagerRegisterGraphicsFont(cgFont, &error);
|
||||
if (success) {
|
||||
font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL);
|
||||
m_applicationGraphicsFonts.append(QCFType<CGFontRef>::constructFromGet(cgFont));
|
||||
} else {
|
||||
NSLog(@"Unable to register font: %@", error);
|
||||
CFRelease(error);
|
||||
|
|
@ -484,12 +494,13 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData
|
|||
QCFType<CFURLRef> fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false);
|
||||
bool success = CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error);
|
||||
if (success) {
|
||||
const void *keys[] = { fontURL };
|
||||
const void *values[] = { kCTFontURLAttribute };
|
||||
const void *keys[] = { kCTFontURLAttribute };
|
||||
const void *values[] = { fontURL };
|
||||
QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(NULL, keys, values, 1,
|
||||
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithAttributes(attributes);
|
||||
font = CTFontCreateWithFontDescriptor(descriptor, 0.0, NULL);
|
||||
m_applicationURLFonts.append(QCFType<CFURLRef>::constructFromGet(fontURL));
|
||||
} else {
|
||||
NSLog(@"Unable to register font: %@", error);
|
||||
CFRelease(error);
|
||||
|
|
@ -499,6 +510,10 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData
|
|||
if (font) {
|
||||
QStringList families;
|
||||
families.append(QCFString(CTFontCopyFamilyName(font)));
|
||||
|
||||
QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font);
|
||||
populateFromDescriptor(descriptor);
|
||||
|
||||
CFRelease(font);
|
||||
return families;
|
||||
}
|
||||
|
|
@ -534,9 +549,12 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData
|
|||
QStringList families;
|
||||
for (int i = 0; i < containedFonts.size(); ++i) {
|
||||
QCFType<CTFontRef> font = CTFontCreateWithPlatformFont(containedFonts[i], 12.0, NULL, NULL);
|
||||
QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font);
|
||||
populateFromDescriptor(descriptor);
|
||||
families.append(QCFString(CTFontCopyFamilyName(font)));
|
||||
}
|
||||
|
||||
m_applicationFonts.append(fontContainer);
|
||||
return families;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -569,5 +587,28 @@ QList<int> QCoreTextFontDatabase::standardSizes() const
|
|||
return ret;
|
||||
}
|
||||
|
||||
void QCoreTextFontDatabase::removeApplicationFonts()
|
||||
{
|
||||
#ifdef Q_OS_MACX
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
|
||||
if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
|
||||
CFErrorRef error;
|
||||
for (int i = 0; i < m_applicationGraphicsFonts.count(); ++i)
|
||||
CTFontManagerUnregisterGraphicsFont(m_applicationGraphicsFonts[i], &error);
|
||||
m_applicationGraphicsFonts.clear();
|
||||
|
||||
for (int i = 0; i < m_applicationURLFonts.count(); ++i)
|
||||
CTFontManagerUnregisterFontsForURL(m_applicationURLFonts[i], kCTFontManagerScopeProcess, &error);
|
||||
m_applicationURLFonts.clear();
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < m_applicationFonts.count(); ++i)
|
||||
ATSFontDeactivate(m_applicationFonts[i], 0, kATSOptionFlagsDoNotNotify);
|
||||
m_applicationFonts.clear();
|
||||
ATSFontNotify(kATSFontNotifyActionFontsChanged, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@
|
|||
#define QCORETEXTFONTDATABASE_H
|
||||
|
||||
#include <qpa/qplatformfontdatabase.h>
|
||||
#include <private/qcore_mac_p.h>
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#else
|
||||
#include <CoreText/CoreText.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -63,9 +71,21 @@ public:
|
|||
QList<int> standardSizes() const;
|
||||
|
||||
private:
|
||||
void populateFromDescriptor(CTFontDescriptorRef font);
|
||||
|
||||
mutable QString defaultFontName;
|
||||
mutable QHash<QString, QString> psNameToFamily;
|
||||
mutable QHash<QString, QString> familyNameToPsName;
|
||||
|
||||
void removeApplicationFonts();
|
||||
#ifdef Q_OS_MACX
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
|
||||
QVector<QCFType<CGFontRef> > m_applicationGraphicsFonts;
|
||||
QVector<QCFType<CFURLRef> > m_applicationURLFonts;
|
||||
#else
|
||||
QVector<ATSFontContainerRef> m_applicationFonts;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -253,11 +253,8 @@ void tst_QFontDatabase::addAppFont()
|
|||
return;
|
||||
#endif
|
||||
QCOMPARE(fontDbChangedSpy.count(), 1);
|
||||
// addApplicationFont is supported on Mac, don't skip the test if it breaks.
|
||||
#ifndef Q_OS_MAC
|
||||
if (id == -1)
|
||||
QSKIP("Skip the test since app fonts are not supported on this system");
|
||||
#endif
|
||||
|
||||
const QStringList addedFamilies = QFontDatabase::applicationFontFamilies(id);
|
||||
QVERIFY(!addedFamilies.isEmpty());
|
||||
|
|
@ -272,9 +269,6 @@ void tst_QFontDatabase::addAppFont()
|
|||
QVERIFY(QFontDatabase::removeApplicationFont(id));
|
||||
QCOMPARE(fontDbChangedSpy.count(), 2);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QEXPECT_FAIL("font file", "QTBUG-23062", Continue);
|
||||
#endif
|
||||
QCOMPARE(db.families(), oldFamilies);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue