1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qbasicunixfontdatabase.h"
43
44 #include <QtGui/private/qapplication_p.h>
45 #include <QtGui/QPlatformScreen>
46
47 #include <QtCore/QFile>
48 #include <QtCore/QLibraryInfo>
49 #include <QtCore/QDir>
50
51 #undef QT_NO_FREETYPE
52 #include <QtGui/private/qfontengine_ft_p.h>
53 #include <QtGui/private/qfontengine_p.h>
54
55 #include <ft2build.h>
56 #include FT_TRUETYPE_TABLES_H
57
58 #define SimplifiedChineseCsbBit 18
59 #define TraditionalChineseCsbBit 20
60 #define JapaneseCsbBit 17
61 #define KoreanCsbBit 21
62
63 static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
64 // Any,
65 { 127, 127 },
66 // Latin,
67 { 0, 127 },
68 // Greek,
69 { 7, 127 },
70 // Cyrillic,
71 { 9, 127 },
72 // Armenian,
73 { 10, 127 },
74 // Hebrew,
75 { 11, 127 },
76 // Arabic,
77 { 13, 127 },
78 // Syriac,
79 { 71, 127 },
80 //Thaana,
81 { 72, 127 },
82 //Devanagari,
83 { 15, 127 },
84 //Bengali,
85 { 16, 127 },
86 //Gurmukhi,
87 { 17, 127 },
88 //Gujarati,
89 { 18, 127 },
90 //Oriya,
91 { 19, 127 },
92 //Tamil,
93 { 20, 127 },
94 //Telugu,
95 { 21, 127 },
96 //Kannada,
97 { 22, 127 },
98 //Malayalam,
99 { 23, 127 },
100 //Sinhala,
101 { 73, 127 },
102 //Thai,
103 { 24, 127 },
104 //Lao,
105 { 25, 127 },
106 //Tibetan,
107 { 70, 127 },
108 //Myanmar,
109 { 74, 127 },
110 // Georgian,
111 { 26, 127 },
112 // Khmer,
113 { 80, 127 },
114 // SimplifiedChinese,
115 { 126, 127 },
116 // TraditionalChinese,
117 { 126, 127 },
118 // Japanese,
119 { 126, 127 },
120 // Korean,
121 { 56, 127 },
122 // Vietnamese,
123 { 0, 127 }, // same as latin1
124 // Other,
125 { 126, 127 },
126 // Ogham,
127 { 78, 127 },
128 // Runic,
129 { 79, 127 },
130 // Nko,
131 { 14, 127 },
132 };
133
determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4],quint32 codePageRange[2])134 static QSupportedWritingSystems determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2])
135 {
136 QSupportedWritingSystems writingSystems;
137 bool hasScript = false;
138
139 int i;
140 for(i = 0; i < QFontDatabase::WritingSystemsCount; i++) {
141 int bit = requiredUnicodeBits[i][0];
142 int index = bit/32;
143 int flag = 1 << (bit&31);
144 if (bit != 126 && unicodeRange[index] & flag) {
145 bit = requiredUnicodeBits[i][1];
146 index = bit/32;
147
148 flag = 1 << (bit&31);
149 if (bit == 127 || unicodeRange[index] & flag) {
150 writingSystems.setSupported(QFontDatabase::WritingSystem(i));
151 hasScript = true;
152 // qDebug("font %s: index=%d, flag=%8x supports script %d", familyName.latin1(), index, flag, i);
153 }
154 }
155 }
156 if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) {
157 writingSystems.setSupported(QFontDatabase::SimplifiedChinese);
158 hasScript = true;
159 //qDebug("font %s supports Simplified Chinese", familyName.latin1());
160 }
161 if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
162 writingSystems.setSupported(QFontDatabase::TraditionalChinese);
163 hasScript = true;
164 //qDebug("font %s supports Traditional Chinese", familyName.latin1());
165 }
166 if(codePageRange[0] & (1 << JapaneseCsbBit)) {
167 writingSystems.setSupported(QFontDatabase::Japanese);
168 hasScript = true;
169 //qDebug("font %s supports Japanese", familyName.latin1());
170 }
171 if(codePageRange[0] & (1 << KoreanCsbBit)) {
172 writingSystems.setSupported(QFontDatabase::Korean);
173 hasScript = true;
174 //qDebug("font %s supports Korean", familyName.latin1());
175 }
176 if (!hasScript)
177 writingSystems.setSupported(QFontDatabase::Symbol);
178
179 return writingSystems;
180 }
181
scriptRequiresOpenType(int script)182 static inline bool scriptRequiresOpenType(int script)
183 {
184 return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
185 || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
186 }
187
populateFontDatabase()188 void QBasicUnixFontDatabase::populateFontDatabase()
189 {
190 QPlatformFontDatabase::populateFontDatabase();
191 QString fontpath = fontDir();
192
193 if(!QFile::exists(fontpath)) {
194 qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
195 qPrintable(fontpath));
196 }
197
198 QDir dir(fontpath);
199 dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
200 << QLatin1String("*.ttc") << QLatin1String("*.pfa")
201 << QLatin1String("*.pfb"));
202 dir.refresh();
203 for (int i = 0; i < int(dir.count()); ++i) {
204 const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
205 // qDebug() << "looking at" << file;
206 addTTFile(QByteArray(), file);
207 }
208 }
209
fontEngine(const QFontDef & fontDef,QUnicodeTables::Script script,void * usrPtr)210 QFontEngine *QBasicUnixFontDatabase::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *usrPtr)
211 {
212 QFontEngineFT *engine;
213 FontFile *fontfile = static_cast<FontFile *> (usrPtr);
214 QFontEngine::FaceId fid;
215 fid.filename = fontfile->fileName.toLocal8Bit();
216 fid.index = fontfile->indexValue;
217 engine = new QFontEngineFT(fontDef);
218
219 bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
220 QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono;
221 if (!engine->init(fid,antialias,format)) {
222 delete engine;
223 engine = 0;
224 return engine;
225 }
226 if (engine->invalid()) {
227 delete engine;
228 engine = 0;
229 } else if (scriptRequiresOpenType(script)) {
230 HB_Face hbFace = engine->harfbuzzFace();
231 if (!hbFace || !hbFace->supported_scripts[script]) {
232 delete engine;
233 engine = 0;
234 }
235 }
236
237 return engine;
238 }
239
fallbacksForFamily(const QString family,const QFont::Style & style,const QFont::StyleHint & styleHint,const QUnicodeTables::Script & script) const240 QStringList QBasicUnixFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
241 {
242 Q_UNUSED(family);
243 Q_UNUSED(style);
244 Q_UNUSED(styleHint);
245 Q_UNUSED(script);
246 return QStringList();
247 }
248
addApplicationFont(const QByteArray & fontData,const QString & fileName)249 QStringList QBasicUnixFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
250 {
251 return addTTFile(fontData,fileName.toLocal8Bit());
252 }
253
releaseHandle(void * handle)254 void QBasicUnixFontDatabase::releaseHandle(void *handle)
255 {
256 FontFile *file = static_cast<FontFile *>(handle);
257 delete file;
258 }
259
addTTFile(const QByteArray & fontData,const QByteArray & file)260 QStringList QBasicUnixFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file)
261 {
262 extern FT_Library qt_getFreetype();
263 FT_Library library = qt_getFreetype();
264
265 int index = 0;
266 int numFaces = 0;
267 QStringList families;
268 do {
269 FT_Face face;
270 FT_Error error;
271 if (!fontData.isEmpty()) {
272 error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face);
273 } else {
274 error = FT_New_Face(library, file.constData(), index, &face);
275 }
276 if (error != FT_Err_Ok) {
277 qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error;
278 break;
279 }
280 numFaces = face->num_faces;
281
282 QFont::Weight weight = QFont::Normal;
283
284 QFont::Style style = QFont::StyleNormal;
285 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
286 style = QFont::StyleItalic;
287
288 if (face->style_flags & FT_STYLE_FLAG_BOLD)
289 weight = QFont::Bold;
290
291 QSupportedWritingSystems writingSystems;
292 // detect symbol fonts
293 for (int i = 0; i < face->num_charmaps; ++i) {
294 FT_CharMap cm = face->charmaps[i];
295 if (cm->encoding == ft_encoding_adobe_custom
296 || cm->encoding == ft_encoding_symbol) {
297 writingSystems.setSupported(QFontDatabase::Symbol);
298 break;
299 }
300 }
301
302 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
303 if (os2) {
304 quint32 unicodeRange[4] = {
305 quint32(os2->ulUnicodeRange1), quint32(os2->ulUnicodeRange2),
306 quint32(os2->ulUnicodeRange3), quint32(os2->ulUnicodeRange4)
307 };
308 quint32 codePageRange[2] = {
309 quint32(os2->ulCodePageRange1), quint32(os2->ulCodePageRange2)
310 };
311
312 writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
313 }
314
315 QString family = QString::fromAscii(face->family_name);
316 FontFile *fontFile = new FontFile;
317 fontFile->fileName = file;
318 fontFile->indexValue = index;
319
320 QFont::Stretch stretch = QFont::Unstretched;
321
322 registerFont(family,"",weight,style,stretch,true,true,0,writingSystems,fontFile);
323
324 families.append(family);
325
326 FT_Done_Face(face);
327 ++index;
328 } while (index < numFaces);
329 return families;
330 }
331