diff options
Diffstat (limited to 'src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm')
-rw-r--r-- | src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm | 211 |
1 files changed, 71 insertions, 140 deletions
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index ce9b61ba4c..d89a81be6b 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<CFArrayRef> familyNames = availableFamilyNames(); const int numberOfFamilies = CFArrayGetCount(familyNames); for (int i = 0; i < numberOfFamilies; ++i) { @@ -255,6 +251,24 @@ struct FontDescription { QSupportedWritingSystems writingSystems; }; +#ifndef QT_NO_DEBUG_STREAM +Q_DECL_UNUSED static inline QDebug operator<<(QDebug debug, const FontDescription &fd) +{ + QDebugStateSaver saver(debug); + return debug.nospace() << "FontDescription(" + << "familyName=" << QString(fd.familyName) + << ", styleName=" << QString(fd.styleName) + << ", foundry=" << fd.foundryName + << ", weight=" << fd.weight + << ", style=" << fd.style + << ", stretch=" << fd.stretch + << ", pixelSize=" << fd.pixelSize + << ", fixedPitch=" << fd.fixedPitch + << ", writingSystems=" << fd.writingSystems + << ")"; +} +#endif + static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) { QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute); @@ -358,9 +372,22 @@ void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font, con fd.pixelSize, fd.fixedPitch, fd.writingSystems, (void *) font); } +static NSString * const kQtFontDataAttribute = @"QtFontDataAttribute"; + +template <typename T> +T *descriptorAttribute(CTFontDescriptorRef descriptor, CFStringRef name) +{ + return [static_cast<T *>(CTFontDescriptorCopyAttribute(descriptor, name)) autorelease]; +} + void QCoreTextFontDatabase::releaseHandle(void *handle) { - CFRelease(CTFontDescriptorRef(handle)); + CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(handle); + if (NSValue *fontDataValue = descriptorAttribute<NSValue>(descriptor, (CFStringRef)kQtFontDataAttribute)) { + QByteArray *fontData = static_cast<QByteArray *>(fontDataValue.pointerValue); + delete fontData; + } + CFRelease(descriptor); } extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef); @@ -395,61 +422,31 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const { CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(usrPtr); - QByteArray filename; - if (NSURL *url = [static_cast<NSURL *>(CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute)) autorelease]) { - if ([url.scheme isEqual:@"qrc"]) - filename = ":"; - else if (!url.fileURL) - qWarning() << "QFontDatabase: Unknown scheme" << url.scheme << "in font descriptor URL"; + if (NSURL *url = descriptorAttribute<NSURL>(descriptor, kCTFontURLAttribute)) { + Q_ASSERT(url.fileURL); + QFontEngine::FaceId faceId; + faceId.filename = QString::fromNSString(url.path).toUtf8(); + return QFontEngineFT::create(fontDef, faceId); - filename += QString::fromNSString(url.path).toUtf8(); + } else if (NSValue *fontDataValue = descriptorAttribute<NSValue>(descriptor, (CFStringRef)kQtFontDataAttribute)) { + QByteArray *fontData = static_cast<QByteArray *>(fontDataValue.pointerValue); + return QFontEngineFT::create(*fontData, fontDef.pixelSize, + static_cast<QFont::HintingPreference>(fontDef.hintingPreference)); } - Q_ASSERT(!filename.isEmpty()); - - QFontEngine::FaceId faceId; - faceId.filename = filename; - return QFontEngineFT::create(fontDef, faceId); + Q_UNREACHABLE(); } #endif -static void releaseFontData(void* info, const void* data, size_t size) -{ - Q_UNUSED(data); - Q_UNUSED(size); - delete (QByteArray*)info; -} - -template <> -QFontEngine *QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) +template <class T> +QFontEngine *QCoreTextFontDatabaseEngineFactory<T>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { - Q_UNUSED(hintingPreference); - - QByteArray* fontDataCopy = new QByteArray(fontData); - QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy, - fontDataCopy->constData(), fontDataCopy->size(), releaseFontData); - - CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider); - - QFontEngine *fontEngine = NULL; - if (cgFont == NULL) { - qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed"); - } else { - QFontDef def; - def.pixelSize = pixelSize; - def.pointSize = pixelSize * 72.0 / qt_defaultDpi(); - fontEngine = new QCoreTextFontEngine(cgFont, def); - CFRelease(cgFont); - } - - return fontEngine; + return T::create(fontData, pixelSize, hintingPreference); } +// Explicitly instantiate so that we don't need the plugin to involve FreeType +template class QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>; #ifndef QT_NO_FREETYPE -template <> -QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - return QFontEngineFT::create(fontData, pixelSize, hintingPreference); -} +template class QCoreTextFontDatabaseEngineFactory<QFontEngineFT>; #endif QFont::StyleHint styleHintFromNSString(NSString *style) @@ -584,90 +581,41 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo return fallbackLists[styleLookupKey.arg(styleHint)]; } -template <> -CFArrayRef QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::createDescriptorArrayForFont(CTFontRef font, 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) -{ - 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 - // agreeable to OSX. - if (!fileName.isEmpty()) { - QCFType<CFURLRef> fontURL; - - if (fileName.startsWith(QLatin1String(":/"))) { - // QUrl::fromLocalFile() doesn't accept qrc pseudo-paths like ":/fonts/myfont.ttf". - // Therefore construct from QString with the qrc:// scheme -> "qrc:///fonts/myfont.ttf". - fontURL = QUrl(QStringLiteral("qrc://") + fileName.mid(1)).toCFURL(); - } else { - // At this point we hope that filename is in a format that QUrl can handle. - fontURL = QUrl::fromLocalFile(fileName).toCFURL(); - } - - QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(attributes, kCTFontURLAttribute, fontURL); - descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, attributes); - } - - CFArrayAppendValue(array, descriptor); - return array; -} -#endif - 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))); - } + QCFType<CFDataRef> fontDataReference = fontData.toRawCFData(); + if (QCFType<CTFontDescriptorRef> descriptor = CTFontManagerCreateFontDescriptorFromData(fontDataReference)) { + // There's no way to get the data back out of a font descriptor created with + // CTFontManagerCreateFontDescriptorFromData, so we attach the data manually. + NSDictionary *attributes = @{ kQtFontDataAttribute : [NSValue valueWithPointer:new QByteArray(fontData)] }; + descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, (CFDictionaryRef)attributes); + CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(array, descriptor); + fonts = array; } } 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(); - 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)); - } + 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)); } + // 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 +794,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 |