From ac10780c78444e8899b3ef965b6ffe56128e32be Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 16 Jul 2012 13:42:14 +0200 Subject: Support fallbacks fonts in UIKit plugin Code is taken from the Qt 5 CoreText font database, but the hardcoded path for the plist has been modified for iOS. Change-Id: I71271600ec5dd085d469d5c42f9811a23948021f Reviewed-by: Jiang Jiang --- src/plugins/platforms/uikit/platform.pro | 6 +- .../platforms/uikit/qcoretextfontdatabase.cpp | 156 ------------- .../platforms/uikit/qcoretextfontdatabase.h | 8 + .../platforms/uikit/qcoretextfontdatabase.mm | 248 +++++++++++++++++++++ 4 files changed, 258 insertions(+), 160 deletions(-) delete mode 100644 src/plugins/platforms/uikit/qcoretextfontdatabase.cpp create mode 100644 src/plugins/platforms/uikit/qcoretextfontdatabase.mm diff --git a/src/plugins/platforms/uikit/platform.pro b/src/plugins/platforms/uikit/platform.pro index b5ff62f..1b90f3e 100644 --- a/src/plugins/platforms/uikit/platform.pro +++ b/src/plugins/platforms/uikit/platform.pro @@ -9,7 +9,8 @@ OBJECTIVE_SOURCES = main.mm \ quikitwindow.mm \ quikitscreen.mm \ quikiteventloop.mm \ - quikitwindowsurface.mm + quikitwindowsurface.mm \ + qcoretextfontdatabase.mm OBJECTIVE_HEADERS = quikitintegration.h \ quikitwindow.h \ @@ -20,9 +21,6 @@ OBJECTIVE_HEADERS = quikitintegration.h \ HEADERS = quikitsoftwareinputhandler.h \ qcoretextfontdatabase.h -SOURCES += \ - qcoretextfontdatabase.cpp - #needed for qcoretextfontengine even if it's not used INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src diff --git a/src/plugins/platforms/uikit/qcoretextfontdatabase.cpp b/src/plugins/platforms/uikit/qcoretextfontdatabase.cpp deleted file mode 100644 index 2854567..0000000 --- a/src/plugins/platforms/uikit/qcoretextfontdatabase.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qcoretextfontdatabase.h" - -#include - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -void QCoreTextFontDatabase::populateFontDatabase() -{ - QCFType collection = CTFontCollectionCreateFromAvailableFonts(0); - if(!collection) - return; - QCFType fonts = CTFontCollectionCreateMatchingFontDescriptors(collection); - if(!fonts) - return; - QSupportedWritingSystems supportedWritingSystems; - for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) - supportedWritingSystems.setSupported((QFontDatabase::WritingSystem)i, true); - QString foundry_name = "CoreText"; - const int numFonts = CFArrayGetCount(fonts); - for(int i = 0; i < numFonts; ++i) { - CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fonts, i); - - QCFString family_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); -// QCFString style_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute); - - QFont::Weight fontWeight = QFont::Normal; - QFont::Style fontStyle = QFont::StyleNormal; - if(QCFType styles = (CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute)) { - if(CFNumberRef weight = (CFNumberRef)CFDictionaryGetValue(styles, kCTFontWeightTrait)) { - Q_ASSERT(CFNumberIsFloatType(weight)); - double d; - if(CFNumberGetValue(weight, kCFNumberDoubleType, &d)) { - if (d > 0.0) - fontWeight = QFont::Bold; - } - } - if(CFNumberRef italic = (CFNumberRef)CFDictionaryGetValue(styles, kCTFontSlantTrait)) { - Q_ASSERT(CFNumberIsFloatType(italic)); - double d; - if(CFNumberGetValue(italic, kCFNumberDoubleType, &d)) { - if (d > 0.0) - fontStyle = QFont::StyleItalic; - } - } - } - - int pixelSize = 0; - if(QCFType size = (CFNumberRef)CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) { - if(CFNumberIsFloatType(size)) { - double d; - CFNumberGetValue(size, kCFNumberDoubleType, &d); - pixelSize = d; - } else { - CFNumberGetValue(size, kCFNumberIntType, &pixelSize); - } - } - registerFont(QString(family_name), - foundry_name, - fontWeight, - fontStyle, - QFont::Unstretched, - true, - true, - pixelSize, - supportedWritingSystems, - 0); - } -} - -QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle) -{ - Q_UNUSED(script) - Q_UNUSED(handle) - CTFontSymbolicTraits symbolicTraits = 0; - if (fontDef.weight >= QFont::Bold) - symbolicTraits |= kCTFontBoldTrait; - switch (fontDef.style) { - case QFont::StyleNormal: - break; - case QFont::StyleItalic: - case QFont::StyleOblique: - symbolicTraits |= kCTFontItalicTrait; - break; - } - - CGAffineTransform transform = CGAffineTransformIdentity; - if (fontDef.stretch != 100) { - transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); - } - - QCFType baseFont = CTFontCreateWithName(QCFString(fontDef.family), fontDef.pixelSize, &transform); - QCFType ctFont = NULL; - // There is a side effect in Core Text: if we apply 0 as symbolic traits to a font in normal weight, - // we will get the light version of that font (while the way supposed to work doesn't: - // setting kCTFontWeightTrait to some value between -1.0 to 0.0 has no effect on font selection) - if (fontDef.weight != QFont::Normal || symbolicTraits) - ctFont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, &transform, symbolicTraits, symbolicTraits); - - // CTFontCreateCopyWithSymbolicTraits returns NULL if we ask for a trait that does - // not exist for the given font. (for example italic) - if (ctFont == 0) { - ctFont = baseFont; - } - - if (ctFont) - return new QCoreTextFontEngine(ctFont, fontDef); - return 0; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/uikit/qcoretextfontdatabase.h b/src/plugins/platforms/uikit/qcoretextfontdatabase.h index 05b9b09..77010c2 100644 --- a/src/plugins/platforms/uikit/qcoretextfontdatabase.h +++ b/src/plugins/platforms/uikit/qcoretextfontdatabase.h @@ -51,6 +51,14 @@ class QCoreTextFontDatabase : public QPlatformFontDatabase public: void populateFontDatabase(); QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); + + QStringList fallbacksForFamily(const QString family, + const QFont::Style &style, + const QFont::StyleHint &styleHint, + const QUnicodeTables::Script &script) const; + +private: + QHash fallbackLists; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/uikit/qcoretextfontdatabase.mm b/src/plugins/platforms/uikit/qcoretextfontdatabase.mm new file mode 100644 index 0000000..47bfba1 --- /dev/null +++ b/src/plugins/platforms/uikit/qcoretextfontdatabase.mm @@ -0,0 +1,248 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcoretextfontdatabase.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString family, + const QFont::Style &style, + const QFont::StyleHint &styleHint, + const QUnicodeTables::Script &script) const +{ + Q_UNUSED(family); + Q_UNUSED(style); + Q_UNUSED(script); + if (fallbackLists.isEmpty()) + const_cast(this)->populateFontDatabase(); + + return fallbackLists[styleHint]; +} + +static QFont::StyleHint styleHintFromNSString(NSString *style) +{ + if ([style isEqual: @"sans-serif"]) + return QFont::SansSerif; + else if ([style isEqual: @"monospace"]) + return QFont::Monospace; + else if ([style isEqual: @"cursive"]) + return QFont::Cursive; + else if ([style isEqual: @"serif"]) + return QFont::Serif; + else if ([style isEqual: @"fantasy"]) + return QFont::Fantasy; + else + return QFont::AnyStyle; +} + +static NSInteger languageMapSort(id obj1, id obj2, void *context) +{ + NSArray *map1 = (NSArray *) obj1; + NSArray *map2 = (NSArray *) obj2; + NSArray *languages = (NSArray *) context; + + NSString *lang1 = [map1 objectAtIndex: 0]; + NSString *lang2 = [map2 objectAtIndex: 0]; + + return [languages indexOfObject: lang1] - [languages indexOfObject: lang2]; +} + +static QString familyNameFromPostScriptName(QHash *psNameToFamily, + NSString *psName) +{ + QString name = QCFString::toQString((CFStringRef) psName); + if (psNameToFamily->contains(name)) { + return psNameToFamily->value(name); + } else { + QCFType font = CTFontCreateWithName((CFStringRef) psName, 12.0, NULL); + if (font) { + QCFString family = CTFontCopyFamilyName(font); + (*psNameToFamily)[name] = family; + return family; + } + } + + return name; +} + +void QCoreTextFontDatabase::populateFontDatabase() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + QCFType collection = CTFontCollectionCreateFromAvailableFonts(0); + if (!collection) + return; + QCFType fonts = CTFontCollectionCreateMatchingFontDescriptors(collection); + if (!fonts) + return; + QSupportedWritingSystems supportedWritingSystems; + for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) + supportedWritingSystems.setSupported((QFontDatabase::WritingSystem)i, true); + QString foundry_name = "CoreText"; + const int numFonts = CFArrayGetCount(fonts); + QHash psNameToFamily; + for (int i = 0; i < numFonts; ++i) { + CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fonts, i); + + QCFString family_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); +// QCFString style_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute); + + QFont::Weight fontWeight = QFont::Normal; + QFont::Style fontStyle = QFont::StyleNormal; + if (QCFType styles = (CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute)) { + if (CFNumberRef weight = (CFNumberRef)CFDictionaryGetValue(styles, kCTFontWeightTrait)) { + Q_ASSERT(CFNumberIsFloatType(weight)); + double d; + if (CFNumberGetValue(weight, kCFNumberDoubleType, &d)) { + if (d > 0.0) + fontWeight = QFont::Bold; + } + } + if (CFNumberRef italic = (CFNumberRef)CFDictionaryGetValue(styles, kCTFontSlantTrait)) { + Q_ASSERT(CFNumberIsFloatType(italic)); + double d; + if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) { + if (d > 0.0) + fontStyle = QFont::StyleItalic; + } + } + } + + int pixelSize = 0; + if (QCFType size = (CFNumberRef)CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) { + if (CFNumberIsFloatType(size)) { + double d; + CFNumberGetValue(size, kCFNumberDoubleType, &d); + pixelSize = d; + } else { + CFNumberGetValue(size, kCFNumberIntType, &pixelSize); + } + } + QString familyName = QCFString::toQString(family_name); + registerFont(familyName, + foundry_name, + fontWeight, + fontStyle, + QFont::Unstretched, + true, + true, + pixelSize, + supportedWritingSystems, + 0); + + CFStringRef psName = (CFStringRef) CTFontDescriptorCopyAttribute(font, + kCTFontNameAttribute); + psNameToFamily[QCFString::toQString(psName)] = familyName; + CFRelease(psName); + } + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"]; + + NSDictionary *fallbackDict = [NSDictionary dictionaryWithContentsOfFile: @"/System/Library/Frameworks/CoreText.framework/DefaultFontFallbacks.plist"]; + for (NSString *style in [fallbackDict allKeys]) { + NSArray *list = [fallbackDict valueForKey: style]; + QFont::StyleHint styleHint = styleHintFromNSString(style); + QStringList fallbackList; + for (id item in list) { + if ([item isKindOfClass: [NSArray class]]) { + NSArray *langs = [(NSArray *) item sortedArrayUsingFunction: languageMapSort + context: languages]; + for (NSArray *map in langs) + fallbackList.append(familyNameFromPostScriptName(&psNameToFamily, [map objectAtIndex: 1])); + } else if ([item isKindOfClass: [NSString class]]) { + fallbackList.append(familyNameFromPostScriptName(&psNameToFamily, item)); + } + } + + fallbackLists[styleHint] = fallbackList; + } + + [pool release]; +} + +QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle) +{ + Q_UNUSED(script) + Q_UNUSED(handle) + CTFontSymbolicTraits symbolicTraits = 0; + if (fontDef.weight >= QFont::Bold) + symbolicTraits |= kCTFontBoldTrait; + switch (fontDef.style) { + case QFont::StyleNormal: + break; + case QFont::StyleItalic: + case QFont::StyleOblique: + symbolicTraits |= kCTFontItalicTrait; + break; + } + + CGAffineTransform transform = CGAffineTransformIdentity; + if (fontDef.stretch != 100) { + transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); + } + + QCFType baseFont = CTFontCreateWithName(QCFString(fontDef.family), fontDef.pixelSize, &transform); + QCFType ctFont = NULL; + // There is a side effect in Core Text: if we apply 0 as symbolic traits to a font in normal weight, + // we will get the light version of that font (while the way supposed to work doesn't: + // setting kCTFontWeightTrait to some value between -1.0 to 0.0 has no effect on font selection) + if (fontDef.weight != QFont::Normal || symbolicTraits) + ctFont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, &transform, symbolicTraits, symbolicTraits); + + // CTFontCreateCopyWithSymbolicTraits returns NULL if we ask for a trait that does + // not exist for the given font. (for example italic) + if (ctFont == 0) { + ctFont = baseFont; + } + + if (ctFont) + return new QCoreTextFontEngine(ctFont, fontDef); + return 0; +} + +QT_END_NAMESPACE -- cgit v0.12