From ce2bc0e2d5b1d647db1e1726ecd434cc8a55accf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 31 Mar 2020 12:25:59 +0200 Subject: Move CoreText font engine/database to QtGui Task-number: QTBUG-83255 Change-Id: Id34ed1759fdebbb1d09e51009f0370736002167c Reviewed-by: Lars Knoll --- src/platformsupport/fontdatabases/CMakeLists.txt | 21 - .../fontdatabases/fontdatabases.pro | 4 - src/platformsupport/fontdatabases/mac/coretext.pri | 19 - .../fontdatabases/mac/qcoretextfontdatabase.mm | 798 --------------- .../fontdatabases/mac/qcoretextfontdatabase_p.h | 116 --- .../fontdatabases/mac/qfontengine_coretext.mm | 1060 -------------------- .../fontdatabases/mac/qfontengine_coretext_p.h | 159 --- src/platformsupport/platformsupport.pro | 2 +- 8 files changed, 1 insertion(+), 2178 deletions(-) delete mode 100644 src/platformsupport/fontdatabases/mac/coretext.pri delete mode 100644 src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm delete mode 100644 src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h delete mode 100644 src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm delete mode 100644 src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h (limited to 'src/platformsupport') diff --git a/src/platformsupport/fontdatabases/CMakeLists.txt b/src/platformsupport/fontdatabases/CMakeLists.txt index 01802f99fd..913e9ba14e 100644 --- a/src/platformsupport/fontdatabases/CMakeLists.txt +++ b/src/platformsupport/fontdatabases/CMakeLists.txt @@ -25,27 +25,6 @@ qt_add_module(FontDatabaseSupport ## Scopes: ##################################################################### -qt_extend_target(FontDatabaseSupport CONDITION APPLE - SOURCES - mac/qcoretextfontdatabase.mm mac/qcoretextfontdatabase_p.h - mac/qfontengine_coretext.mm mac/qfontengine_coretext_p.h - LIBRARIES - ${FWCoreFoundation} - ${FWCoreGraphics} - ${FWCoreText} - ${FWFoundation} -) - -qt_extend_target(FontDatabaseSupport CONDITION MACOS - LIBRARIES - ${FWAppKit} -) - -qt_extend_target(FontDatabaseSupport CONDITION APPLE AND NOT MACOS - LIBRARIES - ${FWUIKit} -) - qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_freetype LIBRARIES WrapFreetype::WrapFreetype diff --git a/src/platformsupport/fontdatabases/fontdatabases.pro b/src/platformsupport/fontdatabases/fontdatabases.pro index f102bb8e9d..d90ec31685 100644 --- a/src/platformsupport/fontdatabases/fontdatabases.pro +++ b/src/platformsupport/fontdatabases/fontdatabases.pro @@ -7,10 +7,6 @@ CONFIG += static internal_module DEFINES += QT_NO_CAST_FROM_ASCII PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h -darwin { - include($$PWD/mac/coretext.pri) -} - unix { include($$PWD/genericunix/genericunix.pri) } diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri deleted file mode 100644 index 31470ae583..0000000000 --- a/src/platformsupport/fontdatabases/mac/coretext.pri +++ /dev/null @@ -1,19 +0,0 @@ -HEADERS += $$PWD/qcoretextfontdatabase_p.h $$PWD/qfontengine_coretext_p.h -OBJECTIVE_SOURCES += $$PWD/qfontengine_coretext.mm $$PWD/qcoretextfontdatabase.mm - -LIBS_PRIVATE += \ - -framework CoreFoundation \ - -framework CoreGraphics \ - -framework CoreText \ - -framework Foundation - -macos: \ - LIBS_PRIVATE += -framework AppKit -else: \ - LIBS_PRIVATE += -framework UIKit - -CONFIG += watchos_coretext - -qtConfig(freetype) { - QMAKE_USE_PRIVATE += freetype -} diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm deleted file mode 100644 index c0f1bd4d8d..0000000000 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ /dev/null @@ -1,798 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglobal.h" - -#include - -#if defined(Q_OS_MACOS) -#import -#import -#elif defined(QT_PLATFORM_UIKIT) -#import -#endif - -#include - -#include "qcoretextfontdatabase_p.h" -#include "qfontengine_coretext_p.h" -#if QT_CONFIG(settings) -#include -#endif -#include -#ifndef QT_NO_FREETYPE -#include -#endif - -QT_BEGIN_NAMESPACE - -// 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[] = { - 0, // Any - "en", // Latin - "el", // Greek - "ru", // Cyrillic - "hy", // Armenian - "he", // Hebrew - "ar", // Arabic - "syr", // Syriac - "div", // Thaana - "hi", // Devanagari - "bn", // Bengali - "pa", // Gurmukhi - "gu", // Gujarati - "or", // Oriya - "ta", // Tamil - "te", // Telugu - "kn", // Kannada - "ml", // Malayalam - "si", // Sinhala - "th", // Thai - "lo", // Lao - "bo", // Tibetan - "my", // Myanmar - "ka", // Georgian - "km", // Khmer - "zh-Hans", // SimplifiedChinese - "zh-Hant", // TraditionalChinese - "ja", // Japanese - "ko", // Korean - "vi", // Vietnamese - 0, // Symbol - "sga", // Ogham - "non", // Runic - "man" // N'Ko -}; -enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) }; - -QCoreTextFontDatabase::QCoreTextFontDatabase() - : m_hasPopulatedAliases(false) -{ -} - -QCoreTextFontDatabase::~QCoreTextFontDatabase() -{ - for (CTFontDescriptorRef ref : qAsConst(m_systemFontDescriptors)) - CFRelease(ref); -} - -void QCoreTextFontDatabase::populateFontDatabase() -{ - qCDebug(lcQpaFonts) << "Populating font database..."; - QElapsedTimer elapsed; - if (lcQpaFonts().isDebugEnabled()) - elapsed.start(); - - QCFType familyNames = CTFontManagerCopyAvailableFontFamilyNames(); - for (NSString *familyName in familyNames.as()) - QPlatformFontDatabase::registerFontFamily(QString::fromNSString(familyName)); - - qCDebug(lcQpaFonts) << "Populating available families took" << elapsed.restart() << "ms"; - - // Force creating the theme fonts to get the descriptors in m_systemFontDescriptors - if (m_themeFonts.isEmpty()) - (void)themeFonts(); - - qCDebug(lcQpaFonts) << "Resolving theme fonts took" << elapsed.restart() << "ms"; - - Q_FOREACH (CTFontDescriptorRef fontDesc, m_systemFontDescriptors) - populateFromDescriptor(fontDesc); - - qCDebug(lcQpaFonts) << "Populating system descriptors took" << elapsed.restart() << "ms"; - - Q_ASSERT(!m_hasPopulatedAliases); -} - -bool QCoreTextFontDatabase::populateFamilyAliases(const QString &missingFamily) -{ -#if defined(Q_OS_MACOS) - if (m_hasPopulatedAliases) - return false; - - // There's no API to go from a localized family name to its non-localized - // name, so we have to resort to enumerating all the available fonts and - // doing a reverse lookup. - - qCDebug(lcQpaFonts) << "Populating family aliases..."; - QElapsedTimer elapsed; - elapsed.start(); - - QString nonLocalizedMatch; - QCFType familyNames = CTFontManagerCopyAvailableFontFamilyNames(); - NSFontManager *fontManager = NSFontManager.sharedFontManager; - for (NSString *familyName in familyNames.as()) { - NSString *localizedFamilyName = [fontManager localizedNameForFamily:familyName face:nil]; - if (![localizedFamilyName isEqual:familyName]) { - QString nonLocalizedFamily = QString::fromNSString(familyName); - QString localizedFamily = QString::fromNSString(localizedFamilyName); - QPlatformFontDatabase::registerAliasToFontFamily(nonLocalizedFamily, localizedFamily); - if (localizedFamily == missingFamily) - nonLocalizedMatch = nonLocalizedFamily; - } - } - m_hasPopulatedAliases = true; - - if (lcQpaFonts().isWarningEnabled()) { - QString warningMessage; - QDebug msg(&warningMessage); - - msg << "Populating font family aliases took" << elapsed.restart() << "ms."; - if (!nonLocalizedMatch.isNull()) - msg << "Replace uses of" << missingFamily << "with its non-localized name" << nonLocalizedMatch; - else - msg << "Replace uses of missing font family" << missingFamily << "with one that exists"; - msg << "to avoid this cost."; - - qCWarning(lcQpaFonts) << qPrintable(warningMessage); - } - - return true; -#else - Q_UNUSED(missingFamily); - return false; -#endif -} - -void QCoreTextFontDatabase::populateFamily(const QString &familyName) -{ - QCFType attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, QCFString(familyName)); - QCFType nameOnlyDescriptor = CTFontDescriptorCreateWithAttributes(attributes); - - // A single family might match several different fonts with different styles eg. - QCFType matchingFonts = (CFArrayRef) CTFontDescriptorCreateMatchingFontDescriptors(nameOnlyDescriptor, 0); - if (!matchingFonts) { - qCWarning(lcQpaFonts) << "QCoreTextFontDatabase: Found no matching fonts for family" << familyName; - return; - } - - const int numFonts = CFArrayGetCount(matchingFonts); - for (int i = 0; i < numFonts; ++i) - populateFromDescriptor(CTFontDescriptorRef(CFArrayGetValueAtIndex(matchingFonts, i)), familyName); -} - -void QCoreTextFontDatabase::invalidate() -{ - m_hasPopulatedAliases = false; -} - -struct FontDescription { - QCFString familyName; - QCFString styleName; - QString foundryName; - QFont::Weight weight; - QFont::Style style; - QFont::Stretch stretch; - qreal pointSize; - bool fixedPitch; - 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 - << ", pointSize=" << fd.pointSize - << ", fixedPitch=" << fd.fixedPitch - << ", writingSystems=" << fd.writingSystems - << ")"; -} -#endif - -static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) -{ - QCFType styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute); - - fd->foundryName = QStringLiteral("CoreText"); - fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); - fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute); - fd->weight = QFont::Normal; - fd->style = QFont::StyleNormal; - fd->stretch = QFont::Unstretched; - fd->fixedPitch = false; - - if (QCFType tempFont = CTFontCreateWithFontDescriptor(font, 0.0, 0)) { - uint tag = MAKE_TAG('O', 'S', '/', '2'); - CTFontRef tempFontRef = tempFont; - void *userData = reinterpret_cast(&tempFontRef); - uint length = 128; - QVarLengthArray os2Table(length); - if (QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length) && length >= 86) { - if (length > uint(os2Table.length())) { - os2Table.resize(length); - if (!QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length)) - Q_UNREACHABLE(); - Q_ASSERT(length >= 86); - } - fd->writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast(os2Table.data()), length); - } - } - - if (styles) { - if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) { - double normalizedWeight; - if (CFNumberGetValue(weightValue, kCFNumberFloat64Type, &normalizedWeight)) - fd->weight = QCoreTextFontEngine::qtWeightFromCFWeight(float(normalizedWeight)); - } - if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) { - double d; - if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) { - if (d > 0.0) - fd->style = QFont::StyleItalic; - } - } - if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) { - int d; - if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) { - if (d & kCTFontMonoSpaceTrait) - fd->fixedPitch = true; - if (d & kCTFontExpandedTrait) - fd->stretch = QFont::Expanded; - else if (d & kCTFontCondensedTrait) - fd->stretch = QFont::Condensed; - } - } - } - - if (QCFType size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) { - if (CFNumberIsFloatType(size)) { - double d; - CFNumberGetValue(size, kCFNumberDoubleType, &d); - fd->pointSize = d; - } else { - int i; - CFNumberGetValue(size, kCFNumberIntType, &i); - fd->pointSize = i; - } - } - - if (QCFType 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)) - fd->writingSystems.setSupported(QFontDatabase::WritingSystem(i)); - } - } -} - -void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font, const QString &familyName, QFontDatabasePrivate::ApplicationFont *applicationFont) -{ - FontDescription fd; - getFontDescription(font, &fd); - - // Note: The familyName we are registering, and the family name of the font descriptor, may not - // match, as CTFontDescriptorCreateMatchingFontDescriptors will return descriptors for replacement - // fonts if a font family does not have any fonts available on the system. - QString family = !familyName.isNull() ? familyName : static_cast(fd.familyName); - - if (applicationFont != nullptr) { - QFontDatabasePrivate::ApplicationFont::Properties properties; - properties.familyName = family; - properties.styleName = fd.styleName; - properties.weight = fd.weight; - properties.stretch = fd.stretch; - properties.style = fd.style; - - applicationFont->properties.append(properties); - } - - CFRetain(font); - QPlatformFontDatabase::registerFont(family, fd.styleName, fd.foundryName, fd.weight, fd.style, fd.stretch, - true /* antialiased */, true /* scalable */, 0 /* pixelSize, ignored as font is scalable */, - fd.fixedPitch, fd.writingSystems, (void *)font); -} - -static NSString * const kQtFontDataAttribute = @"QtFontDataAttribute"; - -template -T *descriptorAttribute(CTFontDescriptorRef descriptor, CFStringRef name) -{ - return [static_cast(CTFontDescriptorCopyAttribute(descriptor, name)) autorelease]; -} - -void QCoreTextFontDatabase::releaseHandle(void *handle) -{ - CTFontDescriptorRef descriptor = static_cast(handle); - if (NSValue *fontDataValue = descriptorAttribute(descriptor, (CFStringRef)kQtFontDataAttribute)) { - QByteArray *fontData = static_cast(fontDataValue.pointerValue); - delete fontData; - } - CFRelease(descriptor); -} - -extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef); - -template <> -QFontEngine *QCoreTextFontDatabaseEngineFactory::fontEngine(const QFontDef &fontDef, void *usrPtr) -{ - QCFType descriptor = QCFType::constructFromGet( - static_cast(usrPtr)); - - // 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 = fontDef.pixelSize; - - CGAffineTransform matrix = qt_transform_from_fontdef(fontDef); - if (QCFType font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix)) - return new QCoreTextFontEngine(font, fontDef); - - return nullptr; -} - -#ifndef QT_NO_FREETYPE -template <> -QFontEngine *QCoreTextFontDatabaseEngineFactory::fontEngine(const QFontDef &fontDef, void *usrPtr) -{ - CTFontDescriptorRef descriptor = static_cast(usrPtr); - - if (NSValue *fontDataValue = descriptorAttribute(descriptor, (CFStringRef)kQtFontDataAttribute)) { - QByteArray *fontData = static_cast(fontDataValue.pointerValue); - return QFontEngineFT::create(*fontData, fontDef.pixelSize, - static_cast(fontDef.hintingPreference)); - } else if (NSURL *url = descriptorAttribute(descriptor, kCTFontURLAttribute)) { - Q_ASSERT(url.fileURL); - QFontEngine::FaceId faceId; - faceId.filename = QString::fromNSString(url.path).toUtf8(); - return QFontEngineFT::create(fontDef, faceId); - } - Q_UNREACHABLE(); -} -#endif - -template -QFontEngine *QCoreTextFontDatabaseEngineFactory::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - return T::create(fontData, pixelSize, hintingPreference); -} - -// Explicitly instantiate so that we don't need the plugin to involve FreeType -template class QCoreTextFontDatabaseEngineFactory; -#ifndef QT_NO_FREETYPE -template class QCoreTextFontDatabaseEngineFactory; -#endif - -CTFontDescriptorRef descriptorForFamily(const QString &familyName) -{ - return CTFontDescriptorCreateWithAttributes(CFDictionaryRef(@{ - (id)kCTFontFamilyNameAttribute: familyName.toNSString() - })); -} - -CTFontDescriptorRef descriptorForFamily(const char *familyName) -{ - return descriptorForFamily(QString::fromLatin1(familyName)); -} - -CFArrayRef fallbacksForDescriptor(CTFontDescriptorRef descriptor) -{ - QCFType font = CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr); - if (!font) { - qCWarning(lcQpaFonts) << "Failed to create fallback font for" << descriptor; - return nullptr; - } - - CFArrayRef cascadeList = CFArrayRef(CTFontCopyDefaultCascadeListForLanguages(font, - (CFArrayRef)[NSUserDefaults.standardUserDefaults stringArrayForKey:@"AppleLanguages"])); - - if (!cascadeList) { - qCWarning(lcQpaFonts) << "Failed to create fallback cascade list for" << descriptor; - return nullptr; - } - - return cascadeList; -} - -CFArrayRef QCoreTextFontDatabase::fallbacksForFamily(const QString &family) -{ - if (family.isEmpty()) - return nullptr; - - QCFType fontDescriptor = descriptorForFamily(family); - if (!fontDescriptor) { - qCWarning(lcQpaFonts) << "Failed to create fallback font descriptor for" << family; - return nullptr; - } - - // If the font is not available we want to fall back to the style hint. - // By creating a matching font descriptor we can verify whether the font - // is available or not, and avoid CTFontCreateWithFontDescriptor picking - // a default font for us based on incomplete information. - fontDescriptor = CTFontDescriptorCreateMatchingFontDescriptor(fontDescriptor, 0); - if (!fontDescriptor) - return nullptr; - - return fallbacksForDescriptor(fontDescriptor); -} - -CTFontDescriptorRef descriptorForFontType(CTFontUIFontType uiType) -{ - static const CGFloat kDefaultSizeForRequestedUIType = 0.0; - QCFType ctFont = CTFontCreateUIFontForLanguage( - uiType, kDefaultSizeForRequestedUIType, nullptr); - return CTFontCopyFontDescriptor(ctFont); -} - -CTFontDescriptorRef descriptorForStyle(QFont::StyleHint styleHint) -{ - switch (styleHint) { - case QFont::SansSerif: return descriptorForFamily("Helvetica"); - case QFont::Serif: return descriptorForFamily("Times New Roman"); - case QFont::Monospace: return descriptorForFamily("Menlo"); -#ifdef Q_OS_MACOS - case QFont::Cursive: return descriptorForFamily("Apple Chancery"); -#endif - case QFont::Fantasy: return descriptorForFamily("Zapfino"); - case QFont::TypeWriter: return descriptorForFamily("American Typewriter"); - case QFont::AnyStyle: Q_FALLTHROUGH(); - case QFont::System: return descriptorForFontType(kCTFontUIFontSystem); - default: return nullptr; // No matching font on this platform - } -} - -QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const -{ - Q_UNUSED(style); - - qCDebug(lcQpaFonts).nospace() << "Resolving fallbacks families for" - << (!family.isEmpty() ? qPrintable(QLatin1String(" family '%1' with").arg(family)) : "") - << " style hint " << styleHint; - - QMacAutoReleasePool pool; - - QStringList fallbackList; - - QCFType fallbackFonts = fallbacksForFamily(family); - if (!fallbackFonts || !CFArrayGetCount(fallbackFonts)) { - // We were not able to find a fallback for the specific family, - // or the family was empty, so we fall back to the style hint. - if (!family.isEmpty()) - qCDebug(lcQpaFonts) << "No fallbacks found. Using style hint instead"; - - if (QCFType styleDescriptor = descriptorForStyle(styleHint)) { - CFMutableArrayRef tmp = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(tmp, styleDescriptor); - QCFType styleFallbacks = fallbacksForDescriptor(styleDescriptor); - CFArrayAppendArray(tmp, styleFallbacks, CFRangeMake(0, CFArrayGetCount(styleFallbacks))); - fallbackFonts = tmp; - } - } - - if (!fallbackFonts) - return fallbackList; - - const int numberOfFallbacks = CFArrayGetCount(fallbackFonts); - for (int i = 0; i < numberOfFallbacks; ++i) { - auto fallbackDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fallbackFonts, i)); - auto fallbackFamilyName = QCFString(CTFontDescriptorCopyAttribute(fallbackDescriptor, kCTFontFamilyNameAttribute)); - - if (!isFamilyPopulated(fallbackFamilyName)) { - // We need to populate, or at least register the fallback fonts, - // otherwise the Qt font database may not know they exist. - if (isPrivateFontFamily(fallbackFamilyName)) - const_cast(this)->populateFromDescriptor(fallbackDescriptor); - else - registerFontFamily(fallbackFamilyName); - } - - fallbackList.append(fallbackFamilyName); - } - - // Some fallback fonts will have have an order in the list returned - // by Core Text that would indicate they should be preferred for e.g. - // Arabic, or Emoji, while in reality only supporting a tiny subset - // of the required glyphs, or representing them by question marks. - // Move these to the end, so that the proper fonts are preferred. - for (const char *family : { ".Apple Symbols Fallback", ".Noto Sans Universal" }) { - int index = fallbackList.indexOf(QLatin1String(family)); - if (index >= 0) - fallbackList.move(index, fallbackList.size() - 1); - } - -#if defined(Q_OS_MACOS) - // Since we are only returning a list of default fonts for the current language, we do not - // cover all Unicode completely. This was especially an issue for some of the common script - // symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk - // of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most - // of Unicode 2.1. - if (!fallbackList.contains(QStringLiteral("Arial Unicode MS"))) - fallbackList.append(QStringLiteral("Arial Unicode MS")); - // Since some symbols (specifically Braille) are not in Arial Unicode MS, we - // add Apple Symbols to cover those too. - if (!fallbackList.contains(QStringLiteral("Apple Symbols"))) - fallbackList.append(QStringLiteral("Apple Symbols")); -#endif - - extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &); - fallbackList = qt_sort_families_by_writing_system(script, fallbackList); - - qCDebug(lcQpaFonts).nospace() << "Fallback families ordered by script " << script << ": " << fallbackList; - - return fallbackList; -} - -QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont) -{ - QCFType fonts; - - if (!fontData.isEmpty()) { - QCFType fontDataReference = fontData.toRawCFData(); - if (QCFType 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 fontURL = QUrl::fromLocalFile(fileName).toCFURL(); - fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL); - } - - if (!fonts) - return QStringList(); - - QStringList families; - const int numFonts = CFArrayGetCount(fonts); - for (int i = 0; i < numFonts; ++i) { - CTFontDescriptorRef fontDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fonts, i)); - populateFromDescriptor(fontDescriptor, QString(), applicationFont); - 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; -} - -bool QCoreTextFontDatabase::isPrivateFontFamily(const QString &family) const -{ - if (family.startsWith(QLatin1Char('.')) || family == QLatin1String("LastResort")) - return true; - - return QPlatformFontDatabase::isPrivateFontFamily(family); -} - -static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f) -{ - switch (f) { - case QPlatformTheme::SystemFont: - return kCTFontUIFontSystem; - - case QPlatformTheme::MenuFont: - case QPlatformTheme::MenuBarFont: - case QPlatformTheme::MenuItemFont: - return kCTFontUIFontMenuItem; - - case QPlatformTheme::MessageBoxFont: - return kCTFontUIFontEmphasizedSystem; - - case QPlatformTheme::LabelFont: - return kCTFontUIFontSystem; - - case QPlatformTheme::TipLabelFont: - return kCTFontUIFontToolTip; - - case QPlatformTheme::StatusBarFont: - return kCTFontUIFontSystem; - - case QPlatformTheme::TitleBarFont: - return kCTFontUIFontWindowTitle; - - case QPlatformTheme::MdiSubWindowTitleFont: - return kCTFontUIFontSystem; - - case QPlatformTheme::DockWidgetTitleFont: - return kCTFontUIFontSmallSystem; - - case QPlatformTheme::PushButtonFont: - return kCTFontUIFontPushButton; - - case QPlatformTheme::CheckBoxFont: - case QPlatformTheme::RadioButtonFont: - return kCTFontUIFontSystem; - - case QPlatformTheme::ToolButtonFont: - return kCTFontUIFontSmallToolbar; - - case QPlatformTheme::ItemViewFont: - return kCTFontUIFontSystem; - - case QPlatformTheme::ListViewFont: - return kCTFontUIFontViews; - - case QPlatformTheme::HeaderViewFont: - return kCTFontUIFontSmallSystem; - - case QPlatformTheme::ListBoxFont: - return kCTFontUIFontViews; - - case QPlatformTheme::ComboMenuItemFont: - return kCTFontUIFontSystem; - - case QPlatformTheme::ComboLineEditFont: - return kCTFontUIFontViews; - - case QPlatformTheme::SmallFont: - return kCTFontUIFontSmallSystem; - - case QPlatformTheme::MiniFont: - return kCTFontUIFontMiniSystem; - - case QPlatformTheme::FixedFont: - return kCTFontUIFontUserFixedPitch; - - default: - return kCTFontUIFontSystem; - } -} - -static CTFontDescriptorRef fontDescriptorFromTheme(QPlatformTheme::Font f) -{ -#if defined(QT_PLATFORM_UIKIT) - // Use Dynamic Type to resolve theme fonts if possible, to get - // correct font sizes and style based on user configuration. - NSString *textStyle = 0; - switch (f) { - case QPlatformTheme::TitleBarFont: - case QPlatformTheme::HeaderViewFont: - textStyle = UIFontTextStyleHeadline; - break; - case QPlatformTheme::MdiSubWindowTitleFont: - textStyle = UIFontTextStyleSubheadline; - break; - case QPlatformTheme::TipLabelFont: - case QPlatformTheme::SmallFont: - textStyle = UIFontTextStyleFootnote; - break; - case QPlatformTheme::MiniFont: - textStyle = UIFontTextStyleCaption2; - break; - case QPlatformTheme::FixedFont: - // Fall back to regular code path, as iOS doesn't provide - // an appropriate text style for this theme font. - break; - default: - textStyle = UIFontTextStyleBody; - break; - } - - if (textStyle) { - UIFontDescriptor *desc = [UIFontDescriptor preferredFontDescriptorWithTextStyle:textStyle]; - return static_cast(CFBridgingRetain(desc)); - } -#endif // Q_OS_IOS, Q_OS_TVOS, Q_OS_WATCHOS - - // macOS default case and iOS fallback case - return descriptorForFontType(fontTypeFromTheme(f)); -} - -const QHash &QCoreTextFontDatabase::themeFonts() const -{ - if (m_themeFonts.isEmpty()) { - for (long f = QPlatformTheme::SystemFont; f < QPlatformTheme::NFonts; f++) { - QPlatformTheme::Font ft = static_cast(f); - m_themeFonts.insert(ft, themeFont(ft)); - } - } - - return m_themeFonts; -} - -QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const -{ - CTFontDescriptorRef fontDesc = fontDescriptorFromTheme(f); - FontDescription fd; - getFontDescription(fontDesc, &fd); - - if (!m_systemFontDescriptors.contains(fontDesc)) - m_systemFontDescriptors.insert(fontDesc); - else - CFRelease(fontDesc); - - QFont *font = new QFont(fd.familyName, fd.pointSize, fd.weight, fd.style == QFont::StyleItalic); - return font; -} - -QFont QCoreTextFontDatabase::defaultFont() const -{ - if (defaultFontName.isEmpty()) { - QCFType systemFont = descriptorForFontType(kCTFontUIFontSystem); - defaultFontName = QCFString(CTFontDescriptorCopyAttribute(systemFont, kCTFontFamilyNameAttribute)); - } - - return QFont(defaultFontName); -} - -bool QCoreTextFontDatabase::fontsAlwaysScalable() const -{ - return true; -} - -QList QCoreTextFontDatabase::standardSizes() const -{ - QList ret; - static const unsigned short standard[] = - { 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288, 0 }; - ret.reserve(int(sizeof(standard) / sizeof(standard[0]))); - const unsigned short *sizes = standard; - while (*sizes) ret << *sizes++; - return ret; -} - -QT_END_NAMESPACE - diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h deleted file mode 100644 index 63419f75a9..0000000000 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QCORETEXTFONTDATABASE_H -#define QCORETEXTFONTDATABASE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include -#include - -Q_FORWARD_DECLARE_CF_TYPE(CTFontDescriptor); -Q_FORWARD_DECLARE_CF_TYPE(CTFont); - -Q_DECLARE_METATYPE(QCFType); -Q_DECLARE_METATYPE(QCFType); - -QT_BEGIN_NAMESPACE - -class QCoreTextFontDatabase : public QPlatformFontDatabase -{ -public: - QCoreTextFontDatabase(); - ~QCoreTextFontDatabase(); - void populateFontDatabase() override; - bool populateFamilyAliases(const QString &missingFamily) override; - void populateFamily(const QString &familyName) override; - void invalidate() override; - - QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override; - QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr) override; - void releaseHandle(void *handle) override; - bool isPrivateFontFamily(const QString &family) const override; - QFont defaultFont() const override; - bool fontsAlwaysScalable() const override; - QList standardSizes() const override; - - // For iOS and OS X platform themes - QFont *themeFont(QPlatformTheme::Font) const; - const QHash &themeFonts() const; - -protected: - mutable QSet m_systemFontDescriptors; - -private: - void populateFromDescriptor(CTFontDescriptorRef font, const QString &familyName = QString(), QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr); - static CFArrayRef fallbacksForFamily(const QString &family); - - mutable QString defaultFontName; - - mutable QHash m_themeFonts; - bool m_hasPopulatedAliases; -}; - -// Split out into separate template class so that the compiler doesn't have -// to generate code for each override in QCoreTextFontDatabase for each T. - -template -class QCoreTextFontDatabaseEngineFactory : public QCoreTextFontDatabase -{ -public: - QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; - QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; -}; - -QT_END_NAMESPACE - -#endif // QCORETEXTFONTDATABASE_H diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm deleted file mode 100644 index 57fbf6032e..0000000000 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ /dev/null @@ -1,1060 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qfontengine_coretext_p.h" - -#include -#include -#if QT_CONFIG(settings) -#include -#endif -#include -#include -#include -#include - -#include - -#if defined(Q_OS_MACOS) -#import -#endif - -#if defined(QT_PLATFORM_UIKIT) -#import -#endif - -// These are available cross platform, exported as kCTFontWeightXXX from CoreText.framework, -// but they are not documented and are not in public headers so are private API and exposed -// only through the NSFontWeightXXX and UIFontWeightXXX aliases in AppKit and UIKit (rdar://26109857) -#if defined(Q_OS_MACOS) -#define kCTFontWeightUltraLight NSFontWeightUltraLight -#define kCTFontWeightThin NSFontWeightThin -#define kCTFontWeightLight NSFontWeightLight -#define kCTFontWeightRegular NSFontWeightRegular -#define kCTFontWeightMedium NSFontWeightMedium -#define kCTFontWeightSemibold NSFontWeightSemibold -#define kCTFontWeightBold NSFontWeightBold -#define kCTFontWeightHeavy NSFontWeightHeavy -#define kCTFontWeightBlack NSFontWeightBlack -#elif defined(QT_PLATFORM_UIKIT) -#define kCTFontWeightUltraLight UIFontWeightUltraLight -#define kCTFontWeightThin UIFontWeightThin -#define kCTFontWeightLight UIFontWeightLight -#define kCTFontWeightRegular UIFontWeightRegular -#define kCTFontWeightMedium UIFontWeightMedium -#define kCTFontWeightSemibold UIFontWeightSemibold -#define kCTFontWeightBold UIFontWeightBold -#define kCTFontWeightHeavy UIFontWeightHeavy -#define kCTFontWeightBlack UIFontWeightBlack -#endif - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") - -static float SYNTHETIC_ITALIC_SKEW = std::tan(14.f * std::acos(0.f) / 90.f); - -bool QCoreTextFontEngine::ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length) -{ - CTFontRef ctfont = *(CTFontRef *)user_data; - - QCFType table = CTFontCopyTable(ctfont, tag, 0); - if (!table) - return false; - - CFIndex tableLength = CFDataGetLength(table); - if (buffer && int(*length) >= tableLength) - CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); - *length = tableLength; - Q_ASSERT(int(*length) > 0); - return true; -} - -QFont::Weight QCoreTextFontEngine::qtWeightFromCFWeight(float value) -{ -#define COMPARE_WEIGHT_DISTANCE(ct_weight, qt_weight) \ - { \ - float d; \ - if ((d = qAbs(value - ct_weight)) < distance) { \ - distance = d; \ - ret = qt_weight; \ - } \ - } - - float distance = qAbs(value - kCTFontWeightBlack); - QFont::Weight ret = QFont::Black; - - // Compare distance to system weight to find the closest match. - // (Note: Must go from high to low, so that midpoints are rounded up) - COMPARE_WEIGHT_DISTANCE(kCTFontWeightHeavy, QFont::ExtraBold); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightBold, QFont::Bold); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightSemibold, QFont::DemiBold); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightMedium, QFont::Medium); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightRegular, QFont::Normal); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightLight, QFont::Light); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightThin, QFont::ExtraLight); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightUltraLight, QFont::Thin); - -#undef COMPARE_WEIGHT_DISTANCE - - return ret; -} - -CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef) -{ - CGAffineTransform transform = CGAffineTransformIdentity; - if (fontDef.stretch && fontDef.stretch != 100) - transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); - return transform; -} - -// Keeps font data alive until engine is disposed -class QCoreTextRawFontEngine : public QCoreTextFontEngine -{ -public: - QCoreTextRawFontEngine(CGFontRef font, const QFontDef &def, const QByteArray &fontData) - : QCoreTextFontEngine(font, def) - , m_fontData(fontData) - {} - QFontEngine *cloneWithSize(qreal pixelSize) const - { - QFontDef newFontDef = fontDef; - newFontDef.pixelSize = pixelSize; - newFontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); - - return new QCoreTextRawFontEngine(cgFont, newFontDef, m_fontData); - } - QByteArray m_fontData; -}; - -QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - Q_UNUSED(hintingPreference); - - QCFType fontDataReference = fontData.toRawCFData(); - QCFType dataProvider = CGDataProviderCreateWithCFData(fontDataReference); - - // Note: CTFontCreateWithGraphicsFont (which we call from the QCoreTextFontEngine - // constructor) has a bug causing it to retain the CGFontRef but never release it. - // The result is that we are leaking the CGFont, CGDataProvider, and CGData, but - // as the CGData is created from the raw QByteArray data, which we deref in the - // subclass above during destruction, we're at least not leaking the font data, - // (unless CoreText copies it internally). http://stackoverflow.com/questions/40805382/ - QCFType cgFont = CGFontCreateWithDataProvider(dataProvider); - - if (!cgFont) { - qWarning("QCoreTextFontEngine::create: CGFontCreateWithDataProvider failed"); - return nullptr; - } - - QFontDef def; - def.pixelSize = pixelSize; - def.pointSize = pixelSize * 72.0 / qt_defaultDpi(); - return new QCoreTextRawFontEngine(cgFont, def, fontData); -} - -QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) - : QCoreTextFontEngine(def) -{ - ctfont = QCFType::constructFromGet(font); - cgFont = CTFontCopyGraphicsFont(font, nullptr); - init(); -} - -QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def) - : QCoreTextFontEngine(def) -{ - cgFont = QCFType::constructFromGet(font); - ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, nullptr); - init(); -} - -QCoreTextFontEngine::QCoreTextFontEngine(const QFontDef &def) - : QFontEngine(Mac) -{ - fontDef = def; - transform = qt_transform_from_fontdef(fontDef); -} - -QCoreTextFontEngine::~QCoreTextFontEngine() -{ -} - -void QCoreTextFontEngine::init() -{ - Q_ASSERT(ctfont); - Q_ASSERT(cgFont); - - face_id.index = 0; - QCFString name = CTFontCopyName(ctfont, kCTFontUniqueNameKey); - face_id.filename = QString::fromCFString(name).toUtf8(); - - QCFString family = CTFontCopyFamilyName(ctfont); - fontDef.family = family; - - QCFString styleName = (CFStringRef) CTFontCopyAttribute(ctfont, kCTFontStyleNameAttribute); - fontDef.styleName = styleName; - - synthesisFlags = 0; - CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont); - - if (traits & kCTFontColorGlyphsTrait) - glyphFormat = QFontEngine::Format_ARGB; - else if (shouldSmoothFont() && fontSmoothing() == FontSmoothing::Subpixel) - glyphFormat = QFontEngine::Format_A32; - else - glyphFormat = QFontEngine::Format_A8; - - if (traits & kCTFontItalicTrait) - fontDef.style = QFont::StyleItalic; - - static const auto getTraitValue = [](CFDictionaryRef allTraits, CFStringRef trait) -> float { - if (CFDictionaryContainsKey(allTraits, trait)) { - CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait); - float v = 0; - CFNumberGetValue(traitNum, kCFNumberFloatType, &v); - return v; - } - return 0; - }; - - QCFType allTraits = CTFontCopyTraits(ctfont); - fontDef.weight = QCoreTextFontEngine::qtWeightFromCFWeight(getTraitValue(allTraits, kCTFontWeightTrait)); - int slant = static_cast(getTraitValue(allTraits, kCTFontSlantTrait) * 500 + 500); - if (slant > 500 && !(traits & kCTFontItalicTrait)) - fontDef.style = QFont::StyleOblique; - - if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) - synthesisFlags |= SynthesizedBold; - // XXX: we probably don't need to synthesis italic for oblique font - if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) - synthesisFlags |= SynthesizedItalic; - - avgCharWidth = 0; - QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); - unsigned emSize = CTFontGetUnitsPerEm(ctfont); - if (os2Table.size() >= 10) { - fsType = qFromBigEndian(os2Table.constData() + 8); - // qAbs is a workaround for weird fonts like Lucida Grande - qint16 width = qAbs(qFromBigEndian(os2Table.constData() + 2)); - avgCharWidth = QFixed::fromReal(width * fontDef.pixelSize / emSize); - } else - avgCharWidth = QFontEngine::averageCharWidth(); - - underlineThickness = QFixed::fromReal(CTFontGetUnderlineThickness(ctfont)); - underlinePos = -QFixed::fromReal(CTFontGetUnderlinePosition(ctfont)); - - cache_cost = (CTFontGetAscent(ctfont) + CTFontGetDescent(ctfont)) * avgCharWidth.toInt() * 2000; - - kerningPairsLoaded = false; -} - -glyph_t QCoreTextFontEngine::glyphIndex(uint ucs4) const -{ - int len = 0; - - QChar str[2]; - if (Q_UNLIKELY(QChar::requiresSurrogates(ucs4))) { - str[len++] = QChar(QChar::highSurrogate(ucs4)); - str[len++] = QChar(QChar::lowSurrogate(ucs4)); - } else { - str[len++] = QChar(ucs4); - } - - CGGlyph glyphIndices[2]; - - CTFontGetGlyphsForCharacters(ctfont, (const UniChar *)str, glyphIndices, len); - - return glyphIndices[0]; -} - -bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, - int *nglyphs, QFontEngine::ShaperFlags flags) const -{ - Q_ASSERT(glyphs->numGlyphs >= *nglyphs); - if (*nglyphs < len) { - *nglyphs = len; - return false; - } - - QVarLengthArray cgGlyphs(len); - CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len); - - int glyph_pos = 0; - for (int i = 0; i < len; ++i) { - glyphs->glyphs[glyph_pos] = cgGlyphs[i]; - if (glyph_pos < i) - cgGlyphs[glyph_pos] = cgGlyphs[i]; - glyph_pos++; - - // If it's a non-BMP char, skip the lower part of surrogate pair and go - // directly to the next char without increasing glyph_pos - if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) - ++i; - } - - *nglyphs = glyph_pos; - glyphs->numGlyphs = glyph_pos; - - if (!(flags & GlyphIndicesOnly)) - loadAdvancesForGlyphs(cgGlyphs, glyphs); - - return true; -} - -glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs) -{ - QFixed w; -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics; -QT_WARNING_POP - - for (int i = 0; i < glyphs.numGlyphs; ++i) { - w += round ? glyphs.effectiveAdvance(i).round() - : glyphs.effectiveAdvance(i); - } - return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0); -} - -glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) -{ - glyph_metrics_t ret; - CGGlyph g = glyph; - CGRect rect = CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontOrientationHorizontal, &g, 0, 1); - if (synthesisFlags & QFontEngine::SynthesizedItalic) { - rect.size.width += rect.size.height * SYNTHETIC_ITALIC_SKEW; - } - ret.width = QFixed::fromReal(rect.size.width); - ret.height = QFixed::fromReal(rect.size.height); - ret.x = QFixed::fromReal(rect.origin.x); - ret.y = -QFixed::fromReal(rect.origin.y) - ret.height; - CGSize advances[1]; - CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, &g, advances, 1); - ret.xoff = QFixed::fromReal(advances[0].width); - ret.yoff = QFixed::fromReal(advances[0].height); - -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { -QT_WARNING_POP - ret.xoff = ret.xoff.round(); - ret.yoff = ret.yoff.round(); - } - - return ret; -} - -void QCoreTextFontEngine::initializeHeightMetrics() const -{ - m_ascent = QFixed::fromReal(CTFontGetAscent(ctfont)); - m_descent = QFixed::fromReal(CTFontGetDescent(ctfont)); - m_leading = QFixed::fromReal(CTFontGetLeading(ctfont)); - - QFontEngine::initializeHeightMetrics(); -} - -QFixed QCoreTextFontEngine::capHeight() const -{ - QFixed c = QFixed::fromReal(CTFontGetCapHeight(ctfont)); - if (c <= 0) - return calculatedCapHeight(); - -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) -QT_WARNING_POP - c = c.round(); - - return c; -} - -QFixed QCoreTextFontEngine::xHeight() const -{ -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - ? QFixed::fromReal(CTFontGetXHeight(ctfont)).round() - : QFixed::fromReal(CTFontGetXHeight(ctfont)); -QT_WARNING_POP -} - -QFixed QCoreTextFontEngine::averageCharWidth() const -{ -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - ? avgCharWidth.round() : avgCharWidth; -QT_WARNING_POP -} - -qreal QCoreTextFontEngine::maxCharWidth() const -{ - // ### FIXME: 'W' might not be the widest character, but this is better than nothing - const glyph_t glyph = glyphIndex('W'); - glyph_metrics_t bb = const_cast(this)->boundingBox(glyph); - return bb.xoff.toReal(); -} - -bool QCoreTextFontEngine::hasColorGlyphs() const -{ - return glyphFormat == QFontEngine::Format_ARGB; -} - -void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight) -{ - QVarLengthArray positions; - QVarLengthArray glyphs; - QTransform matrix; - matrix.translate(x, y); - getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - if (glyphs.size() == 0) - return; - - CGContextSetFontSize(ctx, fontDef.pixelSize); - - CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx); - - CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, -1, 0, -paintDeviceHeight); - - CGAffineTransformConcat(cgMatrix, oldTextMatrix); - - if (synthesisFlags & QFontEngine::SynthesizedItalic) - cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0)); - - cgMatrix = CGAffineTransformConcat(cgMatrix, transform); - - CGContextSetTextMatrix(ctx, cgMatrix); - - CGContextSetTextDrawingMode(ctx, kCGTextFill); - - QVarLengthArray cgPositions(glyphs.size()); - QVarLengthArray cgGlyphs(glyphs.size()); - const qreal firstX = positions[0].x.toReal(); - const qreal firstY = positions[0].y.toReal(); - for (int i = 0; i < glyphs.size(); ++i) { - cgPositions[i].x = positions[i].x.toReal() - firstX; - cgPositions[i].y = firstY - positions[i].y.toReal(); - cgGlyphs[i] = glyphs[i]; - } - - //NSLog(@"Font inDraw %@ ctfont %@", CGFontCopyFullName(cgFont), CTFontCopyFamilyName(ctfont)); - - CGContextSetTextPosition(ctx, positions[0].x.toReal(), positions[0].y.toReal()); - CTFontDrawGlyphs(ctfont, cgGlyphs.data(), cgPositions.data(), glyphs.size(), ctx); - - if (synthesisFlags & QFontEngine::SynthesizedBold) { - CGContextSetTextPosition(ctx, positions[0].x.toReal() + 0.5 * lineThickness().toReal(), - positions[0].y.toReal()); - CTFontDrawGlyphs(ctfont, cgGlyphs.data(), cgPositions.data(), glyphs.size(), ctx); - } - - CGContextSetTextMatrix(ctx, oldTextMatrix); -} - -struct ConvertPathInfo -{ - ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos, qreal newStretch = 1.0) : - path(newPath), pos(newPos), stretch(newStretch) {} - QPainterPath *path; - QPointF pos; - qreal stretch; -}; - -static void convertCGPathToQPainterPath(void *info, const CGPathElement *element) -{ - ConvertPathInfo *myInfo = static_cast(info); - switch(element->type) { - case kCGPathElementMoveToPoint: - myInfo->path->moveTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), - element->points[0].y + myInfo->pos.y()); - break; - case kCGPathElementAddLineToPoint: - myInfo->path->lineTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), - element->points[0].y + myInfo->pos.y()); - break; - case kCGPathElementAddQuadCurveToPoint: - myInfo->path->quadTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), - element->points[0].y + myInfo->pos.y(), - (element->points[1].x * myInfo->stretch) + myInfo->pos.x(), - element->points[1].y + myInfo->pos.y()); - break; - case kCGPathElementAddCurveToPoint: - myInfo->path->cubicTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), - element->points[0].y + myInfo->pos.y(), - (element->points[1].x * myInfo->stretch) + myInfo->pos.x(), - element->points[1].y + myInfo->pos.y(), - (element->points[2].x * myInfo->stretch) + myInfo->pos.x(), - element->points[2].y + myInfo->pos.y()); - break; - case kCGPathElementCloseSubpath: - myInfo->path->closeSubpath(); - break; - default: - qCWarning(lcQpaFonts) << "Unhandled path transform type: " << element->type; - } - -} - -void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs, - QPainterPath *path, QTextItem::RenderFlags) -{ - if (hasColorGlyphs()) - return; // We can't convert color-glyphs to path - - CGAffineTransform cgMatrix = CGAffineTransformIdentity; - cgMatrix = CGAffineTransformScale(cgMatrix, 1, -1); - - if (synthesisFlags & QFontEngine::SynthesizedItalic) - cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0)); - - qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0; - for (int i = 0; i < nGlyphs; ++i) { - QCFType cgpath = CTFontCreatePathForGlyph(ctfont, glyphs[i], &cgMatrix); - ConvertPathInfo info(path, positions[i].toPointF(), stretch); - CGPathApply(cgpath, &info, convertCGPathToQPainterPath); - } -} - -static void qcoretextfontengine_scaleMetrics(glyph_metrics_t &br, const QTransform &matrix) -{ - if (matrix.isScaling()) { - qreal hscale = matrix.m11(); - qreal vscale = matrix.m22(); - br.width = QFixed::fromReal(br.width.toReal() * hscale); - br.height = QFixed::fromReal(br.height.toReal() * vscale); - br.x = QFixed::fromReal(br.x.toReal() * hscale); - br.y = QFixed::fromReal(br.y.toReal() * vscale); - } -} - -glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, GlyphFormat format) -{ - if (matrix.type() > QTransform::TxScale) - return QFontEngine::alphaMapBoundingBox(glyph, subPixelPosition, matrix, format); - - glyph_metrics_t br = boundingBox(glyph); - qcoretextfontengine_scaleMetrics(br, matrix); - - // Normalize width and height - if (br.width < 0) - br.width = -br.width; - if (br.height < 0) - br.height = -br.height; - - if (format == QFontEngine::Format_A8 || format == QFontEngine::Format_A32) { - // Drawing a glyph at x-position 0 with anti-aliasing enabled - // will potentially fill the pixel to the left of 0, as the - // coordinates are not aligned to the center of pixels. To - // prevent clipping of this pixel we need to shift the glyph - // in the bitmap one pixel to the right. The shift needs to - // be reflected in the glyph metrics as well, so that the final - // position of the glyph is correct, which is why doing the - // shift in imageForGlyph() is not enough. - br.x -= 1; - - // As we've shifted the glyph one pixel to the right, we need - // to expand the width of the alpha map bounding box as well. - br.width += 1; - - // But we have the same anti-aliasing problem on the right - // hand side of the glyph, eg. if the width of the glyph - // results in the bounding rect landing between two pixels. - // We pad the bounding rect again to account for the possible - // anti-aliased drawing. - br.width += 1; - - // We also shift the glyph to right right based on the subpixel - // position, so we pad the bounding box to take account for the - // subpixel positions that may result in the glyph being drawn - // one pixel to the right of the 0-subpixel position. - br.width += 1; - - // The same same logic as for the x-position needs to be applied - // to the y-position, except we don't need to compensate for - // the subpixel positioning. - br.y -= 1; - br.height += 2; - } - - return br; -} - -/* - Apple has gone through many iterations of its font smoothing algorithms, - and there are many ways to enable or disable certain aspects of it. As - keeping up with all the different toggles and behavior differences between - macOS versions is tricky, we resort to rendering a single glyph in a few - configurations, picking up the font smoothing algorithm from the observed - result. - - The possible values are: - - - Disabled: No font smoothing is applied. - - Possibly triggered by the user unchecking the "Use font smoothing when - available" checkbox in the system preferences or setting AppleFontSmoothing - to 0. Also controlled by the CGContextSetAllowsFontSmoothing() API, - which gets its default from the settings above. This API overrides - the more granular CGContextSetShouldSmoothFonts(), which we use to - enable (request) or disable font smoothing. - - Note that this does not exclude normal antialiasing, controlled by - the CGContextSetShouldAntialias() API. - - - Subpixel: Font smoothing is applied, and affects subpixels. - - This was the default mode on macOS versions prior to 10.14 (Mojave). - The font dilation (stem darkening) parameters were controlled by the - AppleFontSmoothing setting, ranging from 1 to 3 (light to strong). - - On Mojave it is no longer supported, but can be triggered by a legacy - override (CGFontRenderingFontSmoothingDisabled=NO), so we need to - still account for it, otherwise users will have a bad time. - - - Grayscale: Font smoothing is applied, but does not affect subpixels. - - This is the default mode on macOS 10.14 (Mojave). The font dilation - (stem darkening) parameters are not affected by the AppleFontSmoothing - setting, but are instead computed based on the fill color used when - drawing the glyphs (white fill gives a lighter dilation than black - fill). This affects how we build our glyph cache, since we produce - alpha maps by drawing white on black. -*/ -QCoreTextFontEngine::FontSmoothing QCoreTextFontEngine::fontSmoothing() -{ - static const FontSmoothing cachedFontSmoothing = [] { - static const int kSize = 10; - QCFType font = CTFontCreateWithName(CFSTR("Helvetica"), kSize, nullptr); - - UniChar character('X'); CGGlyph glyph; - CTFontGetGlyphsForCharacters(font, &character, &glyph, 1); - - auto drawGlyph = [&](bool smooth) -> QImage { - QImage image(kSize, kSize, QImage::Format_RGB32); - image.fill(0); - - QMacCGContext ctx(&image); - CGContextSetTextDrawingMode(ctx, kCGTextFill); - CGContextSetGrayFillColor(ctx, 1, 1); - - // Will be ignored if CGContextSetAllowsFontSmoothing() has been - // set to false by CoreGraphics based on user defaults. - CGContextSetShouldSmoothFonts(ctx, smooth); - - CTFontDrawGlyphs(font, &glyph, &CGPointZero, 1, ctx); - return image; - }; - - QImage nonSmoothed = drawGlyph(false); - QImage smoothed = drawGlyph(true); - - FontSmoothing fontSmoothing = FontSmoothing::Disabled; - [&] { - for (int x = 0; x < kSize; ++x) { - for (int y = 0; y < kSize; ++y) { - QRgb sp = smoothed.pixel(x, y); - if (qRed(sp) != qGreen(sp) || qRed(sp) != qBlue(sp)) { - fontSmoothing = FontSmoothing::Subpixel; - return; - } - - if (sp != nonSmoothed.pixel(x, y)) - fontSmoothing = FontSmoothing::Grayscale; - } - } - }(); - - auto defaults = [NSUserDefaults standardUserDefaults]; - qCDebug(lcQpaFonts) << "Resolved font smoothing algorithm. Defaults =" - << [[defaults dictionaryRepresentation] dictionaryWithValuesForKeys:@[ - @"AppleFontSmoothing", - @"CGFontRenderingFontSmoothingDisabled" - ]] << "Result =" << fontSmoothing; - - return fontSmoothing; - }(); - - return cachedFontSmoothing; -} - -bool QCoreTextFontEngine::shouldAntialias() const -{ - return !(fontDef.styleStrategy & QFont::NoAntialias); -} - -bool QCoreTextFontEngine::shouldSmoothFont() const -{ - if (hasColorGlyphs()) - return false; - - if (!shouldAntialias()) - return false; - - switch (fontSmoothing()) { - case Disabled: return false; - case Subpixel: return !(fontDef.styleStrategy & QFont::NoSubpixelAntialias); - case Grayscale: return true; - } - - Q_UNREACHABLE(); -} - -bool QCoreTextFontEngine::expectsGammaCorrectedBlending() const -{ - return shouldSmoothFont() && fontSmoothing() == Subpixel; -} - -qreal QCoreTextFontEngine::fontSmoothingGamma() -{ - return 2.0; -} - -QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, const QColor &color) -{ - glyph_metrics_t br = alphaMapBoundingBox(glyph, subPixelPosition, matrix, glyphFormat); - - QImage::Format imageFormat = hasColorGlyphs() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; - QImage im(br.width.ceil().toInt(), br.height.ceil().toInt(), imageFormat); - if (!im.width() || !im.height()) - return im; - - QCFType colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - QCFType ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(), - 8, im.bytesPerLine(), colorspace, - qt_mac_bitmapInfoForImage(im)); - Q_ASSERT(ctx); - - CGContextSetShouldAntialias(ctx, shouldAntialias()); - - const bool shouldSmooth = shouldSmoothFont(); - CGContextSetShouldSmoothFonts(ctx, shouldSmooth); - -#if defined(Q_OS_MACOS) - auto glyphColor = [&] { - if (shouldSmooth && fontSmoothing() == Grayscale) { - // The grayscale font smoothing algorithm introduced in macOS Mojave (10.14) adjusts - // its dilation (stem darkening) parameters based on the fill color. This means our - // default approach of drawing white on black to produce the alpha map will result - // in non-native looking text when then drawn as black on white during the final blit. - // As a workaround we use the application's current appearance to decide whether to - // draw with white or black fill, and then invert the glyph image in the latter case, - // producing an alpha map. This covers the most common use-cases, but longer term we - // should propagate the fill color all the way from the paint engine, and include it - //in the key for the glyph cache. - - if (!qt_mac_applicationIsInDarkMode()) - return kCGColorBlack; - } - return kCGColorWhite; - }(); - - const bool blackOnWhiteGlyphs = glyphColor == kCGColorBlack; - if (blackOnWhiteGlyphs) - im.fill(Qt::white); - else -#endif - im.fill(0); - - CGContextSetFontSize(ctx, fontDef.pixelSize); - - CGAffineTransform cgMatrix = CGAffineTransformIdentity; - - if (synthesisFlags & QFontEngine::SynthesizedItalic) - cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0)); - - if (!hasColorGlyphs()) // CTFontDrawGlyphs incorporates the font's matrix already - cgMatrix = CGAffineTransformConcat(cgMatrix, transform); - - if (matrix.isScaling()) - cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMakeScale(matrix.m11(), matrix.m22())); - - CGGlyph cgGlyph = glyph; - qreal pos_x = -br.x.truncate() + subPixelPosition.toReal(); - qreal pos_y = im.height() + br.y.toReal(); - - if (!hasColorGlyphs()) { - CGContextSetTextMatrix(ctx, cgMatrix); -#if defined(Q_OS_MACOS) - CGContextSetFillColorWithColor(ctx, CGColorGetConstantColor(glyphColor)); -#else - CGContextSetRGBFillColor(ctx, 1, 1, 1, 1); -#endif - CGContextSetTextDrawingMode(ctx, kCGTextFill); - CGContextSetTextPosition(ctx, pos_x, pos_y); - - CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx); - - if (synthesisFlags & QFontEngine::SynthesizedBold) { - CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y); - CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx); - } - } else { - CGContextSetRGBFillColor(ctx, color.redF(), color.greenF(), color.blueF(), color.alphaF()); - - // CGContextSetTextMatrix does not work with color glyphs, so we use - // the CTM instead. This means we must translate the CTM as well, to - // set the glyph position, instead of using CGContextSetTextPosition. - CGContextTranslateCTM(ctx, pos_x, pos_y); - CGContextConcatCTM(ctx, cgMatrix); - - // CGContextShowGlyphsWithAdvances does not support the 'sbix' color-bitmap - // glyphs in the Apple Color Emoji font, so we use CTFontDrawGlyphs instead. - CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx); - } - - if (expectsGammaCorrectedBlending()) - qGamma_correct_back_to_linear_cs(&im); - -#if defined(Q_OS_MACOS) - if (blackOnWhiteGlyphs) - im.invertPixels(); -#endif - - return im; -} - -QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) -{ - return alphaMapForGlyph(glyph, subPixelPosition, QTransform()); -} - -QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &x) -{ - if (x.type() > QTransform::TxScale) - return QFontEngine::alphaMapForGlyph(glyph, subPixelPosition, x); - - QImage im = imageForGlyph(glyph, subPixelPosition, x); - - QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8); - - for (int y=0; y QTransform::TxScale) - return QFontEngine::alphaRGBMapForGlyph(glyph, subPixelPosition, x); - - return imageForGlyph(glyph, subPixelPosition, x); -} - -QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color) -{ - if (t.type() > QTransform::TxScale) - return QFontEngine::bitmapForGlyph(glyph, subPixelPosition, t, color); - - return imageForGlyph(glyph, subPixelPosition, t, color); -} - -void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const -{ - Q_UNUSED(flags); - - const int numGlyphs = glyphs->numGlyphs; - QVarLengthArray cgGlyphs(numGlyphs); - - for (int i = 0; i < numGlyphs; ++i) { - Q_ASSERT(!QFontEngineMulti::highByte(glyphs->glyphs[i])); - cgGlyphs[i] = glyphs->glyphs[i]; - } - - loadAdvancesForGlyphs(cgGlyphs, glyphs); -} - -void QCoreTextFontEngine::loadAdvancesForGlyphs(QVarLengthArray &cgGlyphs, QGlyphLayout *glyphs) const -{ - const int numGlyphs = glyphs->numGlyphs; - QVarLengthArray advances(numGlyphs); - CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), numGlyphs); - - for (int i = 0; i < numGlyphs; ++i) { - QFixed advance = QFixed::fromReal(advances[i].width); -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - glyphs->advances[i] = fontDef.styleStrategy & QFont::ForceIntegerMetrics - ? advance.round() : advance; -QT_WARNING_POP - } -} - -QFontEngine::FaceId QCoreTextFontEngine::faceId() const -{ - return face_id; -} - -bool QCoreTextFontEngine::canRender(const QChar *string, int len) const -{ - QVarLengthArray cgGlyphs(len); - return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len); -} - -bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const -{ - return ct_getSfntTable((void *)&ctfont, tag, buffer, length); -} - -void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metric) -{ - CGAffineTransform cgMatrix = CGAffineTransformIdentity; - - qreal emSquare = CTFontGetUnitsPerEm(ctfont); - qreal scale = emSquare / CTFontGetSize(ctfont); - cgMatrix = CGAffineTransformScale(cgMatrix, scale, -scale); - - QCFType cgpath = CTFontCreatePathForGlyph(ctfont, (CGGlyph) glyph, &cgMatrix); - ConvertPathInfo info(path, QPointF(0,0)); - CGPathApply(cgpath, &info, convertCGPathToQPainterPath); - - *metric = boundingBox(glyph); - // scale the metrics too - metric->width = QFixed::fromReal(metric->width.toReal() * scale); - metric->height = QFixed::fromReal(metric->height.toReal() * scale); - metric->x = QFixed::fromReal(metric->x.toReal() * scale); - metric->y = QFixed::fromReal(metric->y.toReal() * scale); - metric->xoff = QFixed::fromReal(metric->xoff.toReal() * scale); - metric->yoff = QFixed::fromReal(metric->yoff.toReal() * scale); -} - -QFixed QCoreTextFontEngine::emSquareSize() const -{ - return QFixed(int(CTFontGetUnitsPerEm(ctfont))); -} - -QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const -{ - QFontDef newFontDef = fontDef; - newFontDef.pixelSize = pixelSize; - newFontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); - - return new QCoreTextFontEngine(cgFont, newFontDef); -} - -Qt::HANDLE QCoreTextFontEngine::handle() const -{ - return (Qt::HANDLE)(static_cast(ctfont)); -} - -bool QCoreTextFontEngine::supportsTransformation(const QTransform &transform) const -{ - if (transform.type() < QTransform::TxScale) - return true; - else if (transform.type() == QTransform::TxScale && - transform.m11() >= 0 && transform.m22() >= 0) - return true; - else - return false; -} - -QFixed QCoreTextFontEngine::lineThickness() const -{ - return underlineThickness; -} - -QFixed QCoreTextFontEngine::underlinePosition() const -{ - return underlinePos; -} - -QFontEngine::Properties QCoreTextFontEngine::properties() const -{ - Properties result; - - QCFString psName, copyright; - psName = CTFontCopyPostScriptName(ctfont); - copyright = CTFontCopyName(ctfont, kCTFontCopyrightNameKey); - result.postscriptName = QString::fromCFString(psName).toUtf8(); - result.copyright = QString::fromCFString(copyright).toUtf8(); - - qreal emSquare = CTFontGetUnitsPerEm(ctfont); - qreal scale = emSquare / CTFontGetSize(ctfont); - - CGRect cgRect = CTFontGetBoundingBox(ctfont); - result.boundingBox = QRectF(cgRect.origin.x * scale, - -CTFontGetAscent(ctfont) * scale, - cgRect.size.width * scale, - cgRect.size.height * scale); - - result.emSquare = emSquareSize(); - result.ascent = QFixed::fromReal(CTFontGetAscent(ctfont) * scale); - result.descent = QFixed::fromReal(CTFontGetDescent(ctfont) * scale); - result.leading = QFixed::fromReal(CTFontGetLeading(ctfont) * scale); - result.italicAngle = QFixed::fromReal(CTFontGetSlantAngle(ctfont)); - result.capHeight = QFixed::fromReal(CTFontGetCapHeight(ctfont) * scale); - result.lineWidth = QFixed::fromReal(CTFontGetUnderlineThickness(ctfont) * scale); - -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { -QT_WARNING_POP - result.ascent = result.ascent.round(); - result.descent = result.descent.round(); - result.leading = result.leading.round(); - result.italicAngle = result.italicAngle.round(); - result.capHeight = result.capHeight.round(); - result.lineWidth = result.lineWidth.round(); - } - - return result; -} - -void QCoreTextFontEngine::doKerning(QGlyphLayout *g, ShaperFlags flags) const -{ - if (!kerningPairsLoaded) { - kerningPairsLoaded = true; - qreal emSquare = CTFontGetUnitsPerEm(ctfont); - qreal scale = emSquare / CTFontGetSize(ctfont); - - const_cast(this)->loadKerningPairs(QFixed::fromReal(scale)); - } - - QFontEngine::doKerning(g, flags); -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h deleted file mode 100644 index da75594fde..0000000000 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ /dev/null @@ -1,159 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QFONTENGINE_CORETEXT_P_H -#define QFONTENGINE_CORETEXT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -#ifdef Q_OS_MACOS -#include -#else -#include -#include -#endif - -QT_BEGIN_NAMESPACE - -Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) - -class QCoreTextFontEngine : public QFontEngine -{ - Q_GADGET - -public: - QCoreTextFontEngine(CTFontRef font, const QFontDef &def); - QCoreTextFontEngine(CGFontRef font, const QFontDef &def); - ~QCoreTextFontEngine(); - - glyph_t glyphIndex(uint ucs4) const override; - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; - void recalcAdvances(QGlyphLayout *, ShaperFlags) const override; - - glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; - glyph_metrics_t boundingBox(glyph_t glyph) override; - - QFixed capHeight() const override; - QFixed xHeight() const override; - qreal maxCharWidth() const override; - QFixed averageCharWidth() const override; - - void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, - QPainterPath *path, QTextItem::RenderFlags) override; - - bool canRender(const QChar *string, int len) const override; - - int synthesized() const override { return synthesisFlags; } - bool supportsSubPixelPositions() const override { return true; } - - QFixed lineThickness() const override; - QFixed underlinePosition() const override; - - void draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight); - - FaceId faceId() const override; - bool getSfntTableData(uint /*tag*/, uchar * /*buffer*/, uint * /*length*/) const override; - void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override; - QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition) override; - QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override; - QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override; - glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) override; - QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override; - QFixed emSquareSize() const override; - void doKerning(QGlyphLayout *g, ShaperFlags flags) const override; - - bool supportsTransformation(const QTransform &transform) const override; - bool expectsGammaCorrectedBlending() const override; - - QFontEngine *cloneWithSize(qreal pixelSize) const override; - Qt::HANDLE handle() const override; - int glyphMargin(QFontEngine::GlyphFormat format) override { Q_UNUSED(format); return 0; } - - QFontEngine::Properties properties() const override; - - enum FontSmoothing { Disabled, Subpixel, Grayscale }; - Q_ENUM(FontSmoothing); - - static FontSmoothing fontSmoothing(); - static qreal fontSmoothingGamma(); - - static bool ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length); - static QFont::Weight qtWeightFromCFWeight(float value); - - static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); - -protected: - QCoreTextFontEngine(const QFontDef &def); - void init(); - QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &m, const QColor &color = QColor()); - void loadAdvancesForGlyphs(QVarLengthArray &cgGlyphs, QGlyphLayout *glyphs) const; - bool hasColorGlyphs() const; - bool shouldAntialias() const; - bool shouldSmoothFont() const; - void initializeHeightMetrics() const override; - - QCFType ctfont; - QCFType cgFont; - int synthesisFlags; - CGAffineTransform transform; - QFixed avgCharWidth; - QFixed underlineThickness; - QFixed underlinePos; - QFontEngine::FaceId face_id; - mutable bool kerningPairsLoaded; -}; - -CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef); - -QT_END_NAMESPACE - -#endif // QFONTENGINE_CORETEXT_P_H diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 7d099b7bbc..a3b194a17b 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -8,7 +8,7 @@ SUBDIRS = \ fbconvenience \ themes -qtConfig(freetype)|darwin|win32: \ +if(qtConfig(freetype):!darwin)|win32: \ SUBDIRS += fontdatabases qtConfig(evdev)|qtConfig(tslib)|qtConfig(libinput)|qtConfig(integrityhid)|qtConfig(xkbcommon) { -- cgit v1.2.3