1/*
2 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
3 * Copyright (C) 2012 University of Szeged. All rights reserved.
4 *
5 * GNU Lesser General Public License Usage
6 * This file may be used under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation.
8 * Please review the following information to ensure the GNU Lesser
9 * General Public License version 2.1 requirements will be met:
10 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
11 *
12 * GNU General Public License Usage
13 * Alternatively, this file may be used under the terms of the GNU General
14 * Public License version 3.0 as published by the Free Software Foundation.
15 * Please review the following information to ensure the GNU General Public
16 * License version 3.0 requirements will be met:
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 */
20
21#include "TestFontDatabase.h"
22#include <QtCore/QDir>
23#include <QtCore/QFileInfo>
24#include <QtCore/private/qcore_mac_p.h>
25#include <QtPlatformSupport/private/qfontengine_coretext_p.h>
26#import <Foundation/Foundation.h>
27
28// From Qt.
29static const char *languageForWritingSystem[] = {
30 0, // Any
31 "en", // Latin
32 "el", // Greek
33 "ru", // Cyrillic
34 "hy", // Armenian
35 "he", // Hebrew
36 "ar", // Arabic
37 "syr", // Syriac
38 "div", // Thaana
39 "hi", // Devanagari
40 "bn", // Bengali
41 "pa", // Gurmukhi
42 "gu", // Gujarati
43 "or", // Oriya
44 "ta", // Tamil
45 "te", // Telugu
46 "kn", // Kannada
47 "ml", // Malayalam
48 "si", // Sinhala
49 "th", // Thai
50 "lo", // Lao
51 "bo", // Tibetan
52 "my", // Myanmar
53 "ka", // Georgian
54 "km", // Khmer
55 "zh-cn", // SimplifiedChinese
56 "zh-tw", // TraditionalChinese
57 "ja", // Japanese
58 "ko", // Korean
59 "vi", // Vietnamese
60 0, // Symbol
61 0, // Ogham
62 0, // Runic
63 0 // N'Ko
64};
65enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char*) };
66
67QFont TestFontDatabase::defaultFont() const
68{
69 return QFont(QStringLiteral("Nimbus Sans L"));
70}
71
72void TestFontDatabase::populateFontDatabase()
73{
74 // Determine the set of default system fonts in order to filter them out.
75 QCFType<CTFontCollectionRef> systemCollection(CTFontCollectionCreateFromAvailableFonts(0));
76 QCFType<CFArrayRef> systemFonts = systemCollection ? CTFontCollectionCreateMatchingFontDescriptors(systemCollection) : 0;
77 if (!systemFonts)
78 qFatal("Cannot get system fonts\n");
79
80 QByteArray testFontsVar = getenv("WEBKIT_TESTFONTS");
81 QDir fontsDir(QString::fromLatin1(testFontsVar));
82 if (testFontsVar.isEmpty() || !fontsDir.exists()) {
83 qFatal("\n\n"
84 "----------------------------------------------------------------------\n"
85 "QCoreTextFontDatabaseWKTest:\n"
86 "WEBKIT_TESTFONTS environment variable is not set correctly.\n"
87 "This variable has to point to the directory containing the fonts\n"
88 "you can clone from git://gitorious.org/qtwebkit/testfonts.git\n"
89 "----------------------------------------------------------------------\n"
90 );
91 }
92
93 QCFType<CFMutableSetRef> systemFontSet(CFSetCreateMutable(0, 0, &kCFTypeSetCallBacks));
94 for (int i = 0; i < CFArrayGetCount(systemFonts); ++i) {
95 CTFontDescriptorRef font = static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(systemFonts, i));
96 CFSetAddValue(systemFontSet, font);
97 }
98
99 // Add the test fonts to the set.
100 QStringList filters;
101 filters << QStringLiteral("*.ttf");
102 QFileInfoList files = fontsDir.entryInfoList(filters, QDir::Files);
103 foreach (QFileInfo file, files) {
104 QByteArray path = QFile::encodeName(file.canonicalFilePath());
105 QCFType<CFURLRef> fontFile(CFURLCreateFromFileSystemRepresentation(0, reinterpret_cast<const UInt8*>(path.constData()), path.length(), false));
106 CFErrorRef error;
107 if (!CTFontManagerRegisterFontsForURL(fontFile, kCTFontManagerScopeProcess, &error)) {
108 CFRelease(error);
109 qFatal("Failed registering font file: %s\n", path.constData());
110 }
111 }
112
113 // This substitution is done via fonts.conf on Linux.
114 QFont::insertSubstitution(QStringLiteral("Helvetica"), QString::fromLatin1(defaultWebKitTestFontFamily));
115
116 // ----------------------------------------------------------------------------
117 // This is a copy of QCoretextFontDatabase::populateFontDatabase from Qt except
118 // we filter out the system fonts.
119
120 QCFType<CTFontCollectionRef> collection = CTFontCollectionCreateFromAvailableFonts(0);
121 QCFType<CFArrayRef> fonts = CTFontCollectionCreateMatchingFontDescriptors(collection);
122
123 QString foundryName = QLatin1String("CoreText");
124 const int numFonts = CFArrayGetCount(fonts);
125 QHash<QString, QString> psNameToFamily;
126 for (int i = 0; i < numFonts; ++i) {
127 CTFontDescriptorRef font = static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(fonts, i));
128 if (CFSetGetCountOfValue(systemFontSet, font))
129 continue;
130 QCFString familyName = static_cast<CFStringRef>(CTFontDescriptorCopyLocalizedAttribute(font, kCTFontFamilyNameAttribute, NULL));
131 QCFType<CFDictionaryRef> styles = static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute));
132 QFont::Weight weight = QFont::Normal;
133 QFont::Style style = QFont::StyleNormal;
134 QFont::Stretch stretch = QFont::Unstretched;
135 bool fixedPitch = false;
136
137 if (styles) {
138 if (CFNumberRef weightValue = static_cast<CFNumberRef>(CFDictionaryGetValue(styles, kCTFontWeightTrait))) {
139 Q_ASSERT(CFNumberIsFloatType(weightValue));
140 double d;
141 if (CFNumberGetValue(weightValue, kCFNumberDoubleType, &d))
142 weight = (d > 0.0) ? QFont::Bold : QFont::Normal;
143 }
144 if (CFNumberRef italic = static_cast<CFNumberRef>(CFDictionaryGetValue(styles, kCTFontSlantTrait))) {
145 Q_ASSERT(CFNumberIsFloatType(italic));
146 double d;
147 if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) {
148 if (d > 0.0)
149 style = QFont::StyleItalic;
150 }
151 }
152 if (CFNumberRef symbolic = static_cast<CFNumberRef>(CFDictionaryGetValue(styles, kCTFontSymbolicTrait))) {
153 int d;
154 if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) {
155 if (d & kCTFontMonoSpaceTrait)
156 fixedPitch = true;
157 if (d & kCTFontExpandedTrait)
158 stretch = QFont::Expanded;
159 else if (d & kCTFontCondensedTrait)
160 stretch = QFont::Condensed;
161 }
162 }
163 }
164
165 int pixelSize = 0;
166 if (QCFType<CFNumberRef> size = static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute))) {
167 if (CFNumberIsFloatType(size)) {
168 double d;
169 CFNumberGetValue(size, kCFNumberDoubleType, &d);
170 pixelSize = d;
171 } else {
172 CFNumberGetValue(size, kCFNumberIntType, &pixelSize);
173 }
174 }
175
176 QSupportedWritingSystems writingSystems;
177 if (QCFType<CFArrayRef> languages = static_cast<CFArrayRef>(CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute))) {
178 CFIndex length = CFArrayGetCount(languages);
179 for (int i = 1; i < LanguageCount; ++i) {
180 if (!languageForWritingSystem[i])
181 continue;
182 QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII);
183 if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang))
184 writingSystems.setSupported(QFontDatabase::WritingSystem(i));
185 }
186 }
187
188 CFRetain(font);
189 QPlatformFontDatabase::registerFont(familyName, foundryName, weight, style, stretch,
190 true /* antialiased */, true /* scalable */,
191 pixelSize, fixedPitch, writingSystems, (void *) font);
192 CFStringRef psName = static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(font, kCTFontNameAttribute));
193 // we need PostScript Name to family name mapping for fallback list construction
194 psNameToFamily[QCFString::toQString((NSString *) psName)] = familyName;
195 CFRelease(psName);
196 }
197 // ----------------------------------------------------------------------------
198}