Teach CoreText font db to handle application font files with multiple fonts

The ATS code path already did this, by enumerating all the fonts in the
resolved collection. The CoreText code path assumed that registering a
font URL would only add a single font.

We now use CTFontManagerRegisterFontsForURL to enumerate all fonts
that were added. This functionality is not available for fonts based
on a data provider.

As part of implementing the patch the code was simplified to re-use
logic between the different ways of resolving font descriptors from
a file or byte array.

Change-Id: I6eb15df939d03dc588a87e46f39bd54e56b50643
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
This commit is contained in:
Tor Arne Vestbø 2014-01-22 13:41:26 +01:00 committed by The Qt Project
parent 5173589b79
commit c76a6fe2c4

View File

@ -477,99 +477,91 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
#ifdef Q_OS_MACX #ifdef Q_OS_MACX
QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
{ {
QCFType<CFArrayRef> fonts;
QStringList families;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
CTFontRef font = NULL; CFErrorRef error = 0;
if (!fontData.isEmpty()) { if (!fontData.isEmpty()) {
QByteArray* fontDataCopy = new QByteArray(fontData); QByteArray* fontDataCopy = new QByteArray(fontData);
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy, QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
fontDataCopy->constData(), fontDataCopy->size(), releaseFontData); fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider); QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider);
if (cgFont) { if (cgFont) {
CFErrorRef error; if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) {
bool success = CTFontManagerRegisterGraphicsFont(cgFont, &error); CFMutableArrayRef singleFontArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (success) { QCFType<CTFontRef> font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL);
font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL); CFArrayAppendValue(singleFontArray, QCFType<CTFontDescriptorRef>(CTFontCopyFontDescriptor(font)));
fonts = singleFontArray;
m_applicationFonts.append(QVariant::fromValue(QCFType<CGFontRef>::constructFromGet(cgFont))); m_applicationFonts.append(QVariant::fromValue(QCFType<CGFontRef>::constructFromGet(cgFont)));
} else {
NSLog(@"Unable to register font: %@", error);
CFRelease(error);
} }
CGFontRelease(cgFont);
} }
} else { } else {
CFErrorRef error;
QCFType<CFURLRef> fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false); QCFType<CFURLRef> fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false);
bool success = CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error); if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error)) {
if (success) { fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL);
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_applicationFonts.append(QVariant::fromValue(QCFType<CFURLRef>::constructFromGet(fontURL))); m_applicationFonts.append(QVariant::fromValue(QCFType<CFURLRef>::constructFromGet(fontURL)));
} else {
NSLog(@"Unable to register font: %@", error);
CFRelease(error);
} }
} }
if (font) { if (error) {
QStringList families; NSLog(@"Unable to register font: %@", error);
families.append(QCFString(CTFontCopyFamilyName(font))); CFRelease(error);
QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font);
populateFromDescriptor(descriptor);
CFRelease(font);
return families;
} }
} else } else
#endif #endif
{ {
ATSFontContainerRef fontContainer; ATSFontContainerRef fontContainer;
OSStatus e; OSStatus e;
if (!fontData.isEmpty()) { if (!fontData.isEmpty()) {
e = ATSFontActivateFromMemory((void *) fontData.constData(), fontData.size(), e = ATSFontActivateFromMemory((void *) fontData.constData(), fontData.size(),
kATSFontContextLocal, kATSFontFormatUnspecified, NULL, kATSFontContextLocal, kATSFontFormatUnspecified, NULL,
kATSOptionFlagsDefault, &fontContainer); kATSOptionFlagsDefault, &fontContainer);
} else { } else {
FSRef ref; FSRef ref;
OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref); OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref);
if (qt_mac_create_fsref(fileName, &ref) != noErr) if (qt_mac_create_fsref(fileName, &ref) != noErr)
return QStringList(); return QStringList();
e = ATSFontActivateFromFileReference(&ref, kATSFontContextLocal, kATSFontFormatUnspecified, 0, e = ATSFontActivateFromFileReference(&ref, kATSFontContextLocal, kATSFontFormatUnspecified, 0,
kATSOptionFlagsDefault, &fontContainer); kATSOptionFlagsDefault, &fontContainer);
}
if (e == noErr) {
ItemCount fontCount = 0;
e = ATSFontFindFromContainer(fontContainer, kATSOptionFlagsDefault, 0, 0, &fontCount);
if (e != noErr)
return QStringList();
QVarLengthArray<ATSFontRef> containedFonts(fontCount);
e = ATSFontFindFromContainer(fontContainer, kATSOptionFlagsDefault, fontCount, containedFonts.data(), &fontCount);
if (e != noErr)
return QStringList();
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(QVariant::fromValue(fontContainer)); if (e == noErr) {
return families; ItemCount fontCount = 0;
} e = ATSFontFindFromContainer(fontContainer, kATSOptionFlagsDefault, 0, 0, &fontCount);
if (e != noErr)
return QStringList();
QVarLengthArray<ATSFontRef> containedFonts(fontCount);
e = ATSFontFindFromContainer(fontContainer, kATSOptionFlagsDefault, fontCount, containedFonts.data(), &fontCount);
if (e != noErr)
return QStringList();
CFMutableArrayRef fontsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
for (int i = 0; i < containedFonts.size(); ++i) {
QCFType<CTFontRef> font = CTFontCreateWithPlatformFont(containedFonts[i], 12.0, NULL, NULL);
CFArrayAppendValue(fontsArray, QCFType<CTFontDescriptorRef>(CTFontCopyFontDescriptor(font)));
}
fonts = fontsArray;
m_applicationFonts.append(QVariant::fromValue(fontContainer));
}
} }
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<CFStringRef> familyName = CFStringRef(CTFontDescriptorCopyLocalizedAttribute(fontDescriptor, kCTFontFamilyNameAttribute, NULL));
families.append(QCFString(familyName));
}
}
return families;
} }
#endif #endif