diff options
Diffstat (limited to 'src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm')
-rw-r--r-- | src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm | 174 |
1 files changed, 144 insertions, 30 deletions
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index be70092010..0af779097c 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -33,6 +33,8 @@ #include "qglobal.h" +#include <sys/param.h> + #if defined(Q_OS_MACX) #import <Cocoa/Cocoa.h> #import <IOKit/graphics/IOGraphicsLib.h> @@ -43,23 +45,13 @@ #include "qcoretextfontdatabase_p.h" #include "qfontengine_coretext_p.h" #include <QtCore/QSettings> -#include <QtGui/QGuiApplication> #include <QtCore/QtEndian> +#ifndef QT_NO_FREETYPE +#include <QtGui/private/qfontengine_ft_p.h> +#endif QT_BEGIN_NAMESPACE -namespace { -class AutoReleasePool -{ -public: - AutoReleasePool(): pool([[NSAutoreleasePool alloc] init]) {} - ~AutoReleasePool() { [pool release]; } - -private: - NSAutoreleasePool *pool; -}; -} - // this could become a list of all languages used for each writing // system, instead of using the single most common language. static const char *languageForWritingSystem[] = { @@ -114,8 +106,12 @@ static NSInteger languageMapSort(id obj1, id obj2, void *context) } #endif -QCoreTextFontDatabase::QCoreTextFontDatabase() +QCoreTextFontDatabase::QCoreTextFontDatabase(bool useFreeType) +#ifndef QT_NO_FREETYPE + : m_useFreeType(useFreeType) +#endif { + Q_UNUSED(useFreeType) #ifdef Q_OS_MACX QSettings appleSettings(QLatin1String("apple.com")); QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold")); @@ -360,22 +356,56 @@ void QCoreTextFontDatabase::releaseHandle(void *handle) CFRelease(CTFontDescriptorRef(handle)); } +#ifndef QT_NO_FREETYPE +static QByteArray filenameForCFUrl(CFURLRef url) +{ + // The on-stack buffer prevents that a QByteArray allocated for the worst case (MAXPATHLEN) + // stays around for the lifetime of the font. Additionally, it helps to move the char + // signedness cast to an acceptable place. + uchar buffer[MAXPATHLEN]; + QByteArray filename; + + if (!CFURLGetFileSystemRepresentation(url, true, buffer, sizeof(buffer))) { + qWarning("QCoreTextFontDatabase::filenameForCFUrl: could not resolve file for URL %s", + qPrintable(QString::fromCFString(CFURLGetString(url)))); + } else { + QCFType<CFStringRef> scheme = CFURLCopyScheme(url); + if (QString::fromCFString(scheme) == QLatin1String("qrc")) + filename = ":"; + + filename += reinterpret_cast<char *>(buffer); + } + + return filename; +} +#endif + extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef); QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr) { - qreal scaledPointSize = f.pixelSize; + CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(usrPtr); + +#ifndef QT_NO_FREETYPE + if (m_useFreeType) { + QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute))); - // When 96 DPI is forced, the Mac plugin will use DPI 72 for some - // fonts (hardcoded in qcocoaintegration.mm) and 96 for others. This - // discrepancy makes it impossible to find the correct point size - // here without having the DPI used for the font. Until a proper - // solution (requiring API change) can be made, we simply fall back - // to passing in the point size to retain old behavior. - if (QGuiApplication::testAttribute(Qt::AA_Use96Dpi)) - scaledPointSize = f.pointSize; + QByteArray filename; + if (url) + filename = filenameForCFUrl(url); + + return freeTypeFontEngine(f, filename); + } +#endif + + // Since we do not pass in the destination DPI to CoreText when making + // the font, we need to pass in a point size which is scaled to include + // the DPI. The default DPI for the screen is 72, thus the scale factor + // is destinationDpi / 72, but since pixelSize = pointSize / 72 * dpi, + // the pixelSize is actually the scaled point size for the destination + // DPI, and we can use that directly. + qreal scaledPointSize = f.pixelSize; - CTFontDescriptorRef descriptor = (CTFontDescriptorRef) usrPtr; CGAffineTransform matrix = qt_transform_from_fontdef(f); CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix); if (font) { @@ -397,6 +427,29 @@ static void releaseFontData(void* info, const void* data, size_t size) QFontEngine *QCoreTextFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { +#ifndef QT_NO_FREETYPE + if (m_useFreeType) { + QByteArray *fontDataCopy = new QByteArray(fontData); + QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy, + fontDataCopy->constData(), fontDataCopy->size(), releaseFontData); + QCFType<CGFontRef> cgFont(CGFontCreateWithDataProvider(dataProvider)); + + if (!cgFont) { + qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed"); + return Q_NULLPTR; + } + + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + fontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + fontDef.hintingPreference = hintingPreference; + CGAffineTransform transform = qt_transform_from_fontdef(fontDef); + QCFType<CTFontRef> ctFont(CTFontCreateWithGraphicsFont(cgFont, fontDef.pixelSize, &transform, Q_NULLPTR)); + QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontCopyAttribute(ctFont, kCTFontURLAttribute))); + return freeTypeFontEngine(fontDef, filenameForCFUrl(url), fontData); + } +#endif + Q_UNUSED(hintingPreference); QByteArray* fontDataCopy = new QByteArray(fontData); @@ -453,7 +506,7 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo Q_UNUSED(style); Q_UNUSED(script); - AutoReleasePool pool; + QMacAutoReleasePool pool; static QHash<QString, QStringList> fallbackLists; @@ -568,10 +621,36 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo } #if HAVE_CORETEXT -static CFArrayRef createDescriptorArrayForFont(CTFontRef font) +static CFArrayRef createDescriptorArrayForFont(CTFontRef font, const QString &fileName = QString()) { CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(array, QCFType<CTFontDescriptorRef>(CTFontCopyFontDescriptor(font))); + QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font); + + Q_UNUSED(fileName) +#ifndef QT_NO_FREETYPE + // 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 if (!fileName.isEmpty()) { + // 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); + } +#endif + + CFArrayAppendValue(array, descriptor); return array; } #endif @@ -592,7 +671,11 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData if (cgFont) { if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) { QCFType<CTFontRef> font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL); - fonts = createDescriptorArrayForFont(font); + fonts = createDescriptorArrayForFont(font +#ifndef QT_NO_FREETYPE + , m_useFreeType ? fileName : QString() +#endif + ); m_applicationFonts.append(QVariant::fromValue(QCFType<CGFontRef>::constructFromGet(cgFont))); } } @@ -638,8 +721,8 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData kATSOptionFlagsDefault, &fontContainer); } else { FSRef ref; - OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref); - if (qt_mac_create_fsref(fileName, &ref) != noErr) + if (FSPathMakeRef(reinterpret_cast<const UInt8 *>(fileName.toUtf8().constData()), + &ref, 0) != noErr) return QStringList(); e = ATSFontActivateFromFileReference(&ref, kATSFontContextLocal, kATSFontFormatUnspecified, 0, kATSOptionFlagsDefault, &fontContainer); @@ -892,5 +975,36 @@ void QCoreTextFontDatabase::removeApplicationFonts() #endif } +#ifndef QT_NO_FREETYPE +QFontEngine *QCoreTextFontDatabase::freeTypeFontEngine(const QFontDef &fontDef, const QByteArray &filename, + const QByteArray &fontData) +{ + QFontEngine::FaceId faceId; + faceId.filename = filename; + const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); + + QScopedPointer<QFontEngineFT> engine(new QFontEngineFT(fontDef)); + QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono; + if (antialias) { + QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint(); + if (subpixelType == QFontEngine::Subpixel_None || (fontDef.styleStrategy & QFont::NoSubpixelAntialias)) { + format = QFontEngineFT::Format_A8; + engine->subpixelType = QFontEngine::Subpixel_None; + } else { + format = QFontEngineFT::Format_A32; + engine->subpixelType = subpixelType; + } + } + + if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) { + qWarning() << "QCoreTextFontDatabase::freeTypefontEngine Failed to create engine"; + return Q_NULLPTR; + } + engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference)); + + return engine.take(); +} +#endif + QT_END_NAMESPACE |