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 QtGui module 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 <qplatformdefs.h>
43 
44 #include <qdebug.h>
45 #include <qpaintdevice.h>
46 #include <qelapsedtimer.h>
47 
48 #include <private/qt_x11_p.h>
49 #include "qx11info_x11.h"
50 #include <qdebug.h>
51 #include <qfile.h>
52 #include <qtemporaryfile.h>
53 #include <qabstractfileengine.h>
54 #include <qmath.h>
55 
56 #include <ctype.h>
57 #include <stdlib.h>
58 
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <fcntl.h>
62 #include <sys/mman.h>
63 
64 #include <private/qfontengine_x11_p.h>
65 
66 #ifndef QT_NO_FONTCONFIG
67 #include <ft2build.h>
68 #include FT_FREETYPE_H
69 
70 #if FC_VERSION >= 20402
71 #include <fontconfig/fcfreetype.h>
72 #endif
73 #endif
74 
75 QT_BEGIN_NAMESPACE
76 
77 // from qfont_x11.cpp
78 extern double qt_pointSize(double pixelSize, int dpi);
79 extern double qt_pixelSize(double pointSize, int dpi);
80 
81 // from qapplication.cpp
82 extern bool qt_is_gui_used;
83 
capitalize(char * s)84 static inline void capitalize (char *s)
85 {
86     bool space = true;
87     while(*s) {
88         if (space)
89             *s = toupper(*s);
90         space = (*s == ' ');
91         ++s;
92     }
93 }
94 
95 
96 /*
97   To regenerate the writingSystems_for_xlfd_encoding table, run
98   'util/unicode/x11/makeencodings' and paste the generated
99   'encodings.c' here.
100 */
101 // ----- begin of generated code -----
102 
103 #define make_tag( c1, c2, c3, c4 )                              \
104     ((((unsigned int)c1)<<24) | (((unsigned int)c2)<<16) |      \
105      (((unsigned int)c3)<<8) | ((unsigned int)c4))
106 
107 struct XlfdEncoding {
108     const char *name;
109     int id;
110     int mib;
111     unsigned int hash1;
112     unsigned int hash2;
113 };
114 
115 static const XlfdEncoding xlfd_encoding[] = {
116     { "iso8859-1", 0, 4, make_tag('i','s','o','8'), make_tag('5','9','-','1') },
117     { "iso8859-2", 1, 5, make_tag('i','s','o','8'), make_tag('5','9','-','2') },
118     { "iso8859-3", 2, 6, make_tag('i','s','o','8'), make_tag('5','9','-','3') },
119     { "iso8859-4", 3, 7, make_tag('i','s','o','8'), make_tag('5','9','-','4') },
120     { "iso8859-9", 4, 12, make_tag('i','s','o','8'), make_tag('5','9','-','9') },
121     { "iso8859-10", 5, 13, make_tag('i','s','o','8'), make_tag('9','-','1','0') },
122     { "iso8859-13", 6, 109, make_tag('i','s','o','8'), make_tag('9','-','1','3') },
123     { "iso8859-14", 7, 110, make_tag('i','s','o','8'), make_tag('9','-','1','4') },
124     { "iso8859-15", 8, 111, make_tag('i','s','o','8'), make_tag('9','-','1','5') },
125     { "hp-roman8", 9, 2004, make_tag('h','p','-','r'), make_tag('m','a','n','8') },
126     { "iso8859-5", 10, 8, make_tag('i','s','o','8'), make_tag('5','9','-','5') },
127     { "*-cp1251", 11, 2251, 0, make_tag('1','2','5','1') },
128     { "koi8-ru", 12, 2084, make_tag('k','o','i','8'), make_tag('8','-','r','u') },
129     { "koi8-u", 13, 2088, make_tag('k','o','i','8'), make_tag('i','8','-','u') },
130     { "koi8-r", 14, 2084, make_tag('k','o','i','8'), make_tag('i','8','-','r') },
131     { "iso8859-7", 15, 10, make_tag('i','s','o','8'), make_tag('5','9','-','7') },
132     { "iso8859-8", 16, 85, make_tag('i','s','o','8'), make_tag('5','9','-','8') },
133     { "gb18030-0", 17, -114, make_tag('g','b','1','8'), make_tag('3','0','-','0') },
134     { "gb18030.2000-0", 18, -113, make_tag('g','b','1','8'), make_tag('0','0','-','0') },
135     { "gbk-0", 19, -113, make_tag('g','b','k','-'), make_tag('b','k','-','0') },
136     { "gb2312.*-0", 20, 57, make_tag('g','b','2','3'), 0 },
137     { "jisx0201*-0", 21, 15, make_tag('j','i','s','x'), 0 },
138     { "jisx0208*-0", 22, 63, make_tag('j','i','s','x'), 0 },
139     { "ksc5601*-*", 23, 36, make_tag('k','s','c','5'), 0 },
140     { "big5hkscs-0", 24, -2101, make_tag('b','i','g','5'), make_tag('c','s','-','0') },
141     { "hkscs-1", 25, -2101, make_tag('h','k','s','c'), make_tag('c','s','-','1') },
142     { "big5*-*", 26, -2026, make_tag('b','i','g','5'), 0 },
143     { "tscii-*", 27, 2028, make_tag('t','s','c','i'), 0 },
144     { "tis620*-*", 28, 2259, make_tag('t','i','s','6'), 0 },
145     { "iso8859-11", 29, 2259, make_tag('i','s','o','8'), make_tag('9','-','1','1') },
146     { "mulelao-1", 30, -4242, make_tag('m','u','l','e'), make_tag('a','o','-','1') },
147     { "ethiopic-unicode", 31, 0, make_tag('e','t','h','i'), make_tag('c','o','d','e') },
148     { "iso10646-1", 32, 0, make_tag('i','s','o','1'), make_tag('4','6','-','1') },
149     { "unicode-*", 33, 0, make_tag('u','n','i','c'), 0 },
150     { "*-symbol", 34, 0, 0, make_tag('m','b','o','l') },
151     { "*-fontspecific", 35, 0, 0, make_tag('i','f','i','c') },
152     { "fontspecific-*", 36, 0, make_tag('f','o','n','t'), 0 },
153     { 0, 0, 0, 0, 0 }
154 };
155 
156 static const char writingSystems_for_xlfd_encoding[sizeof(xlfd_encoding)][QFontDatabase::WritingSystemsCount] = {
157     // iso8859-1
158     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
159       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
160       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
161       0, 0 },
162     // iso8859-2
163     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
164       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
165       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
166       0, 0 },
167     // iso8859-3
168     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
169       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
170       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
171       0, 0 },
172     // iso8859-4
173     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
174       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
175       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
176       0, 0 },
177     // iso8859-9
178     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
179       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
180       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
181       0, 0 },
182     // iso8859-10
183     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
184       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
185       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186       0, 0 },
187     // iso8859-13
188     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
189       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
190       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191       0, 0 },
192     // iso8859-14
193     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
194       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
195       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
196       0, 0 },
197     // iso8859-15
198     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
199       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
200       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
201       0, 0 },
202     // hp-roman8
203     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
204       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
205       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
206       0, 0 },
207     // iso8859-5
208     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
209       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
211       0, 0 },
212     // *-cp1251
213     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
214       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
215       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
216       0, 0 },
217     // koi8-ru
218     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
219       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
220       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
221       0, 0 },
222     // koi8-u
223     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
224       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
225       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
226       0, 0 },
227     // koi8-r
228     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
229       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
230       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
231       0, 0 },
232     // iso8859-7
233     { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
234       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
235       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
236       0, 0 },
237     // iso8859-8
238     { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
239       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
240       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
241       0, 0 },
242     // gb18030-0
243     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
244       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
245       0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
246       0, 0 },
247     // gb18030.2000-0
248     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
249       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
250       0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
251       0, 0 },
252     // gbk-0
253     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
254       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
255       0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
256       0, 0 },
257     // gb2312.*-0
258     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
259       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
260       0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
261       0, 0 },
262     // jisx0201*-0
263     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
264       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
265       0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
266       0, 0 },
267     // jisx0208*-0
268     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
269       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
270       0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
271       0, 0 },
272     // ksc5601*-*
273     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
274       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
275       0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
276       0, 0 },
277     // big5hkscs-0
278     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
279       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
280       0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
281       0, 0 },
282     // hkscs-1
283     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
284       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
285       0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
286       0, 0 },
287     // big5*-*
288     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
289       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
290       0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
291       0, 0 },
292     // tscii-*
293     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
294       0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
295       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296       0, 0 },
297     // tis620*-*
298     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
299       0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
300       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
301       0, 0 },
302     // iso8859-11
303     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
304       0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
305       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
306       0, 0 },
307     // mulelao-1
308     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
309       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
310       1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
311       0, 0 },
312     // ethiopic-unicode
313     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
314       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
315       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
316       0, 0 },
317     // iso10646-1
318     { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
319       0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
320       1, 1, 0, 1, 0, 1, 1, 0, 0, 0,
321       0, 0 },
322     // unicode-*
323     { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
324       0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
325       1, 1, 0, 1, 0, 1, 1, 0, 0, 0,
326       0, 0 },
327     // *-symbol
328     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
329       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
330       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
331       1, 0 },
332     // *-fontspecific
333     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
334       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
335       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
336       1, 0 },
337     // fontspecific-*
338     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
339       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
340       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
341       1, 0 }
342 
343 };
344 
345 // ----- end of generated code -----
346 
347 
348 const int numEncodings = sizeof(xlfd_encoding) / sizeof(XlfdEncoding) - 1;
349 
qt_xlfd_encoding_id(const char * encoding)350 int qt_xlfd_encoding_id(const char *encoding)
351 {
352     // qDebug("looking for encoding id for '%s'", encoding);
353     int len = strlen(encoding);
354     if (len < 4)
355         return -1;
356     unsigned int hash1 = make_tag(encoding[0], encoding[1], encoding[2], encoding[3]);
357     const char *ch = encoding + len - 4;
358     unsigned int hash2 = make_tag(ch[0], ch[1], ch[2], ch[3]);
359 
360     const XlfdEncoding *enc = xlfd_encoding;
361     for (; enc->name; ++enc) {
362         if ((enc->hash1 && enc->hash1 != hash1) ||
363             (enc->hash2 && enc->hash2 != hash2))
364             continue;
365         // hashes match, do a compare if strings match
366         // the enc->name can contain '*'s we have to interpret correctly
367         const char *n = enc->name;
368         const char *e = encoding;
369         while (1) {
370             // qDebug("bol: *e='%c', *n='%c'", *e, *n);
371             if (*e == '\0') {
372                 if (*n)
373                     break;
374                 // qDebug("found encoding id %d", enc->id);
375                 return enc->id;
376             }
377             if (*e == *n) {
378                 ++e;
379                 ++n;
380                 continue;
381             }
382             if (*n != '*')
383                 break;
384             ++n;
385             // qDebug("skip: *e='%c', *n='%c'", *e, *n);
386             while (*e && *e != *n)
387                 ++e;
388         }
389     }
390     // qDebug("couldn't find encoding %s", encoding);
391     return -1;
392 }
393 
qt_mib_for_xlfd_encoding(const char * encoding)394 int qt_mib_for_xlfd_encoding(const char *encoding)
395 {
396     int id = qt_xlfd_encoding_id(encoding);
397     if (id != -1) return xlfd_encoding[id].mib;
398     return 0;
399 }
400 
qt_encoding_id_for_mib(int mib)401 int qt_encoding_id_for_mib(int mib)
402 {
403     const XlfdEncoding *enc = xlfd_encoding;
404     for (; enc->name; ++enc) {
405         if (enc->mib == mib)
406             return enc->id;
407     }
408     return -1;
409 }
410 
xlfd_for_id(int id)411 static const char * xlfd_for_id(int id)
412 {
413     // special case: -1 returns the "*-*" encoding, allowing us to do full
414     // database population in a single X server round trip.
415     if (id < 0 || id > numEncodings)
416         return "*-*";
417     return xlfd_encoding[id].name;
418 }
419 
420 enum XLFDFieldNames {
421     Foundry,
422     Family,
423     Weight,
424     Slant,
425     Width,
426     AddStyle,
427     PixelSize,
428     PointSize,
429     ResolutionX,
430     ResolutionY,
431     Spacing,
432     AverageWidth,
433     CharsetRegistry,
434     CharsetEncoding,
435     NFontFields
436 };
437 
438 // Splits an X font name into fields separated by '-'
parseXFontName(char * fontName,char ** tokens)439 static bool parseXFontName(char *fontName, char **tokens)
440 {
441     if (! fontName || fontName[0] == '0' || fontName[0] != '-') {
442         tokens[0] = 0;
443         return false;
444     }
445 
446     int          i;
447     ++fontName;
448     for (i = 0; i < NFontFields && fontName && fontName[0]; ++i) {
449         tokens[i] = fontName;
450         for (;; ++fontName) {
451             if (*fontName == '-')
452                 break;
453             if (! *fontName) {
454                 fontName = 0;
455                 break;
456             }
457         }
458 
459         if (fontName) *fontName++ = '\0';
460     }
461 
462     if (i < NFontFields) {
463         for (int j = i ; j < NFontFields; ++j)
464             tokens[j] = 0;
465         return false;
466     }
467 
468     return true;
469 }
470 
isZero(char * x)471 static inline bool isZero(char *x)
472 {
473     return (x[0] == '0' && x[1] == 0);
474 }
475 
isScalable(char ** tokens)476 static inline bool isScalable(char **tokens)
477 {
478     return (isZero(tokens[PixelSize]) &&
479             isZero(tokens[PointSize]) &&
480             isZero(tokens[AverageWidth]));
481 }
482 
isSmoothlyScalable(char ** tokens)483 static inline bool isSmoothlyScalable(char **tokens)
484 {
485     return (isZero(tokens[ResolutionX]) &&
486             isZero(tokens[ResolutionY]));
487 }
488 
isFixedPitch(char ** tokens)489 static inline bool isFixedPitch(char **tokens)
490 {
491     return (tokens[Spacing][0] == 'm' ||
492             tokens[Spacing][0] == 'c' ||
493             tokens[Spacing][0] == 'M' ||
494             tokens[Spacing][0] == 'C');
495 }
496 
497 /*
498   Fills in a font definition (QFontDef) from an XLFD (X Logical Font
499   Description).
500 
501   Returns true if the given xlfd is valid.
502 */
qt_fillFontDef(const QByteArray & xlfd,QFontDef * fd,int dpi,QtFontDesc * desc)503 bool qt_fillFontDef(const QByteArray &xlfd, QFontDef *fd, int dpi, QtFontDesc *desc)
504 {
505     char *tokens[NFontFields];
506     QByteArray buffer = xlfd;
507     if (! parseXFontName(buffer.data(), tokens))
508         return false;
509 
510     capitalize(tokens[Family]);
511     capitalize(tokens[Foundry]);
512 
513     fd->styleStrategy |= QFont::NoAntialias;
514     fd->family = QString::fromLatin1(tokens[Family]);
515     QString foundry = QString::fromLatin1(tokens[Foundry]);
516     if (! foundry.isEmpty() && foundry != QLatin1String("*") && (!desc || desc->family->count > 1))
517         fd->family +=
518             QLatin1String(" [") + foundry + QLatin1Char(']');
519 
520     if (qstrlen(tokens[AddStyle]) > 0)
521         fd->addStyle = QString::fromLatin1(tokens[AddStyle]);
522     else
523         fd->addStyle.clear();
524 
525     fd->pointSize = atoi(tokens[PointSize])/10.;
526     fd->styleHint = QFont::AnyStyle;        // ### any until we match families
527 
528     char slant = tolower((uchar) tokens[Slant][0]);
529     fd->style = (slant == 'o' ? QFont::StyleOblique : (slant == 'i' ? QFont::StyleItalic : QFont::StyleNormal));
530     char fixed = tolower((uchar) tokens[Spacing][0]);
531     fd->fixedPitch = (fixed == 'm' || fixed == 'c');
532     fd->weight = getFontWeight(QLatin1String(tokens[Weight]));
533 
534     int r = atoi(tokens[ResolutionY]);
535     fd->pixelSize = atoi(tokens[PixelSize]);
536     // not "0" or "*", or required DPI
537     if (r && fd->pixelSize && r != dpi) {
538         // calculate actual pointsize for display DPI
539         fd->pointSize = qt_pointSize(fd->pixelSize, dpi);
540     } else if (fd->pixelSize == 0 && fd->pointSize) {
541         // calculate pixel size from pointsize/dpi
542         fd->pixelSize = qRound(qt_pixelSize(fd->pointSize, dpi));
543     }
544 
545     return true;
546 }
547 
548 /*
549   Fills in a font definition (QFontDef) from the font properties in an
550   XFontStruct.
551 
552   Returns true if the QFontDef could be filled with properties from
553   the XFontStruct.
554 */
qt_fillFontDef(XFontStruct * fs,QFontDef * fd,int dpi,QtFontDesc * desc)555 static bool qt_fillFontDef(XFontStruct *fs, QFontDef *fd, int dpi, QtFontDesc *desc)
556 {
557     unsigned long value;
558     if (!fs || !XGetFontProperty(fs, XA_FONT, &value))
559         return false;
560 
561     char *n = XGetAtomName(QX11Info::display(), value);
562     QByteArray xlfd(n);
563     if (n)
564         XFree(n);
565     return qt_fillFontDef(xlfd.toLower(), fd, dpi, desc);
566 }
567 
568 
getStyle(char ** tokens)569 static QtFontStyle::Key getStyle(char ** tokens)
570 {
571     QtFontStyle::Key key;
572 
573     char slant0 = tolower((uchar) tokens[Slant][0]);
574 
575     if (slant0 == 'r') {
576         if (tokens[Slant][1]) {
577             char slant1 = tolower((uchar) tokens[Slant][1]);
578 
579             if (slant1 == 'o')
580                 key.style = QFont::StyleOblique;
581             else if (slant1 == 'i')
582                 key.style = QFont::StyleItalic;
583         }
584     } else if (slant0 == 'o')
585         key.style = QFont::StyleOblique;
586     else if (slant0 == 'i')
587         key.style = QFont::StyleItalic;
588 
589     key.weight = getFontWeight(QLatin1String(tokens[Weight]));
590 
591     if (qstrcmp(tokens[Width], "normal") == 0) {
592         key.stretch = 100;
593     } else if (qstrcmp(tokens[Width], "semi condensed") == 0 ||
594                qstrcmp(tokens[Width], "semicondensed") == 0) {
595         key.stretch = 90;
596     } else if (qstrcmp(tokens[Width], "condensed") == 0) {
597         key.stretch = 80;
598     } else if (qstrcmp(tokens[Width], "narrow") == 0) {
599         key.stretch = 60;
600     }
601 
602     return key;
603 }
604 
605 
606 static bool xlfdsFullyLoaded = false;
607 static unsigned char encodingLoaded[numEncodings];
608 
loadXlfds(const char * reqFamily,int encoding_id)609 static void loadXlfds(const char *reqFamily, int encoding_id)
610 {
611     QFontDatabasePrivate *db = privateDb();
612     QtFontFamily *fontFamily = reqFamily ? db->family(QLatin1String(reqFamily)) : 0;
613 
614     // make sure we don't load twice
615     if ((encoding_id == -1 && xlfdsFullyLoaded)
616         || (encoding_id != -1 && encodingLoaded[encoding_id]))
617         return;
618     if (fontFamily && fontFamily->xlfdLoaded)
619         return;
620 
621     int fontCount;
622     // force the X server to give us XLFDs
623     QByteArray xlfd_pattern("-*-");
624     xlfd_pattern += (reqFamily && reqFamily[0] != '\0') ? reqFamily : "*";
625     xlfd_pattern += "-*-*-*-*-*-*-*-*-*-*-";
626     xlfd_pattern += xlfd_for_id(encoding_id);
627 
628     char **fontList = XListFonts(QX11Info::display(),
629                                  xlfd_pattern,
630                                  0xffff, &fontCount);
631     // qDebug("requesting xlfd='%s', got %d fonts", xlfd_pattern.data(), fontCount);
632 
633 
634     char *tokens[NFontFields];
635 
636     for(int i = 0 ; i < fontCount ; i++) {
637         if (! parseXFontName(fontList[i], tokens))
638             continue;
639 
640         // get the encoding_id for this xlfd.  we need to do this
641         // here, since we can pass -1 to this function to do full
642         // database population
643         *(tokens[CharsetEncoding] - 1) = '-';
644         int encoding_id = qt_xlfd_encoding_id(tokens[CharsetRegistry]);
645         if (encoding_id == -1)
646             continue;
647 
648         char *familyName = tokens[Family];
649         capitalize(familyName);
650         char *foundryName = tokens[Foundry];
651         capitalize(foundryName);
652         QtFontStyle::Key styleKey = getStyle(tokens);
653 
654         bool smooth_scalable = false;
655         bool bitmap_scalable = false;
656         if (isScalable(tokens)) {
657             if (isSmoothlyScalable(tokens))
658                 smooth_scalable = true;
659             else
660                 bitmap_scalable = true;
661         }
662         uint pixelSize = atoi(tokens[PixelSize]);
663         uint xpointSize = atoi(tokens[PointSize]);
664         uint xres = atoi(tokens[ResolutionX]);
665         uint yres = atoi(tokens[ResolutionY]);
666         uint avgwidth = atoi(tokens[AverageWidth]);
667         bool fixedPitch = isFixedPitch(tokens);
668 
669         if (avgwidth == 0 && pixelSize != 0) {
670             /*
671               Ignore bitmap scalable fonts that are automatically
672               generated by some X servers.  We know they are bitmap
673               scalable because even though they have a specified pixel
674               size, the average width is zero.
675             */
676             continue;
677         }
678 
679         QtFontFamily *family = fontFamily ? fontFamily : db->family(QLatin1String(familyName), true);
680         family->fontFileIndex = -1;
681         family->symbol_checked = true;
682         QtFontFoundry *foundry = family->foundry(QLatin1String(foundryName), true);
683         QtFontStyle *style = foundry->style(styleKey, QString(), true);
684 
685         delete [] style->weightName;
686         style->weightName = qstrdup(tokens[Weight]);
687         delete [] style->setwidthName;
688         style->setwidthName = qstrdup(tokens[Width]);
689 
690         if (smooth_scalable) {
691             style->smoothScalable = true;
692             style->bitmapScalable = false;
693             pixelSize = SMOOTH_SCALABLE;
694         }
695         if (!style->smoothScalable && bitmap_scalable)
696             style->bitmapScalable = true;
697         if (!fixedPitch)
698             family->fixedPitch = false;
699 
700         QtFontSize *size = style->pixelSize(pixelSize, true);
701         QtFontEncoding *enc =
702             size->encodingID(encoding_id, xpointSize, xres, yres, avgwidth, true);
703         enc->pitch = *tokens[Spacing];
704         if (!enc->pitch) enc->pitch = '*';
705 
706         for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
707             if (writingSystems_for_xlfd_encoding[encoding_id][i])
708                 family->writingSystems[i] = QtFontFamily::Supported;
709         }
710     }
711     if (!reqFamily) {
712         // mark encoding as loaded
713         if (encoding_id == -1)
714             xlfdsFullyLoaded = true;
715         else
716             encodingLoaded[encoding_id] = true;
717     }
718 
719     XFreeFontNames(fontList);
720 }
721 
722 
723 #ifndef QT_NO_FONTCONFIG
724 
725 #ifndef FC_WIDTH
726 #define FC_WIDTH "width"
727 #endif
728 
getFCWeight(int fc_weight)729 static int getFCWeight(int fc_weight)
730 {
731     int qtweight = QFont::Black;
732     if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2)
733         qtweight = QFont::Light;
734     else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2)
735         qtweight = QFont::Normal;
736     else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2)
737         qtweight = QFont::DemiBold;
738     else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2)
739         qtweight = QFont::Bold;
740 
741     return qtweight;
742 }
743 
qt_FcPatternToQFontDef(FcPattern * pattern,const QFontDef & request)744 QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &request)
745 {
746     QFontDef fontDef;
747     fontDef.styleStrategy = request.styleStrategy;
748 
749     fontDef.hintingPreference = request.hintingPreference;
750     FcChar8 *value = 0;
751     if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) == FcResultMatch) {
752         fontDef.family = QString::fromUtf8(reinterpret_cast<const char *>(value));
753     }
754 
755     double dpi;
756     if (FcPatternGetDouble(pattern, FC_DPI, 0, &dpi) != FcResultMatch) {
757         if (X11->display)
758             dpi = QX11Info::appDpiY();
759         else
760             dpi = qt_defaultDpiY();
761     }
762 
763     double size;
764     if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
765         fontDef.pixelSize = size;
766     else
767         fontDef.pixelSize = 12;
768 
769     fontDef.pointSize = qt_pointSize(fontDef.pixelSize, qRound(dpi));
770 
771     /* ###
772        fontDef.styleHint
773     */
774 
775     int weight;
776     if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight) != FcResultMatch)
777         weight = FC_WEIGHT_MEDIUM;
778     fontDef.weight = getFCWeight(weight);
779 
780     int slant;
781     if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant) != FcResultMatch)
782         slant = FC_SLANT_ROMAN;
783     fontDef.style = (slant == FC_SLANT_ITALIC)
784                     ? QFont::StyleItalic
785                     : ((slant == FC_SLANT_OBLIQUE)
786                        ? QFont::StyleOblique
787                        : QFont::StyleNormal);
788 
789 
790     FcBool scalable;
791     if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch)
792         scalable = false;
793     if (scalable) {
794         fontDef.stretch = request.stretch;
795         fontDef.style = request.style;
796     } else {
797         int width;
798         if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width) == FcResultMatch)
799             fontDef.stretch = width;
800         else
801             fontDef.stretch = 100;
802     }
803 
804     int spacing;
805     if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing) == FcResultMatch) {
806         fontDef.fixedPitch = (spacing >= FC_MONO);
807         fontDef.ignorePitch = false;
808     } else {
809         fontDef.ignorePitch = true;
810     }
811 
812     return fontDef;
813 }
814 
815 static const char *specialLanguages[] = {
816     "en", // Common
817     "el", // Greek
818     "ru", // Cyrillic
819     "hy", // Armenian
820     "he", // Hebrew
821     "ar", // Arabic
822     "syr", // Syriac
823     "div", // Thaana
824     "hi", // Devanagari
825     "bn", // Bengali
826     "pa", // Gurmukhi
827     "gu", // Gujarati
828     "or", // Oriya
829     "ta", // Tamil
830     "te", // Telugu
831     "kn", // Kannada
832     "ml", // Malayalam
833     "si", // Sinhala
834     "th", // Thai
835     "lo", // Lao
836     "bo", // Tibetan
837     "my", // Myanmar
838     "ka", // Georgian
839     "ko", // Hangul
840     "", // Ogham
841     "", // Runic
842     "km", // Khmer
843     "" // N'Ko
844 };
845 enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) };
846 
847 static const ushort specialChars[] = {
848     0, // English
849     0, // Greek
850     0, // Cyrillic
851     0, // Armenian
852     0, // Hebrew
853     0, // Arabic
854     0, // Syriac
855     0, // Thaana
856     0, // Devanagari
857     0, // Bengali
858     0, // Gurmukhi
859     0, // Gujarati
860     0, // Oriya
861     0, // Tamil
862     0xc15, // Telugu
863     0xc95, // Kannada
864     0xd15, // Malayalam
865     0xd9a, // Sinhala
866     0, // Thai
867     0, // Lao
868     0, // Tibetan
869     0x1000, // Myanmar
870     0, // Georgian
871     0, // Hangul
872     0x1681, // Ogham
873     0x16a0, // Runic
874     0,  // Khmer
875     0x7ca // N'Ko
876 };
877 enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) };
878 
879 // this could become a list of all languages used for each writing
880 // system, instead of using the single most common language.
881 static const char *languageForWritingSystem[] = {
882     0,     // Any
883     "en",  // Latin
884     "el",  // Greek
885     "ru",  // Cyrillic
886     "hy",  // Armenian
887     "he",  // Hebrew
888     "ar",  // Arabic
889     "syr", // Syriac
890     "div", // Thaana
891     "hi",  // Devanagari
892     "bn",  // Bengali
893     "pa",  // Gurmukhi
894     "gu",  // Gujarati
895     "or",  // Oriya
896     "ta",  // Tamil
897     "te",  // Telugu
898     "kn",  // Kannada
899     "ml",  // Malayalam
900     "si",  // Sinhala
901     "th",  // Thai
902     "lo",  // Lao
903     "bo",  // Tibetan
904     "my",  // Myanmar
905     "ka",  // Georgian
906     "km",  // Khmer
907     "zh-cn", // SimplifiedChinese
908     "zh-tw", // TraditionalChinese
909     "ja",  // Japanese
910     "ko",  // Korean
911     "vi",  // Vietnamese
912     0, // Symbol
913     0, // Ogham
914     0, // Runic
915     0 // N'Ko
916 };
917 enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) };
918 
919 // Unfortunately FontConfig doesn't know about some languages. We have to test these through the
920 // charset. The lists below contain the systems where we need to do this.
921 static const ushort sampleCharForWritingSystem[] = {
922     0,     // Any
923     0,  // Latin
924     0,  // Greek
925     0,  // Cyrillic
926     0,  // Armenian
927     0,  // Hebrew
928     0,  // Arabic
929     0, // Syriac
930     0, // Thaana
931     0,  // Devanagari
932     0,  // Bengali
933     0,  // Gurmukhi
934     0,  // Gujarati
935     0,  // Oriya
936     0,  // Tamil
937     0xc15,  // Telugu
938     0xc95,  // Kannada
939     0xd15,  // Malayalam
940     0xd9a,  // Sinhala
941     0,  // Thai
942     0,  // Lao
943     0,  // Tibetan
944     0x1000,  // Myanmar
945     0,  // Georgian
946     0,  // Khmer
947     0, // SimplifiedChinese
948     0, // TraditionalChinese
949     0,  // Japanese
950     0,  // Korean
951     0,  // Vietnamese
952     0, // Symbol
953     0x1681, // Ogham
954     0x16a0, // Runic
955     0x7ca // N'Ko
956 };
957 enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) };
958 
959 // Newer FontConfig let's us sort out fonts that contain certain glyphs, but no
960 // open type tables for is directly. Do this so we don't pick some strange
961 // pseudo unicode font
962 static const char *openType[] = {
963     0,     // Any
964     0,  // Latin
965     0,  // Greek
966     0,  // Cyrillic
967     0,  // Armenian
968     0,  // Hebrew
969     0,  // Arabic
970     "syrc",  // Syriac
971     "thaa",  // Thaana
972     "deva",  // Devanagari
973     "beng",  // Bengali
974     "guru",  // Gurmukhi
975     "gurj",  // Gujarati
976     "orya",  // Oriya
977     "taml",  // Tamil
978     "telu",  // Telugu
979     "knda",  // Kannada
980     "mlym",  // Malayalam
981     "sinh",  // Sinhala
982     0,  // Thai
983     0,  // Lao
984     "tibt",  // Tibetan
985     "mymr",  // Myanmar
986     0,  // Georgian
987     "khmr",  // Khmer
988     0, // SimplifiedChinese
989     0, // TraditionalChinese
990     0,  // Japanese
991     0,  // Korean
992     0,  // Vietnamese
993     0, // Symbol
994     0, // Ogham
995     0, // Runic
996     "nko " // N'Ko
997 };
998 enum { OpenTypeCount = sizeof(openType) / sizeof(const char *) };
999 
1000 
loadFontConfig()1001 static void loadFontConfig()
1002 {
1003     Q_ASSERT_X(X11, "QFontDatabase",
1004                "A QApplication object needs to be constructed before FontConfig is used.");
1005     if (!X11->has_fontconfig)
1006         return;
1007 
1008     Q_ASSERT_X(int(QUnicodeTables::ScriptCount) == SpecialLanguageCount,
1009                "QFontDatabase", "New scripts have been added.");
1010     Q_ASSERT_X(int(QUnicodeTables::ScriptCount) == SpecialCharCount,
1011                "QFontDatabase", "New scripts have been added.");
1012     Q_ASSERT_X(int(QFontDatabase::WritingSystemsCount) == LanguageCount,
1013                "QFontDatabase", "New writing systems have been added.");
1014     Q_ASSERT_X(int(QFontDatabase::WritingSystemsCount) == SampleCharCount,
1015                "QFontDatabase", "New writing systems have been added.");
1016     Q_ASSERT_X(int(QFontDatabase::WritingSystemsCount) == OpenTypeCount,
1017                "QFontDatabase", "New writing systems have been added.");
1018 
1019     QFontDatabasePrivate *db = privateDb();
1020     FcFontSet  *fonts;
1021 
1022     FcPattern *pattern = FcPatternCreate();
1023     FcDefaultSubstitute(pattern);
1024     FcChar8 *lang = 0;
1025     if (FcPatternGetString(pattern, FC_LANG, 0, &lang) == FcResultMatch)
1026         db->systemLang = QString::fromUtf8((const char *) lang);
1027     FcPatternDestroy(pattern);
1028 
1029     QString familyName;
1030     FcChar8 *value = 0;
1031     int weight_value;
1032     int slant_value;
1033     int spacing_value;
1034     FcChar8 *file_value;
1035     int index_value;
1036     FcChar8 *foundry_value;
1037     FcChar8 *style_value;
1038     FcBool scalable;
1039 
1040     {
1041         FcObjectSet *os = FcObjectSetCreate();
1042         FcPattern *pattern = FcPatternCreate();
1043         const char *properties [] = {
1044             FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT,
1045             FC_SPACING, FC_FILE, FC_INDEX,
1046             FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT,
1047             FC_WIDTH,
1048 #if FC_VERSION >= 20297
1049             FC_CAPABILITY,
1050 #endif
1051             (const char *)0
1052         };
1053         const char **p = properties;
1054         while (*p) {
1055             FcObjectSetAdd(os, *p);
1056             ++p;
1057         }
1058         fonts = FcFontList(0, pattern, os);
1059         FcObjectSetDestroy(os);
1060         FcPatternDestroy(pattern);
1061     }
1062 
1063     for (int i = 0; i < fonts->nfont; i++) {
1064         if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
1065             continue;
1066         //         capitalize(value);
1067         familyName = QString::fromUtf8((const char *)value);
1068         slant_value = FC_SLANT_ROMAN;
1069         weight_value = FC_WEIGHT_MEDIUM;
1070         spacing_value = FC_PROPORTIONAL;
1071 	file_value = 0;
1072 	index_value = 0;
1073 	scalable = FcTrue;
1074 
1075         if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch)
1076 	    slant_value = FC_SLANT_ROMAN;
1077         if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch)
1078 	    weight_value = FC_WEIGHT_MEDIUM;
1079         if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch)
1080 	    spacing_value = FC_PROPORTIONAL;
1081         if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch)
1082 	    file_value = 0;
1083         if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &index_value) != FcResultMatch)
1084 	    index_value = 0;
1085         if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch)
1086 	    scalable = FcTrue;
1087         if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
1088 	    foundry_value = 0;
1089         if (FcPatternGetString(fonts->fonts[i], FC_STYLE, 0, &style_value) != FcResultMatch)
1090             style_value = 0;
1091         QtFontFamily *family = db->family(familyName, true);
1092 
1093         FcLangSet *langset = 0;
1094         FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset);
1095         if (res == FcResultMatch) {
1096             for (int i = 1; i < LanguageCount; ++i) {
1097                 const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i];
1098                 if (!lang) {
1099                     family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
1100                 } else {
1101                     FcLangResult langRes = FcLangSetHasLang(langset, lang);
1102                     if (langRes != FcLangDifferentLang)
1103                         family->writingSystems[i] = QtFontFamily::Supported;
1104                     else
1105                         family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
1106                 }
1107             }
1108             family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
1109             family->ftWritingSystemCheck = true;
1110         } else {
1111             // we set Other to supported for symbol fonts. It makes no
1112             // sense to merge these with other ones, as they are
1113             // special in a way.
1114             for (int i = 1; i < LanguageCount; ++i)
1115                 family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
1116             family->writingSystems[QFontDatabase::Other] = QtFontFamily::Supported;
1117         }
1118 
1119         FcCharSet *cs = 0;
1120         res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs);
1121         if (res == FcResultMatch) {
1122             // some languages are not supported by FontConfig, we rather check the
1123             // charset to detect these
1124             for (int i = 1; i < SampleCharCount; ++i) {
1125                 if (!sampleCharForWritingSystem[i])
1126                     continue;
1127                 if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i]))
1128                     family->writingSystems[i] = QtFontFamily::Supported;
1129             }
1130         }
1131 
1132 #if FC_VERSION >= 20297
1133         for (int j = 1; j < LanguageCount; ++j) {
1134             if (family->writingSystems[j] == QtFontFamily::Supported && requiresOpenType(j) && openType[j]) {
1135                 FcChar8 *cap;
1136                 res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap);
1137                 if (res != FcResultMatch || !strstr((const char *)cap, openType[j]))
1138                     family->writingSystems[j] = QtFontFamily::UnsupportedFT;
1139             }
1140         }
1141 #endif
1142 
1143         QByteArray file((const char *)file_value);
1144         family->fontFilename = file;
1145         family->fontFileIndex = index_value;
1146 
1147         QtFontStyle::Key styleKey;
1148         QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString();
1149         styleKey.style = (slant_value == FC_SLANT_ITALIC)
1150                          ? QFont::StyleItalic
1151                          : ((slant_value == FC_SLANT_OBLIQUE)
1152                             ? QFont::StyleOblique
1153                             : QFont::StyleNormal);
1154         styleKey.weight = getFCWeight(weight_value);
1155         if (!scalable) {
1156             int width = 100;
1157             FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width);
1158             styleKey.stretch = width;
1159         }
1160 
1161         QtFontFoundry *foundry
1162             = family->foundry(foundry_value ? QString::fromUtf8((const char *)foundry_value) : QString(), true);
1163         QtFontStyle *style = foundry->style(styleKey, styleName, true);
1164 
1165         if (spacing_value < FC_MONO)
1166             family->fixedPitch = false;
1167 
1168         QtFontSize *size;
1169         if (scalable) {
1170             style->smoothScalable = true;
1171             size = style->pixelSize(SMOOTH_SCALABLE, true);
1172         } else {
1173             double pixel_size = 0;
1174             FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size);
1175             size = style->pixelSize((int)pixel_size, true);
1176         }
1177         QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
1178         enc->pitch = (spacing_value >= FC_CHARCELL ? 'c' :
1179                       (spacing_value >= FC_MONO ? 'm' : 'p'));
1180     }
1181 
1182     FcFontSetDestroy (fonts);
1183 
1184     struct FcDefaultFont {
1185         const char *qtname;
1186         const char *rawname;
1187         bool fixed;
1188     };
1189     const FcDefaultFont defaults[] = {
1190         { "Serif", "serif", false },
1191         { "Sans Serif", "sans-serif", false },
1192         { "Monospace", "monospace", true },
1193         { 0, 0, false }
1194     };
1195     const FcDefaultFont *f = defaults;
1196     while (f->qtname) {
1197         QtFontFamily *family = db->family(QLatin1String(f->qtname), true);
1198         family->fixedPitch = f->fixed;
1199         family->synthetic = true;
1200         QtFontFoundry *foundry = family->foundry(QString(), true);
1201 
1202         // aliases only make sense for 'common', not for any of the specials
1203         for (int i = 1; i < LanguageCount; ++i) {
1204             if (requiresOpenType(i))
1205                 family->writingSystems[i] = QtFontFamily::UnsupportedFT;
1206             else
1207                 family->writingSystems[i] = QtFontFamily::Supported;
1208         }
1209         family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
1210 
1211         QtFontStyle::Key styleKey;
1212         for (int i = 0; i < 4; ++i) {
1213             styleKey.style = (i%2) ? QFont::StyleNormal : QFont::StyleItalic;
1214             styleKey.weight = (i > 1) ? QFont::Bold : QFont::Normal;
1215             QtFontStyle *style = foundry->style(styleKey, QString(), true);
1216             style->smoothScalable = true;
1217             QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE, true);
1218             QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
1219             enc->pitch = (f->fixed ? 'm' : 'p');
1220         }
1221         ++f;
1222     }
1223 }
1224 #endif // QT_NO_FONTCONFIG
1225 
1226 static void initializeDb();
1227 
load(const QString & family=QString (),int script=-1,bool forceXLFD=false)1228 static void load(const QString &family = QString(), int script = -1, bool forceXLFD = false)
1229 {
1230     if (X11->has_fontconfig && !forceXLFD) {
1231         initializeDb();
1232         return;
1233     }
1234 
1235 #ifdef QFONTDATABASE_DEBUG
1236     QElapsedTimer t;
1237     t.start();
1238 #endif
1239 
1240     if (family.isNull() && script == -1) {
1241         loadXlfds(0, -1);
1242     } else {
1243         if (family.isNull()) {
1244             // load all families in all writing systems that match \a script
1245             for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
1246                 if (scriptForWritingSystem[ws] != script)
1247                     continue;
1248                 for (int i = 0; i < numEncodings; ++i) {
1249                     if (writingSystems_for_xlfd_encoding[i][ws])
1250                         loadXlfds(0, i);
1251                 }
1252             }
1253         } else {
1254             QtFontFamily *f = privateDb()->family(family);
1255             // could reduce this further with some more magic:
1256             // would need to remember the encodings loaded for the family.
1257             if (!f || !f->xlfdLoaded)
1258                 loadXlfds(family.toLatin1(), -1);
1259         }
1260     }
1261 
1262 #ifdef QFONTDATABASE_DEBUG
1263     FD_DEBUG("QFontDatabase: load(%s, %d) took %d ms",
1264              family.toLatin1().constData(), script, t.elapsed());
1265 #endif
1266 }
1267 
checkSymbolFont(QtFontFamily * family)1268 static void checkSymbolFont(QtFontFamily *family)
1269 {
1270     if (!family || family->symbol_checked || family->fontFilename.isEmpty())
1271         return;
1272 //     qDebug() << "checking " << family->rawName;
1273     family->symbol_checked = true;
1274 
1275     QFontEngine::FaceId id;
1276     id.filename = family->fontFilename;
1277     id.index = family->fontFileIndex;
1278     QFreetypeFace *f = QFreetypeFace::getFace(id);
1279     if (!f) {
1280         qWarning("checkSymbolFonts: Couldn't open face %s (%s/%d)",
1281                  qPrintable(family->name), family->fontFilename.data(), family->fontFileIndex);
1282         return;
1283     }
1284     for (int i = 0; i < f->face->num_charmaps; ++i) {
1285         FT_CharMap cm = f->face->charmaps[i];
1286         if (cm->encoding == FT_ENCODING_ADOBE_CUSTOM
1287             || cm->encoding == FT_ENCODING_MS_SYMBOL) {
1288             for (int x = QFontDatabase::Latin; x < QFontDatabase::Other; ++x)
1289                 family->writingSystems[x] = QtFontFamily::Unsupported;
1290             family->writingSystems[QFontDatabase::Other] = QtFontFamily::Supported;
1291             break;
1292         }
1293     }
1294     f->release(id);
1295 }
1296 
checkSymbolFonts(const QString & family=QString ())1297 static void checkSymbolFonts(const QString &family = QString())
1298 {
1299 #ifndef QT_NO_FONTCONFIG
1300     QFontDatabasePrivate *d = privateDb();
1301 
1302     if (family.isEmpty()) {
1303         for (int i = 0; i < d->count; ++i)
1304             checkSymbolFont(d->families[i]);
1305     } else {
1306         checkSymbolFont(d->family(family));
1307     }
1308 #endif
1309 }
1310 
1311 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
1312 
initializeDb()1313 static void initializeDb()
1314 {
1315     QFontDatabasePrivate *db = privateDb();
1316     if (!db || db->count)
1317         return;
1318 
1319     QElapsedTimer t;
1320     t.start();
1321 
1322 #ifndef QT_NO_FONTCONFIG
1323     if (db->reregisterAppFonts) {
1324         db->reregisterAppFonts = false;
1325         for (int i = 0; i < db->applicationFonts.count(); ++i)
1326             if (!db->applicationFonts.at(i).families.isEmpty()) {
1327                 registerFont(&db->applicationFonts[i]);
1328             }
1329     }
1330 
1331     loadFontConfig();
1332     FD_DEBUG("QFontDatabase: loaded FontConfig: %d ms", int(t.elapsed()));
1333 #endif
1334 
1335     t.start();
1336 
1337 #ifndef QT_NO_FONTCONFIG
1338     for (int i = 0; i < db->count; i++) {
1339         for (int j = 0; j < db->families[i]->count; ++j) {        // each foundry
1340             QtFontFoundry *foundry = db->families[i]->foundries[j];
1341             for (int k = 0; k < foundry->count; ++k) {
1342                 QtFontStyle *style = foundry->styles[k];
1343                 if (style->key.style != QFont::StyleNormal) continue;
1344 
1345                 QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE);
1346                 if (! size) continue; // should not happen
1347                 QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
1348                 if (! enc) continue; // should not happen either
1349 
1350                 QtFontStyle::Key key = style->key;
1351 
1352                 // does this style have an italic equivalent?
1353                 key.style = QFont::StyleItalic;
1354                 QtFontStyle *equiv = foundry->style(key);
1355                 if (equiv) continue;
1356 
1357                 // does this style have an oblique equivalent?
1358                 key.style = QFont::StyleOblique;
1359                 equiv = foundry->style(key);
1360                 if (equiv) continue;
1361 
1362                 // let's fake one...
1363                 equiv = foundry->style(key, QString(), true);
1364                 equiv->styleName = styleStringHelper(key.weight, QFont::Style(key.style));
1365                 equiv->smoothScalable = true;
1366 
1367                 QtFontSize *equiv_size = equiv->pixelSize(SMOOTH_SCALABLE, true);
1368                 QtFontEncoding *equiv_enc = equiv_size->encodingID(-1, 0, 0, 0, 0, true);
1369 
1370                 // keep the same pitch
1371                 equiv_enc->pitch = enc->pitch;
1372             }
1373         }
1374     }
1375 #endif
1376 
1377 
1378 #ifdef QFONTDATABASE_DEBUG
1379 #ifndef QT_NO_FONTCONFIG
1380     if (!X11->has_fontconfig)
1381 #endif
1382         // load everything at startup in debug mode.
1383         loadXlfds(0, -1);
1384 
1385     // print the database
1386     for (int f = 0; f < db->count; f++) {
1387         QtFontFamily *family = db->families[f];
1388         FD_DEBUG("'%s' %s  fixed=%s", family->name.latin1(), (family->fixedPitch ? "fixed" : ""),
1389                  (family->fixedPitch ? "yes" : "no"));
1390         for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
1391             QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
1392             FD_DEBUG("\t%s: %s", QFontDatabase::writingSystemName(ws).toLatin1().constData(),
1393                      ((family->writingSystems[i] & QtFontFamily::Supported) ? "Supported" :
1394                       (family->writingSystems[i] & QtFontFamily::Unsupported) == QtFontFamily::Unsupported ?
1395                       "Unsupported" : "Unknown"));
1396         }
1397 
1398         for (int fd = 0; fd < family->count; fd++) {
1399             QtFontFoundry *foundry = family->foundries[fd];
1400             FD_DEBUG("\t\t'%s'", foundry->name.latin1());
1401             for (int s = 0; s < foundry->count; s++) {
1402                 QtFontStyle *style = foundry->styles[s];
1403                 FD_DEBUG("\t\t\tstyle: style=%d weight=%d (%s)\n"
1404                          "\t\t\tstretch=%d (%s)",
1405                          style->key.style, style->key.weight,
1406                          style->weightName, style->key.stretch,
1407                          style->setwidthName ? style->setwidthName : "nil");
1408                 if (style->smoothScalable)
1409                     FD_DEBUG("\t\t\t\tsmooth scalable");
1410                 else if (style->bitmapScalable)
1411                     FD_DEBUG("\t\t\t\tbitmap scalable");
1412                 if (style->pixelSizes) {
1413                     qDebug("\t\t\t\t%d pixel sizes", style->count);
1414                     for (int z = 0; z < style->count; ++z) {
1415                         QtFontSize *size = style->pixelSizes + z;
1416                         for (int e = 0; e < size->count; ++e) {
1417                             FD_DEBUG("\t\t\t\t  size %5d pitch %c encoding %s",
1418                                      size->pixelSize,
1419                                      size->encodings[e].pitch,
1420                                      xlfd_for_id(size->encodings[e].encoding));
1421                         }
1422                     }
1423                 }
1424             }
1425         }
1426     }
1427 #endif // QFONTDATABASE_DEBUG
1428 }
1429 
1430 
1431 // --------------------------------------------------------------------------------------
1432 // font loader
1433 // --------------------------------------------------------------------------------------
1434 
styleHint(const QFontDef & request)1435 static const char *styleHint(const QFontDef &request)
1436 {
1437     const char *stylehint = 0;
1438     switch (request.styleHint) {
1439     case QFont::SansSerif:
1440         stylehint = "sans-serif";
1441         break;
1442     case QFont::Serif:
1443         stylehint = "serif";
1444         break;
1445     case QFont::TypeWriter:
1446         stylehint = "monospace";
1447         break;
1448     default:
1449         if (request.fixedPitch)
1450             stylehint = "monospace";
1451         break;
1452     }
1453     return stylehint;
1454 }
1455 
1456 #ifndef QT_NO_FONTCONFIG
1457 
qt_addPatternProps(FcPattern * pattern,int screen,int script,const QFontDef & request)1458 void qt_addPatternProps(FcPattern *pattern, int screen, int script, const QFontDef &request)
1459 {
1460     double size_value = qMax(qreal(1.), request.pixelSize);
1461     FcPatternDel(pattern, FC_PIXEL_SIZE);
1462     FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size_value);
1463 
1464     if (X11->display && QX11Info::appDepth(screen) <= 8) {
1465         FcPatternDel(pattern, FC_ANTIALIAS);
1466         // can't do antialiasing on 8bpp
1467         FcPatternAddBool(pattern, FC_ANTIALIAS, false);
1468     } else if (request.styleStrategy & (QFont::PreferAntialias|QFont::NoAntialias)) {
1469         FcPatternDel(pattern, FC_ANTIALIAS);
1470         FcPatternAddBool(pattern, FC_ANTIALIAS,
1471                          !(request.styleStrategy & QFont::NoAntialias));
1472     }
1473 
1474     if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') {
1475         Q_ASSERT(script < QUnicodeTables::ScriptCount);
1476         FcLangSet *ls = FcLangSetCreate();
1477         FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
1478         FcPatternDel(pattern, FC_LANG);
1479         FcPatternAddLangSet(pattern, FC_LANG, ls);
1480         FcLangSetDestroy(ls);
1481     }
1482 
1483     if (!request.styleName.isEmpty()) {
1484         QByteArray cs = request.styleName.toUtf8();
1485         FcPatternAddString(pattern, FC_STYLE, (const FcChar8 *) cs.constData());
1486         return;
1487     }
1488 
1489     int weight_value = FC_WEIGHT_BLACK;
1490     if (request.weight == 0)
1491         weight_value = FC_WEIGHT_MEDIUM;
1492     else if (request.weight < (QFont::Light + QFont::Normal) / 2)
1493         weight_value = FC_WEIGHT_LIGHT;
1494     else if (request.weight < (QFont::Normal + QFont::DemiBold) / 2)
1495         weight_value = FC_WEIGHT_MEDIUM;
1496     else if (request.weight < (QFont::DemiBold + QFont::Bold) / 2)
1497         weight_value = FC_WEIGHT_DEMIBOLD;
1498     else if (request.weight < (QFont::Bold + QFont::Black) / 2)
1499         weight_value = FC_WEIGHT_BOLD;
1500     FcPatternDel(pattern, FC_WEIGHT);
1501     FcPatternAddInteger(pattern, FC_WEIGHT, weight_value);
1502 
1503     int slant_value = FC_SLANT_ROMAN;
1504     if (request.style == QFont::StyleItalic)
1505         slant_value = FC_SLANT_ITALIC;
1506     else if (request.style == QFont::StyleOblique)
1507         slant_value = FC_SLANT_OBLIQUE;
1508     FcPatternDel(pattern, FC_SLANT);
1509     FcPatternAddInteger(pattern, FC_SLANT, slant_value);
1510 
1511     int stretch = request.stretch;
1512     if (!stretch)
1513         stretch = 100;
1514     FcPatternDel(pattern, FC_WIDTH);
1515     FcPatternAddInteger(pattern, FC_WIDTH, stretch);
1516 }
1517 
preferScalable(const QFontDef & request)1518 static bool preferScalable(const QFontDef &request)
1519 {
1520     return request.styleStrategy & (QFont::PreferOutline|QFont::ForceOutline|QFont::PreferQuality|QFont::PreferAntialias);
1521 }
1522 
1523 
getFcPattern(const QFontPrivate * fp,int script,const QFontDef & request)1524 static FcPattern *getFcPattern(const QFontPrivate *fp, int script, const QFontDef &request)
1525 {
1526     if (!X11->has_fontconfig)
1527         return 0;
1528 
1529     FcPattern *pattern = FcPatternCreate();
1530     if (!pattern)
1531         return 0;
1532 
1533     FcValue value;
1534     value.type = FcTypeString;
1535 
1536     QtFontDesc desc;
1537     QStringList families_and_foundries = familyList(request);
1538     for (int i = 0; i < families_and_foundries.size(); ++i) {
1539         QString family, foundry;
1540         parseFontName(families_and_foundries.at(i), foundry, family);
1541         if (!family.isEmpty()) {
1542             QByteArray cs = family.toUtf8();
1543             value.u.s = (const FcChar8 *)cs.data();
1544             FcPatternAdd(pattern, FC_FAMILY, value, FcTrue);
1545         }
1546         if (i == 0) {
1547             QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, -1, &desc);
1548             if (!foundry.isEmpty()) {
1549                 QByteArray cs = foundry.toUtf8();
1550                 value.u.s = (const FcChar8 *)cs.data();
1551                 FcPatternAddWeak(pattern, FC_FOUNDRY, value, FcTrue);
1552             }
1553         }
1554     }
1555 
1556     const char *stylehint = styleHint(request);
1557     if (stylehint) {
1558         value.u.s = (const FcChar8 *)stylehint;
1559         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1560     }
1561 
1562     if (!request.ignorePitch) {
1563         char pitch_value = FC_PROPORTIONAL;
1564         if (request.fixedPitch || (desc.family && desc.family->fixedPitch))
1565             pitch_value = FC_MONO;
1566         FcPatternAddInteger(pattern, FC_SPACING, pitch_value);
1567     }
1568     FcPatternAddBool(pattern, FC_OUTLINE, !(request.styleStrategy & QFont::PreferBitmap));
1569     if (preferScalable(request) || (desc.style && desc.style->smoothScalable))
1570         FcPatternAddBool(pattern, FC_SCALABLE, true);
1571 
1572     qt_addPatternProps(pattern, fp->screen, script, request);
1573 
1574     FcConfigSubstitute(0, pattern, FcMatchPattern);
1575     FcDefaultSubstitute(pattern);
1576 
1577     // these should only get added to the pattern _after_ substitution
1578     // append the default fallback font for the specified script
1579     extern QString qt_fallback_font_family(int);
1580     QString fallback = qt_fallback_font_family(script);
1581     if (!fallback.isEmpty()) {
1582         QByteArray cs = fallback.toUtf8();
1583         value.u.s = (const FcChar8 *)cs.data();
1584         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1585     }
1586 
1587     // add the default family
1588     QString defaultFamily = QApplication::font().family();
1589     QByteArray cs = defaultFamily.toUtf8();
1590     value.u.s = (const FcChar8 *)cs.data();
1591     FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1592 
1593     // add QFont::defaultFamily() to the list, for compatibility with
1594     // previous versions
1595     defaultFamily = QApplication::font().defaultFamily();
1596     cs = defaultFamily.toUtf8();
1597     value.u.s = (const FcChar8 *)cs.data();
1598     FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1599 
1600     return pattern;
1601 }
1602 
1603 
FcFontSetRemove(FcFontSet * fs,int at)1604 static void FcFontSetRemove(FcFontSet *fs, int at)
1605 {
1606     Q_ASSERT(at < fs->nfont);
1607     FcPatternDestroy(fs->fonts[at]);
1608     int len = (--fs->nfont - at) * sizeof(FcPattern *);;
1609     if (len > 0)
1610         memmove(fs->fonts + at, fs->fonts + at + 1, len);
1611 }
1612 
tryPatternLoad(FcPattern * match,int screen,const QFontDef & request,int script)1613 static QFontEngine *tryPatternLoad(FcPattern *match, int screen,
1614                                    const QFontDef &request, int script)
1615 {
1616 #ifdef FONT_MATCH_DEBUG
1617     FcChar8 *fam;
1618     FcPatternGetString(match, FC_FAMILY, 0, &fam);
1619     FM_DEBUG("==== trying %s\n", fam);
1620 #endif
1621     FM_DEBUG("passes charset test\n");
1622 
1623     QFontEngineX11FT *engine = 0;
1624     if (!match) // probably no fonts available.
1625         goto done;
1626 
1627     if (script != QUnicodeTables::Common) {
1628         // skip font if it doesn't support the language we want
1629         if (specialChars[script]) {
1630             // need to check the charset, as the langset doesn't work for these scripts
1631             FcCharSet *cs;
1632             if (FcPatternGetCharSet(match, FC_CHARSET, 0, &cs) != FcResultMatch)
1633                 goto done;
1634             if (!FcCharSetHasChar(cs, specialChars[script]))
1635                 goto done;
1636         } else if (*specialLanguages[script] != '\0'){
1637             FcLangSet *langSet = 0;
1638             if (FcPatternGetLangSet(match, FC_LANG, 0, &langSet) != FcResultMatch)
1639                 goto done;
1640             if (FcLangSetHasLang(langSet, (const FcChar8*)specialLanguages[script]) != FcLangEqual)
1641                 goto done;
1642         }
1643     }
1644 
1645     // enforce non-antialiasing if requested. the ft font engine looks at this property.
1646     if (request.styleStrategy & QFont::NoAntialias) {
1647         FcPatternDel(match, FC_ANTIALIAS);
1648         FcPatternAddBool(match, FC_ANTIALIAS, false);
1649     }
1650 
1651     engine = new QFontEngineX11FT(match, qt_FcPatternToQFontDef(match, request), screen);
1652     if (engine->invalid()) {
1653         FM_DEBUG("   --> invalid!\n");
1654         delete engine;
1655         engine = 0;
1656     } else if (scriptRequiresOpenType(script)) {
1657         HB_Face hbFace = engine->harfbuzzFace();
1658         if (!hbFace || !hbFace->supported_scripts[script]) {
1659             FM_DEBUG("  OpenType support missing for script\n");
1660             delete engine;
1661             engine = 0;
1662         }
1663     }
1664 done:
1665     return engine;
1666 }
1667 
qt_fontSetForPattern(FcPattern * pattern,const QFontDef & request)1668 FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request)
1669 {
1670     FcResult result;
1671     FcFontSet *fs = FcFontSort(0, pattern, FcTrue, 0, &result);
1672 #ifdef FONT_MATCH_DEBUG
1673     FM_DEBUG("first font in fontset:\n");
1674     FcPatternPrint(fs->fonts[0]);
1675 #endif
1676 
1677     FcBool forceScalable = request.styleStrategy & QFont::ForceOutline;
1678 
1679     // remove fonts if they are not scalable (and should be)
1680     if (forceScalable && fs) {
1681         for (int i = 0; i < fs->nfont; ++i) {
1682             FcPattern *font = fs->fonts[i];
1683             FcResult res;
1684             FcBool scalable;
1685             res = FcPatternGetBool(font, FC_SCALABLE, 0, &scalable);
1686             if (res != FcResultMatch || !scalable) {
1687                 FcFontSetRemove(fs, i);
1688 #ifdef FONT_MATCH_DEBUG
1689                 FM_DEBUG("removing pattern:");
1690                 FcPatternPrint(font);
1691 #endif
1692                 --i; // go back one
1693             }
1694         }
1695     }
1696 
1697     FM_DEBUG("final pattern contains %d fonts\n", fs->nfont);
1698 
1699     return fs;
1700 }
1701 
loadFc(const QFontPrivate * fp,int script,const QFontDef & request)1702 static QFontEngine *loadFc(const QFontPrivate *fp, int script, const QFontDef &request)
1703 {
1704     FM_DEBUG("===================== loadFc: script=%d family='%s'\n", script, request.family.toLatin1().data());
1705     FcPattern *pattern = getFcPattern(fp, script, request);
1706 
1707 #ifdef FONT_MATCH_DEBUG
1708     FM_DEBUG("\n\nfinal FcPattern contains:\n");
1709     FcPatternPrint(pattern);
1710 #endif
1711 
1712     QFontEngine *fe = 0;
1713     FcResult res;
1714     FcPattern *match = FcFontMatch(0, pattern, &res);
1715     fe = tryPatternLoad(match, fp->screen, request, script);
1716     if (!fe) {
1717         FcFontSet *fs = qt_fontSetForPattern(pattern, request);
1718 
1719         if (match) {
1720             FcPatternDestroy(match);
1721             match = 0;
1722         }
1723 
1724         if (fs) {
1725             for (int i = 0; !fe && i < fs->nfont; ++i) {
1726                 match = FcFontRenderPrepare(NULL, pattern, fs->fonts[i]);
1727                 fe = tryPatternLoad(match, fp->screen, request, script);
1728                 if (fe)
1729                     break;
1730                 FcPatternDestroy(match);
1731                 match = 0;
1732             }
1733             FcFontSetDestroy(fs);
1734         }
1735         FM_DEBUG("engine for script %d is %s\n", script, fe ? fe->fontDef.family.toLatin1().data(): "(null)");
1736     }
1737     if (fe
1738         && script == QUnicodeTables::Common
1739         && !(request.styleStrategy & QFont::NoFontMerging) && !fe->symbol) {
1740         fe = new QFontEngineMultiFT(fe, match, pattern, fp->screen, request);
1741     } else {
1742         FcPatternDestroy(pattern);
1743     }
1744     if (match)
1745         FcPatternDestroy(match);
1746     return fe;
1747 }
1748 
queryFont(const FcChar8 * file,const QByteArray & data,int id,FcBlanks * blanks,int * count)1749 static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
1750 {
1751 #if FC_VERSION < 20402
1752     Q_UNUSED(data)
1753     return FcFreeTypeQuery(file, id, blanks, count);
1754 #else
1755     if (data.isEmpty())
1756         return FcFreeTypeQuery(file, id, blanks, count);
1757 
1758     extern FT_Library qt_getFreetype();
1759     FT_Library lib = qt_getFreetype();
1760 
1761     FcPattern *pattern = 0;
1762 
1763     FT_Face face;
1764     if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) {
1765         *count = face->num_faces;
1766 
1767         pattern = FcFreeTypeQueryFace(face, file, id, blanks);
1768 
1769         FT_Done_Face(face);
1770     }
1771 
1772     return pattern;
1773 #endif
1774 }
1775 #endif // QT_NO_FONTCONFIG
1776 
loadRaw(const QFontPrivate * fp,const QFontDef & request)1777 static QFontEngine *loadRaw(const QFontPrivate *fp, const QFontDef &request)
1778 {
1779     Q_ASSERT(fp && fp->rawMode);
1780 
1781     QByteArray xlfd = request.family.toLatin1();
1782     FM_DEBUG("Loading XLFD (rawmode) '%s'", xlfd.data());
1783 
1784     QFontEngine *fe;
1785     XFontStruct *xfs;
1786     if (!(xfs = XLoadQueryFont(QX11Info::display(), xlfd.data())))
1787         if (!(xfs = XLoadQueryFont(QX11Info::display(), "fixed")))
1788             return 0;
1789 
1790     fe = new QFontEngineXLFD(xfs, xlfd, 0);
1791     if (! qt_fillFontDef(xfs, &fe->fontDef, fp->dpi, 0) &&
1792         ! qt_fillFontDef(xlfd, &fe->fontDef, fp->dpi, 0))
1793         fe->fontDef = QFontDef();
1794     return fe;
1795 }
1796 
loadXlfd(int screen,int script,const QFontDef & request,int force_encoding_id)1797 QFontEngine *QFontDatabase::loadXlfd(int screen, int script, const QFontDef &request, int force_encoding_id)
1798 {
1799     QMutexLocker locker(fontDatabaseMutex());
1800 
1801     QtFontDesc desc;
1802     FM_DEBUG() << "---> loadXlfd: request is" << request.family;
1803     QStringList families_and_foundries = familyList(request);
1804     const char *stylehint = styleHint(request);
1805     if (stylehint)
1806         families_and_foundries << QString::fromLatin1(stylehint);
1807     families_and_foundries << QString();
1808     FM_DEBUG() << "loadXlfd: list is" << families_and_foundries;
1809     for (int i = 0; i < families_and_foundries.size(); ++i) {
1810         QString family, foundry;
1811         QT_PREPEND_NAMESPACE(parseFontName)(families_and_foundries.at(i), foundry, family);
1812         FM_DEBUG("loadXlfd: >>>>>>>>>>>>>>trying to match '%s' encoding=%d", family.toLatin1().data(), force_encoding_id);
1813         QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, force_encoding_id, &desc, QList<int>(), true);
1814         if (desc.family)
1815             break;
1816     }
1817 
1818     QFontEngine *fe = 0;
1819     if (force_encoding_id != -1
1820         || (request.styleStrategy & QFont::NoFontMerging)
1821         || (desc.family && desc.family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
1822         if (desc.family) {
1823             int px = desc.size->pixelSize;
1824             if (desc.style->smoothScalable && px == SMOOTH_SCALABLE)
1825                 px = request.pixelSize;
1826             else if (desc.style->bitmapScalable && px == 0)
1827                 px = request.pixelSize;
1828 
1829             QByteArray xlfd("-");
1830             xlfd += desc.foundry->name.isEmpty() ? QByteArray("*") : desc.foundry->name.toLatin1();
1831             xlfd += '-';
1832             xlfd += desc.family->name.isEmpty() ? QByteArray("*") : desc.family->name.toLatin1();
1833             xlfd += '-';
1834             xlfd += desc.style->weightName ? desc.style->weightName : "*";
1835             xlfd += '-';
1836             xlfd += (desc.style->key.style == QFont::StyleItalic
1837                      ? 'i'
1838                      : (desc.style->key.style == QFont::StyleOblique ? 'o' : 'r'));
1839             xlfd += '-';
1840             xlfd += desc.style->setwidthName ? desc.style->setwidthName : "*";
1841             // ### handle add-style
1842             xlfd += "-*-";
1843             xlfd += QByteArray::number(px);
1844             xlfd += '-';
1845             xlfd += QByteArray::number(desc.encoding->xpoint);
1846             xlfd += '-';
1847             xlfd += QByteArray::number(desc.encoding->xres);
1848             xlfd += '-';
1849             xlfd += QByteArray::number(desc.encoding->yres);
1850             xlfd += '-';
1851             xlfd += desc.encoding->pitch;
1852             xlfd += '-';
1853             xlfd += QByteArray::number(desc.encoding->avgwidth);
1854             xlfd += '-';
1855             xlfd += xlfd_for_id(desc.encoding->encoding);
1856 
1857             FM_DEBUG("    using XLFD: %s\n", xlfd.data());
1858 
1859             const int mib = xlfd_encoding[desc.encoding->encoding].mib;
1860             XFontStruct *xfs;
1861             if ((xfs = XLoadQueryFont(QX11Info::display(), xlfd))) {
1862                 fe = new QFontEngineXLFD(xfs, xlfd, mib);
1863                 const int dpi = QX11Info::appDpiY();
1864                 if (!qt_fillFontDef(xfs, &fe->fontDef, dpi, &desc)
1865                     && !qt_fillFontDef(xlfd, &fe->fontDef, dpi, &desc)) {
1866                     initFontDef(desc, request, &fe->fontDef);
1867                 }
1868             }
1869         }
1870         if (!fe) {
1871             fe = new QFontEngineBox(request.pixelSize);
1872             fe->fontDef = QFontDef();
1873         }
1874     } else {
1875         QList<int> encodings;
1876         if (desc.encoding) {
1877             if (desc.encoding->encoding >= 0)
1878                 encodings.append(int(desc.encoding->encoding));
1879         }
1880 
1881         if (desc.size) {
1882             // append all other encodings for the matched font
1883             for (int i = 0; i < desc.size->count; ++i) {
1884                 QtFontEncoding *e = desc.size->encodings + i;
1885                 if (e == desc.encoding || e->encoding < 0)
1886                     continue;
1887                 encodings.append(int(e->encoding));
1888             }
1889         }
1890         // fill in the missing encodings
1891         const XlfdEncoding *enc = xlfd_encoding;
1892         for (; enc->name; ++enc) {
1893             if (!encodings.contains(enc->id) && enc->id >= 0) {
1894                 encodings.append(enc->id);
1895             }
1896         }
1897 
1898 #if defined(FONT_MATCH_DEBUG)
1899         FM_DEBUG("    using MultiXLFD, encodings:");
1900         for (int i = 0; i < encodings.size(); ++i) {
1901             const int id = encodings.at(i);
1902             FM_DEBUG("      %2d: %s", xlfd_encoding[id].id, xlfd_encoding[id].name);
1903         }
1904 #endif
1905 
1906         fe = new QFontEngineMultiXLFD(request, encodings, screen);
1907     }
1908     return fe;
1909 }
1910 
1911 #if (defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6)) && defined(Q_CC_GNU) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
1912 #define NEEDS_GCC_BUG_WORKAROUND
1913 #endif
1914 
1915 #ifdef NEEDS_GCC_BUG_WORKAROUND
gccBugWorkaround(const QFontDef & req)1916 static inline void gccBugWorkaround(const QFontDef &req)
1917 {
1918     char buffer[8];
1919     snprintf(buffer, 8, "%f", req.pixelSize);
1920 }
1921 #endif
1922 
1923 /*! \internal
1924   Loads a QFontEngine for the specified \a script that matches the
1925   QFontDef \e request member variable.
1926 */
load(const QFontPrivate * d,int script)1927 void QFontDatabase::load(const QFontPrivate *d, int script)
1928 {
1929     Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
1930 
1931     // normalize the request to get better caching
1932     QFontDef req = d->request;
1933     if (req.pixelSize <= 0)
1934         req.pixelSize = qFloor(qt_pixelSize(req.pointSize, d->dpi) * 100.0 + 0.5) * 0.01;
1935     if (req.pixelSize < 1)
1936         req.pixelSize = 1;
1937 
1938 #ifdef NEEDS_GCC_BUG_WORKAROUND
1939     // req.pixelSize ends up with a bogus value unless this workaround is called
1940     gccBugWorkaround(req);
1941 #endif
1942 
1943     if (req.weight == 0)
1944         req.weight = QFont::Normal;
1945     if (req.stretch == 0)
1946         req.stretch = 100;
1947 
1948     QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
1949     if (!d->engineData)
1950         getEngineData(d, key);
1951 
1952     // the cached engineData could have already loaded the engine we want
1953     if (d->engineData->engines[script])
1954         return;
1955 
1956     // set it to the actual pointsize, so QFontInfo will do the right thing
1957     if (req.pointSize < 0)
1958         req.pointSize = qt_pointSize(req.pixelSize, d->dpi);
1959 
1960 
1961     QFontEngine *fe = QFontCache::instance()->findEngine(key);
1962 
1963     if (!fe) {
1964         QMutexLocker locker(fontDatabaseMutex());
1965         if (!privateDb()->count)
1966             initializeDb();
1967 
1968         const bool mainThread = (qApp->thread() == QThread::currentThread());
1969         if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
1970             fe = new QTestFontEngine(req.pixelSize);
1971             fe->fontDef = req;
1972         } else if (d->rawMode) {
1973             if (mainThread)
1974                 fe = loadRaw(d, req);
1975 #ifndef QT_NO_FONTCONFIG
1976         } else if (X11->has_fontconfig) {
1977             fe = loadFc(d, script, req);
1978 #endif
1979         } else if (mainThread && qt_is_gui_used) {
1980             fe = loadXlfd(d->screen, script, req);
1981         }
1982         if (!fe) {
1983             fe = new QFontEngineBox(req.pixelSize);
1984             fe->fontDef = QFontDef();
1985         }
1986     }
1987     if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
1988         for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
1989             if (!d->engineData->engines[i]) {
1990                 d->engineData->engines[i] = fe;
1991                 fe->ref.ref();
1992             }
1993         }
1994     } else {
1995         d->engineData->engines[script] = fe;
1996         fe->ref.ref();
1997     }
1998     QFontCache::instance()->insertEngine(key, fe);
1999 }
2000 
2001 // Needed for fontconfig version < 2.2.97
2002 #ifndef FC_FAMILYLANG
2003 #define FC_FAMILYLANG "familylang"
2004 #endif
2005 
registerFont(QFontDatabasePrivate::ApplicationFont * fnt)2006 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
2007 {
2008 #if defined(QT_NO_FONTCONFIG)
2009     return;
2010 #else
2011     if (!X11->has_fontconfig)
2012         return;
2013 
2014     FcConfig *config = FcConfigGetCurrent();
2015     if (!config)
2016         return;
2017 
2018     FcFontSet *set = FcConfigGetFonts(config, FcSetApplication);
2019     if (!set) {
2020         FcConfigAppFontAddFile(config, (const FcChar8 *)":/non-existent");
2021         set = FcConfigGetFonts(config, FcSetApplication); // try again
2022         if (!set)
2023             return;
2024     }
2025 
2026     QString fileNameForQuery = fnt->fileName;
2027 #if FC_VERSION < 20402
2028     QTemporaryFile tmp;
2029 
2030     if (!fnt->data.isEmpty()) {
2031         if (!tmp.open())
2032             return;
2033         tmp.write(fnt->data);
2034         tmp.flush();
2035         fileNameForQuery = tmp.fileName();
2036     }
2037 #endif
2038 
2039     int id = 0;
2040     FcBlanks *blanks = FcConfigGetBlanks(0);
2041     int count = 0;
2042 
2043     QStringList families;
2044     QFontDatabasePrivate *db = privateDb();
2045 
2046     FcPattern *pattern = 0;
2047     do {
2048         pattern = queryFont((const FcChar8 *)QFile::encodeName(fileNameForQuery).constData(),
2049                             fnt->data, id, blanks, &count);
2050         if (!pattern)
2051             return;
2052 
2053         FcPatternDel(pattern, FC_FILE);
2054         QByteArray cs = fnt->fileName.toUtf8();
2055         FcPatternAddString(pattern, FC_FILE, (const FcChar8 *) cs.constData());
2056 
2057         FcChar8 *fam = 0, *familylang = 0;
2058         int i, n = 0;
2059         for (i = 0; ; i++) {
2060             if (FcPatternGetString(pattern, FC_FAMILYLANG, i, &familylang) != FcResultMatch)
2061                 break;
2062             QString familyLang = QString::fromUtf8((const char *) familylang);
2063             if (familyLang.compare(db->systemLang, Qt::CaseInsensitive) == 0) {
2064                 n = i;
2065                 break;
2066             }
2067         }
2068 
2069         if (FcPatternGetString(pattern, FC_FAMILY, n, &fam) == FcResultMatch) {
2070             QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
2071             families << family;
2072         }
2073 
2074         if (!FcFontSetAdd(set, pattern))
2075             return;
2076 
2077         ++id;
2078     } while (pattern && id < count);
2079 
2080     fnt->families = families;
2081 #endif
2082 }
2083 
removeApplicationFont(int handle)2084 bool QFontDatabase::removeApplicationFont(int handle)
2085 {
2086 #if defined(QT_NO_FONTCONFIG)
2087     return false;
2088 #else
2089     QMutexLocker locker(fontDatabaseMutex());
2090 
2091     QFontDatabasePrivate *db = privateDb();
2092     if (handle < 0 || handle >= db->applicationFonts.count())
2093         return false;
2094 
2095     FcConfigAppFontClear(0);
2096 
2097     db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
2098 
2099     db->reregisterAppFonts = true;
2100     db->invalidate();
2101     return true;
2102 #endif
2103 }
2104 
removeAllApplicationFonts()2105 bool QFontDatabase::removeAllApplicationFonts()
2106 {
2107 #if defined(QT_NO_FONTCONFIG)
2108     return false;
2109 #else
2110     QMutexLocker locker(fontDatabaseMutex());
2111 
2112     QFontDatabasePrivate *db = privateDb();
2113     if (db->applicationFonts.isEmpty())
2114         return false;
2115 
2116     FcConfigAppFontClear(0);
2117     db->applicationFonts.clear();
2118     db->invalidate();
2119     return true;
2120 #endif
2121 }
2122 
supportsThreadedFontRendering()2123 bool QFontDatabase::supportsThreadedFontRendering()
2124 {
2125 #if defined(QT_NO_FONTCONFIG)
2126     return false;
2127 #else
2128     return X11->has_fontconfig;
2129 #endif
2130 }
2131 
resolveFontFamilyAlias(const QString & family)2132 QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
2133 {
2134 #if defined(QT_NO_FONTCONFIG)
2135     return family;
2136 #else
2137     FcPattern *pattern = FcPatternCreate();
2138     if (!pattern)
2139         return family;
2140 
2141     QByteArray cs = family.toUtf8();
2142     FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) cs.constData());
2143     FcConfigSubstitute(0, pattern, FcMatchPattern);
2144     FcDefaultSubstitute(pattern);
2145 
2146     FcChar8 *familyAfterSubstitution;
2147     FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
2148     QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
2149     FcPatternDestroy(pattern);
2150 
2151     return resolved;
2152 #endif
2153 }
2154 
2155 QT_END_NAMESPACE
2156