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