Fix uses of qRound on non-floating-point types.
[profile/ivi/qtbase.git] / src / gui / text / qfontdatabase_x11.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
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
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
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
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
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
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 '-'
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
471 static inline bool isZero(char *x)
472 {
473     return (x[0] == '0' && x[1] == 0);
474 }
475
476 static inline bool isScalable(char **tokens)
477 {
478     return (isZero(tokens[PixelSize]) &&
479             isZero(tokens[PointSize]) &&
480             isZero(tokens[AverageWidth]));
481 }
482
483 static inline bool isSmoothlyScalable(char **tokens)
484 {
485     return (isZero(tokens[ResolutionX]) &&
486             isZero(tokens[ResolutionY]));
487 }
488
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 */
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 */
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
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
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
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
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
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
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
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
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
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->smoothScalable = true;
1365
1366                 QtFontSize *equiv_size = equiv->pixelSize(SMOOTH_SCALABLE, true);
1367                 QtFontEncoding *equiv_enc = equiv_size->encodingID(-1, 0, 0, 0, 0, true);
1368
1369                 // keep the same pitch
1370                 equiv_enc->pitch = enc->pitch;
1371             }
1372         }
1373     }
1374 #endif
1375
1376
1377 #ifdef QFONTDATABASE_DEBUG
1378 #ifndef QT_NO_FONTCONFIG
1379     if (!X11->has_fontconfig)
1380 #endif
1381         // load everything at startup in debug mode.
1382         loadXlfds(0, -1);
1383
1384     // print the database
1385     for (int f = 0; f < db->count; f++) {
1386         QtFontFamily *family = db->families[f];
1387         FD_DEBUG("'%s' %s  fixed=%s", family->name.latin1(), (family->fixedPitch ? "fixed" : ""),
1388                  (family->fixedPitch ? "yes" : "no"));
1389         for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
1390             QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
1391             FD_DEBUG("\t%s: %s", QFontDatabase::writingSystemName(ws).toLatin1().constData(),
1392                      ((family->writingSystems[i] & QtFontFamily::Supported) ? "Supported" :
1393                       (family->writingSystems[i] & QtFontFamily::Unsupported) == QtFontFamily::Unsupported ?
1394                       "Unsupported" : "Unknown"));
1395         }
1396
1397         for (int fd = 0; fd < family->count; fd++) {
1398             QtFontFoundry *foundry = family->foundries[fd];
1399             FD_DEBUG("\t\t'%s'", foundry->name.latin1());
1400             for (int s = 0; s < foundry->count; s++) {
1401                 QtFontStyle *style = foundry->styles[s];
1402                 FD_DEBUG("\t\t\tstyle: style=%d weight=%d (%s)\n"
1403                          "\t\t\tstretch=%d (%s)",
1404                          style->key.style, style->key.weight,
1405                          style->weightName, style->key.stretch,
1406                          style->setwidthName ? style->setwidthName : "nil");
1407                 if (style->smoothScalable)
1408                     FD_DEBUG("\t\t\t\tsmooth scalable");
1409                 else if (style->bitmapScalable)
1410                     FD_DEBUG("\t\t\t\tbitmap scalable");
1411                 if (style->pixelSizes) {
1412                     qDebug("\t\t\t\t%d pixel sizes", style->count);
1413                     for (int z = 0; z < style->count; ++z) {
1414                         QtFontSize *size = style->pixelSizes + z;
1415                         for (int e = 0; e < size->count; ++e) {
1416                             FD_DEBUG("\t\t\t\t  size %5d pitch %c encoding %s",
1417                                      size->pixelSize,
1418                                      size->encodings[e].pitch,
1419                                      xlfd_for_id(size->encodings[e].encoding));
1420                         }
1421                     }
1422                 }
1423             }
1424         }
1425     }
1426 #endif // QFONTDATABASE_DEBUG
1427 }
1428
1429
1430 // --------------------------------------------------------------------------------------
1431 // font loader
1432 // --------------------------------------------------------------------------------------
1433
1434 static const char *styleHint(const QFontDef &request)
1435 {
1436     const char *stylehint = 0;
1437     switch (request.styleHint) {
1438     case QFont::SansSerif:
1439         stylehint = "sans-serif";
1440         break;
1441     case QFont::Serif:
1442         stylehint = "serif";
1443         break;
1444     case QFont::TypeWriter:
1445         stylehint = "monospace";
1446         break;
1447     default:
1448         if (request.fixedPitch)
1449             stylehint = "monospace";
1450         break;
1451     }
1452     return stylehint;
1453 }
1454
1455 #ifndef QT_NO_FONTCONFIG
1456
1457 void qt_addPatternProps(FcPattern *pattern, int screen, int script, const QFontDef &request)
1458 {
1459     double size_value = qMax(qreal(1.), request.pixelSize);
1460     FcPatternDel(pattern, FC_PIXEL_SIZE);
1461     FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size_value);
1462
1463     if (X11->display && QX11Info::appDepth(screen) <= 8) {
1464         FcPatternDel(pattern, FC_ANTIALIAS);
1465         // can't do antialiasing on 8bpp
1466         FcPatternAddBool(pattern, FC_ANTIALIAS, false);
1467     } else if (request.styleStrategy & (QFont::PreferAntialias|QFont::NoAntialias)) {
1468         FcPatternDel(pattern, FC_ANTIALIAS);
1469         FcPatternAddBool(pattern, FC_ANTIALIAS,
1470                          !(request.styleStrategy & QFont::NoAntialias));
1471     }
1472
1473     if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') {
1474         Q_ASSERT(script < QUnicodeTables::ScriptCount);
1475         FcLangSet *ls = FcLangSetCreate();
1476         FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
1477         FcPatternDel(pattern, FC_LANG);
1478         FcPatternAddLangSet(pattern, FC_LANG, ls);
1479         FcLangSetDestroy(ls);
1480     }
1481
1482     if (!request.styleName.isEmpty()) {
1483         QByteArray cs = request.styleName.toUtf8();
1484         FcPatternAddString(pattern, FC_STYLE, (const FcChar8 *) cs.constData());
1485         return;
1486     }
1487
1488     int weight_value = FC_WEIGHT_BLACK;
1489     if (request.weight == 0)
1490         weight_value = FC_WEIGHT_MEDIUM;
1491     else if (request.weight < (QFont::Light + QFont::Normal) / 2)
1492         weight_value = FC_WEIGHT_LIGHT;
1493     else if (request.weight < (QFont::Normal + QFont::DemiBold) / 2)
1494         weight_value = FC_WEIGHT_MEDIUM;
1495     else if (request.weight < (QFont::DemiBold + QFont::Bold) / 2)
1496         weight_value = FC_WEIGHT_DEMIBOLD;
1497     else if (request.weight < (QFont::Bold + QFont::Black) / 2)
1498         weight_value = FC_WEIGHT_BOLD;
1499     FcPatternDel(pattern, FC_WEIGHT);
1500     FcPatternAddInteger(pattern, FC_WEIGHT, weight_value);
1501
1502     int slant_value = FC_SLANT_ROMAN;
1503     if (request.style == QFont::StyleItalic)
1504         slant_value = FC_SLANT_ITALIC;
1505     else if (request.style == QFont::StyleOblique)
1506         slant_value = FC_SLANT_OBLIQUE;
1507     FcPatternDel(pattern, FC_SLANT);
1508     FcPatternAddInteger(pattern, FC_SLANT, slant_value);
1509
1510     int stretch = request.stretch;
1511     if (!stretch)
1512         stretch = 100;
1513     FcPatternDel(pattern, FC_WIDTH);
1514     FcPatternAddInteger(pattern, FC_WIDTH, stretch);
1515 }
1516
1517 static bool preferScalable(const QFontDef &request)
1518 {
1519     return request.styleStrategy & (QFont::PreferOutline|QFont::ForceOutline|QFont::PreferQuality|QFont::PreferAntialias);
1520 }
1521
1522
1523 static FcPattern *getFcPattern(const QFontPrivate *fp, int script, const QFontDef &request)
1524 {
1525     if (!X11->has_fontconfig)
1526         return 0;
1527
1528     FcPattern *pattern = FcPatternCreate();
1529     if (!pattern)
1530         return 0;
1531
1532     FcValue value;
1533     value.type = FcTypeString;
1534
1535     QtFontDesc desc;
1536     QStringList families_and_foundries = familyList(request);
1537     for (int i = 0; i < families_and_foundries.size(); ++i) {
1538         QString family, foundry;
1539         parseFontName(families_and_foundries.at(i), foundry, family);
1540         if (!family.isEmpty()) {
1541             QByteArray cs = family.toUtf8();
1542             value.u.s = (const FcChar8 *)cs.data();
1543             FcPatternAdd(pattern, FC_FAMILY, value, FcTrue);
1544         }
1545         if (i == 0) {
1546             QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, -1, &desc);
1547             if (!foundry.isEmpty()) {
1548                 QByteArray cs = foundry.toUtf8();
1549                 value.u.s = (const FcChar8 *)cs.data();
1550                 FcPatternAddWeak(pattern, FC_FOUNDRY, value, FcTrue);
1551             }
1552         }
1553     }
1554
1555     const char *stylehint = styleHint(request);
1556     if (stylehint) {
1557         value.u.s = (const FcChar8 *)stylehint;
1558         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1559     }
1560
1561     if (!request.ignorePitch) {
1562         char pitch_value = FC_PROPORTIONAL;
1563         if (request.fixedPitch || (desc.family && desc.family->fixedPitch))
1564             pitch_value = FC_MONO;
1565         FcPatternAddInteger(pattern, FC_SPACING, pitch_value);
1566     }
1567     FcPatternAddBool(pattern, FC_OUTLINE, !(request.styleStrategy & QFont::PreferBitmap));
1568     if (preferScalable(request) || (desc.style && desc.style->smoothScalable))
1569         FcPatternAddBool(pattern, FC_SCALABLE, true);
1570
1571     qt_addPatternProps(pattern, fp->screen, script, request);
1572
1573     FcConfigSubstitute(0, pattern, FcMatchPattern);
1574     FcDefaultSubstitute(pattern);
1575
1576     // these should only get added to the pattern _after_ substitution
1577     // append the default fallback font for the specified script
1578     extern QString qt_fallback_font_family(int);
1579     QString fallback = qt_fallback_font_family(script);
1580     if (!fallback.isEmpty()) {
1581         QByteArray cs = fallback.toUtf8();
1582         value.u.s = (const FcChar8 *)cs.data();
1583         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1584     }
1585
1586     // add the default family
1587     QString defaultFamily = QApplication::font().family();
1588     QByteArray cs = defaultFamily.toUtf8();
1589     value.u.s = (const FcChar8 *)cs.data();
1590     FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1591
1592     // add QFont::defaultFamily() to the list, for compatibility with
1593     // previous versions
1594     defaultFamily = QApplication::font().defaultFamily();
1595     cs = defaultFamily.toUtf8();
1596     value.u.s = (const FcChar8 *)cs.data();
1597     FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1598
1599     return pattern;
1600 }
1601
1602
1603 static void FcFontSetRemove(FcFontSet *fs, int at)
1604 {
1605     Q_ASSERT(at < fs->nfont);
1606     FcPatternDestroy(fs->fonts[at]);
1607     int len = (--fs->nfont - at) * sizeof(FcPattern *);;
1608     if (len > 0)
1609         memmove(fs->fonts + at, fs->fonts + at + 1, len);
1610 }
1611
1612 static QFontEngine *tryPatternLoad(FcPattern *match, int screen,
1613                                    const QFontDef &request, int script)
1614 {
1615 #ifdef FONT_MATCH_DEBUG
1616     FcChar8 *fam;
1617     FcPatternGetString(match, FC_FAMILY, 0, &fam);
1618     FM_DEBUG("==== trying %s\n", fam);
1619 #endif
1620     FM_DEBUG("passes charset test\n");
1621
1622     QFontEngineX11FT *engine = 0;
1623     if (!match) // probably no fonts available.
1624         goto done;
1625
1626     if (script != QUnicodeTables::Common) {
1627         // skip font if it doesn't support the language we want
1628         if (specialChars[script]) {
1629             // need to check the charset, as the langset doesn't work for these scripts
1630             FcCharSet *cs;
1631             if (FcPatternGetCharSet(match, FC_CHARSET, 0, &cs) != FcResultMatch)
1632                 goto done;
1633             if (!FcCharSetHasChar(cs, specialChars[script]))
1634                 goto done;
1635         } else if (*specialLanguages[script] != '\0'){
1636             FcLangSet *langSet = 0;
1637             if (FcPatternGetLangSet(match, FC_LANG, 0, &langSet) != FcResultMatch)
1638                 goto done;
1639             if (FcLangSetHasLang(langSet, (const FcChar8*)specialLanguages[script]) != FcLangEqual)
1640                 goto done;
1641         }
1642     }
1643
1644     // enforce non-antialiasing if requested. the ft font engine looks at this property.
1645     if (request.styleStrategy & QFont::NoAntialias) {
1646         FcPatternDel(match, FC_ANTIALIAS);
1647         FcPatternAddBool(match, FC_ANTIALIAS, false);
1648     }
1649
1650     engine = new QFontEngineX11FT(match, qt_FcPatternToQFontDef(match, request), screen);
1651     if (engine->invalid()) {
1652         FM_DEBUG("   --> invalid!\n");
1653         delete engine;
1654         engine = 0;
1655     } else if (scriptRequiresOpenType(script)) {
1656         HB_Face hbFace = engine->harfbuzzFace();
1657         if (!hbFace || !hbFace->supported_scripts[script]) {
1658             FM_DEBUG("  OpenType support missing for script\n");
1659             delete engine;
1660             engine = 0;
1661         }
1662     }
1663 done:
1664     return engine;
1665 }
1666
1667 FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request)
1668 {
1669     FcResult result;
1670     FcFontSet *fs = FcFontSort(0, pattern, FcTrue, 0, &result);
1671 #ifdef FONT_MATCH_DEBUG
1672     FM_DEBUG("first font in fontset:\n");
1673     FcPatternPrint(fs->fonts[0]);
1674 #endif
1675
1676     FcBool forceScalable = request.styleStrategy & QFont::ForceOutline;
1677
1678     // remove fonts if they are not scalable (and should be)
1679     if (forceScalable && fs) {
1680         for (int i = 0; i < fs->nfont; ++i) {
1681             FcPattern *font = fs->fonts[i];
1682             FcResult res;
1683             FcBool scalable;
1684             res = FcPatternGetBool(font, FC_SCALABLE, 0, &scalable);
1685             if (res != FcResultMatch || !scalable) {
1686                 FcFontSetRemove(fs, i);
1687 #ifdef FONT_MATCH_DEBUG
1688                 FM_DEBUG("removing pattern:");
1689                 FcPatternPrint(font);
1690 #endif
1691                 --i; // go back one
1692             }
1693         }
1694     }
1695
1696     FM_DEBUG("final pattern contains %d fonts\n", fs->nfont);
1697
1698     return fs;
1699 }
1700
1701 static QFontEngine *loadFc(const QFontPrivate *fp, int script, const QFontDef &request)
1702 {
1703     FM_DEBUG("===================== loadFc: script=%d family='%s'\n", script, request.family.toLatin1().data());
1704     FcPattern *pattern = getFcPattern(fp, script, request);
1705
1706 #ifdef FONT_MATCH_DEBUG
1707     FM_DEBUG("\n\nfinal FcPattern contains:\n");
1708     FcPatternPrint(pattern);
1709 #endif
1710
1711     QFontEngine *fe = 0;
1712     FcResult res;
1713     FcPattern *match = FcFontMatch(0, pattern, &res);
1714     fe = tryPatternLoad(match, fp->screen, request, script);
1715     if (!fe) {
1716         FcFontSet *fs = qt_fontSetForPattern(pattern, request);
1717
1718         if (match) {
1719             FcPatternDestroy(match);
1720             match = 0;
1721         }
1722
1723         if (fs) {
1724             for (int i = 0; !fe && i < fs->nfont; ++i) {
1725                 match = FcFontRenderPrepare(NULL, pattern, fs->fonts[i]);
1726                 fe = tryPatternLoad(match, fp->screen, request, script);
1727                 if (fe)
1728                     break;
1729                 FcPatternDestroy(match);
1730                 match = 0;
1731             }
1732             FcFontSetDestroy(fs);
1733         }
1734         FM_DEBUG("engine for script %d is %s\n", script, fe ? fe->fontDef.family.toLatin1().data(): "(null)");
1735     }
1736     if (fe
1737         && script == QUnicodeTables::Common
1738         && !(request.styleStrategy & QFont::NoFontMerging) && !fe->symbol) {
1739         fe = new QFontEngineMultiFT(fe, match, pattern, fp->screen, request);
1740     } else {
1741         FcPatternDestroy(pattern);
1742         if (match)
1743             FcPatternDestroy(match);
1744     }
1745     return fe;
1746 }
1747
1748 static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
1749 {
1750 #if FC_VERSION < 20402
1751     Q_UNUSED(data)
1752     return FcFreeTypeQuery(file, id, blanks, count);
1753 #else
1754     if (data.isEmpty())
1755         return FcFreeTypeQuery(file, id, blanks, count);
1756
1757     extern FT_Library qt_getFreetype();
1758     FT_Library lib = qt_getFreetype();
1759
1760     FcPattern *pattern = 0;
1761
1762     FT_Face face;
1763     if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) {
1764         *count = face->num_faces;
1765
1766         pattern = FcFreeTypeQueryFace(face, file, id, blanks);
1767
1768         FT_Done_Face(face);
1769     }
1770
1771     return pattern;
1772 #endif
1773 }
1774 #endif // QT_NO_FONTCONFIG
1775
1776 static QFontEngine *loadRaw(const QFontPrivate *fp, const QFontDef &request)
1777 {
1778     Q_ASSERT(fp && fp->rawMode);
1779
1780     QByteArray xlfd = request.family.toLatin1();
1781     FM_DEBUG("Loading XLFD (rawmode) '%s'", xlfd.data());
1782
1783     QFontEngine *fe;
1784     XFontStruct *xfs;
1785     if (!(xfs = XLoadQueryFont(QX11Info::display(), xlfd.data())))
1786         if (!(xfs = XLoadQueryFont(QX11Info::display(), "fixed")))
1787             return 0;
1788
1789     fe = new QFontEngineXLFD(xfs, xlfd, 0);
1790     if (! qt_fillFontDef(xfs, &fe->fontDef, fp->dpi, 0) &&
1791         ! qt_fillFontDef(xlfd, &fe->fontDef, fp->dpi, 0))
1792         fe->fontDef = QFontDef();
1793     return fe;
1794 }
1795
1796 QFontEngine *QFontDatabase::loadXlfd(int screen, int script, const QFontDef &request, int force_encoding_id)
1797 {
1798     QMutexLocker locker(fontDatabaseMutex());
1799
1800     QtFontDesc desc;
1801     FM_DEBUG() << "---> loadXlfd: request is" << request.family;
1802     QStringList families_and_foundries = familyList(request);
1803     const char *stylehint = styleHint(request);
1804     if (stylehint)
1805         families_and_foundries << QString::fromLatin1(stylehint);
1806     families_and_foundries << QString();
1807     FM_DEBUG() << "loadXlfd: list is" << families_and_foundries;
1808     for (int i = 0; i < families_and_foundries.size(); ++i) {
1809         QString family, foundry;
1810         QT_PREPEND_NAMESPACE(parseFontName)(families_and_foundries.at(i), foundry, family);
1811         FM_DEBUG("loadXlfd: >>>>>>>>>>>>>>trying to match '%s' encoding=%d", family.toLatin1().data(), force_encoding_id);
1812         QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, force_encoding_id, &desc, QList<int>(), true);
1813         if (desc.family)
1814             break;
1815     }
1816
1817     QFontEngine *fe = 0;
1818     if (force_encoding_id != -1
1819         || (request.styleStrategy & QFont::NoFontMerging)
1820         || (desc.family && desc.family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
1821         if (desc.family) {
1822             int px = desc.size->pixelSize;
1823             if (desc.style->smoothScalable && px == SMOOTH_SCALABLE)
1824                 px = request.pixelSize;
1825             else if (desc.style->bitmapScalable && px == 0)
1826                 px = request.pixelSize;
1827
1828             QByteArray xlfd("-");
1829             xlfd += desc.foundry->name.isEmpty() ? QByteArray("*") : desc.foundry->name.toLatin1();
1830             xlfd += '-';
1831             xlfd += desc.family->name.isEmpty() ? QByteArray("*") : desc.family->name.toLatin1();
1832             xlfd += '-';
1833             xlfd += desc.style->weightName ? desc.style->weightName : "*";
1834             xlfd += '-';
1835             xlfd += (desc.style->key.style == QFont::StyleItalic
1836                      ? 'i'
1837                      : (desc.style->key.style == QFont::StyleOblique ? 'o' : 'r'));
1838             xlfd += '-';
1839             xlfd += desc.style->setwidthName ? desc.style->setwidthName : "*";
1840             // ### handle add-style
1841             xlfd += "-*-";
1842             xlfd += QByteArray::number(px);
1843             xlfd += '-';
1844             xlfd += QByteArray::number(desc.encoding->xpoint);
1845             xlfd += '-';
1846             xlfd += QByteArray::number(desc.encoding->xres);
1847             xlfd += '-';
1848             xlfd += QByteArray::number(desc.encoding->yres);
1849             xlfd += '-';
1850             xlfd += desc.encoding->pitch;
1851             xlfd += '-';
1852             xlfd += QByteArray::number(desc.encoding->avgwidth);
1853             xlfd += '-';
1854             xlfd += xlfd_for_id(desc.encoding->encoding);
1855
1856             FM_DEBUG("    using XLFD: %s\n", xlfd.data());
1857
1858             const int mib = xlfd_encoding[desc.encoding->encoding].mib;
1859             XFontStruct *xfs;
1860             if ((xfs = XLoadQueryFont(QX11Info::display(), xlfd))) {
1861                 fe = new QFontEngineXLFD(xfs, xlfd, mib);
1862                 const int dpi = QX11Info::appDpiY();
1863                 if (!qt_fillFontDef(xfs, &fe->fontDef, dpi, &desc)
1864                     && !qt_fillFontDef(xlfd, &fe->fontDef, dpi, &desc)) {
1865                     initFontDef(desc, request, &fe->fontDef);
1866                 }
1867             }
1868         }
1869         if (!fe) {
1870             fe = new QFontEngineBox(request.pixelSize);
1871             fe->fontDef = QFontDef();
1872         }
1873     } else {
1874         QList<int> encodings;
1875         if (desc.encoding) {
1876             if (desc.encoding->encoding >= 0)
1877                 encodings.append(int(desc.encoding->encoding));
1878         }
1879
1880         if (desc.size) {
1881             // append all other encodings for the matched font
1882             for (int i = 0; i < desc.size->count; ++i) {
1883                 QtFontEncoding *e = desc.size->encodings + i;
1884                 if (e == desc.encoding || e->encoding < 0)
1885                     continue;                
1886                 encodings.append(int(e->encoding));
1887             }
1888         }
1889         // fill in the missing encodings
1890         const XlfdEncoding *enc = xlfd_encoding;
1891         for (; enc->name; ++enc) {
1892             if (!encodings.contains(enc->id) && enc->id >= 0) {
1893                 encodings.append(enc->id);
1894             }
1895         }
1896
1897 #if defined(FONT_MATCH_DEBUG)
1898         FM_DEBUG("    using MultiXLFD, encodings:");
1899         for (int i = 0; i < encodings.size(); ++i) {
1900             const int id = encodings.at(i);
1901             FM_DEBUG("      %2d: %s", xlfd_encoding[id].id, xlfd_encoding[id].name);
1902         }
1903 #endif
1904
1905         fe = new QFontEngineMultiXLFD(request, encodings, screen);
1906     }
1907     return fe;
1908 }
1909
1910 #if (defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6)) && defined(Q_CC_GNU) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
1911 #define NEEDS_GCC_BUG_WORKAROUND
1912 #endif
1913
1914 #ifdef NEEDS_GCC_BUG_WORKAROUND
1915 static inline void gccBugWorkaround(const QFontDef &req)
1916 {
1917     char buffer[8];
1918     snprintf(buffer, 8, "%f", req.pixelSize);
1919 }
1920 #endif
1921
1922 /*! \internal
1923   Loads a QFontEngine for the specified \a script that matches the
1924   QFontDef \e request member variable.
1925 */
1926 void QFontDatabase::load(const QFontPrivate *d, int script)
1927 {
1928     Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
1929
1930     // normalize the request to get better caching
1931     QFontDef req = d->request;
1932     if (req.pixelSize <= 0)
1933         req.pixelSize = qFloor(qt_pixelSize(req.pointSize, d->dpi) * 100.0 + 0.5) * 0.01;
1934     if (req.pixelSize < 1)
1935         req.pixelSize = 1;
1936
1937 #ifdef NEEDS_GCC_BUG_WORKAROUND
1938     // req.pixelSize ends up with a bogus value unless this workaround is called
1939     gccBugWorkaround(req);
1940 #endif
1941
1942     if (req.weight == 0)
1943         req.weight = QFont::Normal;
1944     if (req.stretch == 0)
1945         req.stretch = 100;
1946
1947     QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
1948     if (!d->engineData)
1949         getEngineData(d, key);
1950
1951     // the cached engineData could have already loaded the engine we want
1952     if (d->engineData->engines[script])
1953         return;
1954
1955     // set it to the actual pointsize, so QFontInfo will do the right thing
1956     if (req.pointSize < 0)
1957         req.pointSize = qt_pointSize(req.pixelSize, d->dpi);
1958
1959
1960     QFontEngine *fe = QFontCache::instance()->findEngine(key);
1961
1962     if (!fe) {
1963         QMutexLocker locker(fontDatabaseMutex());
1964         if (!privateDb()->count)
1965             initializeDb();
1966
1967         const bool mainThread = (qApp->thread() == QThread::currentThread());
1968         if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
1969             fe = new QTestFontEngine(req.pixelSize);
1970             fe->fontDef = req;
1971         } else if (d->rawMode) {
1972             if (mainThread)
1973                 fe = loadRaw(d, req);
1974 #ifndef QT_NO_FONTCONFIG
1975         } else if (X11->has_fontconfig) {
1976             fe = loadFc(d, script, req);
1977 #endif
1978         } else if (mainThread && qt_is_gui_used) {
1979             fe = loadXlfd(d->screen, script, req);
1980         }
1981         if (!fe) {
1982             fe = new QFontEngineBox(req.pixelSize);
1983             fe->fontDef = QFontDef();
1984         }
1985     }
1986     if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
1987         for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
1988             if (!d->engineData->engines[i]) {
1989                 d->engineData->engines[i] = fe;
1990                 fe->ref.ref();
1991             }
1992         }
1993     } else {
1994         d->engineData->engines[script] = fe;
1995         fe->ref.ref();
1996     }
1997     QFontCache::instance()->insertEngine(key, fe);
1998 }
1999
2000 // Needed for fontconfig version < 2.2.97
2001 #ifndef FC_FAMILYLANG
2002 #define FC_FAMILYLANG "familylang"
2003 #endif
2004
2005 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
2006 {
2007 #if defined(QT_NO_FONTCONFIG)
2008     return;
2009 #else
2010     if (!X11->has_fontconfig)
2011         return;
2012
2013     FcConfig *config = FcConfigGetCurrent();
2014     if (!config)
2015         return;
2016
2017     FcFontSet *set = FcConfigGetFonts(config, FcSetApplication);
2018     if (!set) {
2019         FcConfigAppFontAddFile(config, (const FcChar8 *)":/non-existent");
2020         set = FcConfigGetFonts(config, FcSetApplication); // try again
2021         if (!set)
2022             return;
2023     }
2024
2025     QString fileNameForQuery = fnt->fileName;
2026 #if FC_VERSION < 20402
2027     QTemporaryFile tmp;
2028
2029     if (!fnt->data.isEmpty()) {
2030         if (!tmp.open())
2031             return;
2032         tmp.write(fnt->data);
2033         tmp.flush();
2034         fileNameForQuery = tmp.fileName();
2035     }
2036 #endif
2037
2038     int id = 0;
2039     FcBlanks *blanks = FcConfigGetBlanks(0);
2040     int count = 0;
2041
2042     QStringList families;
2043     QFontDatabasePrivate *db = privateDb();
2044
2045     FcPattern *pattern = 0;
2046     do {
2047         pattern = queryFont((const FcChar8 *)QFile::encodeName(fileNameForQuery).constData(),
2048                             fnt->data, id, blanks, &count);
2049         if (!pattern)
2050             return;
2051
2052         FcPatternDel(pattern, FC_FILE);
2053         QByteArray cs = fnt->fileName.toUtf8();
2054         FcPatternAddString(pattern, FC_FILE, (const FcChar8 *) cs.constData());
2055
2056         FcChar8 *fam = 0, *familylang = 0;
2057         int i, n = 0;
2058         for (i = 0; ; i++) {
2059             if (FcPatternGetString(pattern, FC_FAMILYLANG, i, &familylang) != FcResultMatch)
2060                 break;
2061             QString familyLang = QString::fromUtf8((const char *) familylang);
2062             if (familyLang.compare(db->systemLang, Qt::CaseInsensitive) == 0) {
2063                 n = i;
2064                 break;
2065             }
2066         }
2067
2068         if (FcPatternGetString(pattern, FC_FAMILY, n, &fam) == FcResultMatch) {
2069             QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
2070             families << family;
2071         }
2072
2073         if (!FcFontSetAdd(set, pattern))
2074             return;
2075
2076         ++id;
2077     } while (pattern && id < count);
2078
2079     fnt->families = families;
2080 #endif
2081 }
2082
2083 bool QFontDatabase::removeApplicationFont(int handle)
2084 {
2085 #if defined(QT_NO_FONTCONFIG)
2086     return false;
2087 #else
2088     QMutexLocker locker(fontDatabaseMutex());
2089
2090     QFontDatabasePrivate *db = privateDb();
2091     if (handle < 0 || handle >= db->applicationFonts.count())
2092         return false;
2093
2094     FcConfigAppFontClear(0);
2095
2096     db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
2097
2098     db->reregisterAppFonts = true;
2099     db->invalidate();
2100     return true;
2101 #endif
2102 }
2103
2104 bool QFontDatabase::removeAllApplicationFonts()
2105 {
2106 #if defined(QT_NO_FONTCONFIG)
2107     return false;
2108 #else
2109     QMutexLocker locker(fontDatabaseMutex());
2110
2111     QFontDatabasePrivate *db = privateDb();
2112     if (db->applicationFonts.isEmpty())
2113         return false;
2114
2115     FcConfigAppFontClear(0);
2116     db->applicationFonts.clear();
2117     db->invalidate();
2118     return true;
2119 #endif
2120 }
2121
2122 bool QFontDatabase::supportsThreadedFontRendering()
2123 {
2124 #if defined(QT_NO_FONTCONFIG)
2125     return false;
2126 #else
2127     return X11->has_fontconfig;
2128 #endif
2129 }
2130
2131 QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
2132 {
2133 #if defined(QT_NO_FONTCONFIG)
2134     return family;
2135 #else
2136     FcPattern *pattern = FcPatternCreate();
2137     if (!pattern)
2138         return family;
2139
2140     QByteArray cs = family.toUtf8();
2141     FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) cs.constData());
2142     FcConfigSubstitute(0, pattern, FcMatchPattern);
2143     FcDefaultSubstitute(pattern);
2144
2145     FcChar8 *familyAfterSubstitution;
2146     FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
2147     QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
2148     FcPatternDestroy(pattern);
2149
2150     return resolved;
2151 #endif
2152 }
2153
2154 QT_END_NAMESPACE