Update licenseheader text in source files for qtbase Qt module
[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, 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     FcBool scalable;
1038
1039     {
1040         FcObjectSet *os = FcObjectSetCreate();
1041         FcPattern *pattern = FcPatternCreate();
1042         const char *properties [] = {
1043             FC_FAMILY, FC_WEIGHT, FC_SLANT,
1044             FC_SPACING, FC_FILE, FC_INDEX,
1045             FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT,
1046             FC_WIDTH,
1047 #if FC_VERSION >= 20297
1048             FC_CAPABILITY,
1049 #endif
1050             (const char *)0
1051         };
1052         const char **p = properties;
1053         while (*p) {
1054             FcObjectSetAdd(os, *p);
1055             ++p;
1056         }
1057         fonts = FcFontList(0, pattern, os);
1058         FcObjectSetDestroy(os);
1059         FcPatternDestroy(pattern);
1060     }
1061
1062     for (int i = 0; i < fonts->nfont; i++) {
1063         if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
1064             continue;
1065         //         capitalize(value);
1066         familyName = QString::fromUtf8((const char *)value);
1067         slant_value = FC_SLANT_ROMAN;
1068         weight_value = FC_WEIGHT_MEDIUM;
1069         spacing_value = FC_PROPORTIONAL;
1070         file_value = 0;
1071         index_value = 0;
1072         scalable = FcTrue;
1073
1074         if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch)
1075             slant_value = FC_SLANT_ROMAN;
1076         if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch)
1077             weight_value = FC_WEIGHT_MEDIUM;
1078         if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch)
1079             spacing_value = FC_PROPORTIONAL;
1080         if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch)
1081             file_value = 0;
1082         if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &index_value) != FcResultMatch)
1083             index_value = 0;
1084         if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch)
1085             scalable = FcTrue;
1086         if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
1087             foundry_value = 0;
1088         QtFontFamily *family = db->family(familyName, true);
1089
1090         FcLangSet *langset = 0;
1091         FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset);
1092         if (res == FcResultMatch) {
1093             for (int i = 1; i < LanguageCount; ++i) {
1094                 const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i];
1095                 if (!lang) {
1096                     family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
1097                 } else {
1098                     FcLangResult langRes = FcLangSetHasLang(langset, lang);
1099                     if (langRes != FcLangDifferentLang)
1100                         family->writingSystems[i] = QtFontFamily::Supported;
1101                     else
1102                         family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
1103                 }
1104             }
1105             family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
1106             family->ftWritingSystemCheck = true;
1107         } else {
1108             // we set Other to supported for symbol fonts. It makes no
1109             // sense to merge these with other ones, as they are
1110             // special in a way.
1111             for (int i = 1; i < LanguageCount; ++i)
1112                 family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
1113             family->writingSystems[QFontDatabase::Other] = QtFontFamily::Supported;
1114         }
1115
1116         FcCharSet *cs = 0;
1117         res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs);
1118         if (res == FcResultMatch) {
1119             // some languages are not supported by FontConfig, we rather check the
1120             // charset to detect these
1121             for (int i = 1; i < SampleCharCount; ++i) {
1122                 if (!sampleCharForWritingSystem[i])
1123                     continue;
1124                 if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i]))
1125                     family->writingSystems[i] = QtFontFamily::Supported;
1126             }
1127         }
1128
1129 #if FC_VERSION >= 20297
1130         for (int j = 1; j < LanguageCount; ++j) {
1131             if (family->writingSystems[j] == QtFontFamily::Supported && requiresOpenType(j) && openType[j]) {
1132                 FcChar8 *cap;
1133                 res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap);
1134                 if (res != FcResultMatch || !strstr((const char *)cap, openType[j]))
1135                     family->writingSystems[j] = QtFontFamily::UnsupportedFT;
1136             }
1137         }
1138 #endif
1139
1140         QByteArray file((const char *)file_value);
1141         family->fontFilename = file;
1142         family->fontFileIndex = index_value;
1143
1144         QtFontStyle::Key styleKey;
1145         styleKey.style = (slant_value == FC_SLANT_ITALIC)
1146                          ? QFont::StyleItalic
1147                          : ((slant_value == FC_SLANT_OBLIQUE)
1148                             ? QFont::StyleOblique
1149                             : QFont::StyleNormal);
1150         styleKey.weight = getFCWeight(weight_value);
1151         if (!scalable) {
1152             int width = 100;
1153             FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width);
1154             styleKey.stretch = width;
1155         }
1156
1157         QtFontFoundry *foundry
1158             = family->foundry(foundry_value ? QString::fromUtf8((const char *)foundry_value) : QString(), true);
1159         QtFontStyle *style = foundry->style(styleKey, true);
1160
1161         if (spacing_value < FC_MONO)
1162             family->fixedPitch = false;
1163
1164         QtFontSize *size;
1165         if (scalable) {
1166             style->smoothScalable = true;
1167             size = style->pixelSize(SMOOTH_SCALABLE, true);
1168         } else {
1169             double pixel_size = 0;
1170             FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size);
1171             size = style->pixelSize((int)pixel_size, true);
1172         }
1173         QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
1174         enc->pitch = (spacing_value >= FC_CHARCELL ? 'c' :
1175                       (spacing_value >= FC_MONO ? 'm' : 'p'));
1176     }
1177
1178     FcFontSetDestroy (fonts);
1179
1180     struct FcDefaultFont {
1181         const char *qtname;
1182         const char *rawname;
1183         bool fixed;
1184     };
1185     const FcDefaultFont defaults[] = {
1186         { "Serif", "serif", false },
1187         { "Sans Serif", "sans-serif", false },
1188         { "Monospace", "monospace", true },
1189         { 0, 0, false }
1190     };
1191     const FcDefaultFont *f = defaults;
1192     while (f->qtname) {
1193         QtFontFamily *family = db->family(QLatin1String(f->qtname), true);
1194         family->fixedPitch = f->fixed;
1195         family->synthetic = true;
1196         QtFontFoundry *foundry = family->foundry(QString(), true);
1197
1198         // aliases only make sense for 'common', not for any of the specials
1199         for (int i = 1; i < LanguageCount; ++i) {
1200             if (requiresOpenType(i))
1201                 family->writingSystems[i] = QtFontFamily::UnsupportedFT;
1202             else
1203                 family->writingSystems[i] = QtFontFamily::Supported;
1204         }
1205         family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
1206
1207         QtFontStyle::Key styleKey;
1208         for (int i = 0; i < 4; ++i) {
1209             styleKey.style = (i%2) ? QFont::StyleNormal : QFont::StyleItalic;
1210             styleKey.weight = (i > 1) ? QFont::Bold : QFont::Normal;
1211             QtFontStyle *style = foundry->style(styleKey, true);
1212             style->smoothScalable = true;
1213             QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE, true);
1214             QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
1215             enc->pitch = (f->fixed ? 'm' : 'p');
1216         }
1217         ++f;
1218     }
1219 }
1220 #endif // QT_NO_FONTCONFIG
1221
1222 static void initializeDb();
1223
1224 static void load(const QString &family = QString(), int script = -1, bool forceXLFD = false)
1225 {
1226     if (X11->has_fontconfig && !forceXLFD) {
1227         initializeDb();
1228         return;
1229     }
1230
1231 #ifdef QFONTDATABASE_DEBUG
1232     QElapsedTimer t;
1233     t.start();
1234 #endif
1235
1236     if (family.isNull() && script == -1) {
1237         loadXlfds(0, -1);
1238     } else {
1239         if (family.isNull()) {
1240             // load all families in all writing systems that match \a script
1241             for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
1242                 if (scriptForWritingSystem[ws] != script)
1243                     continue;
1244                 for (int i = 0; i < numEncodings; ++i) {
1245                     if (writingSystems_for_xlfd_encoding[i][ws])
1246                         loadXlfds(0, i);
1247                 }
1248             }
1249         } else {
1250             QtFontFamily *f = privateDb()->family(family);
1251             // could reduce this further with some more magic:
1252             // would need to remember the encodings loaded for the family.
1253             if (!f || !f->xlfdLoaded)
1254                 loadXlfds(family.toLatin1(), -1);
1255         }
1256     }
1257
1258 #ifdef QFONTDATABASE_DEBUG
1259     FD_DEBUG("QFontDatabase: load(%s, %d) took %d ms",
1260              family.toLatin1().constData(), script, t.elapsed());
1261 #endif
1262 }
1263
1264 static void checkSymbolFont(QtFontFamily *family)
1265 {
1266     if (!family || family->symbol_checked || family->fontFilename.isEmpty())
1267         return;
1268 //     qDebug() << "checking " << family->rawName;
1269     family->symbol_checked = true;
1270
1271     QFontEngine::FaceId id;
1272     id.filename = family->fontFilename;
1273     id.index = family->fontFileIndex;
1274     QFreetypeFace *f = QFreetypeFace::getFace(id);
1275     if (!f) {
1276         qWarning("checkSymbolFonts: Couldn't open face %s (%s/%d)",
1277                  qPrintable(family->name), family->fontFilename.data(), family->fontFileIndex);
1278         return;
1279     }
1280     for (int i = 0; i < f->face->num_charmaps; ++i) {
1281         FT_CharMap cm = f->face->charmaps[i];
1282         if (cm->encoding == FT_ENCODING_ADOBE_CUSTOM
1283             || cm->encoding == FT_ENCODING_MS_SYMBOL) {
1284             for (int x = QFontDatabase::Latin; x < QFontDatabase::Other; ++x)
1285                 family->writingSystems[x] = QtFontFamily::Unsupported;
1286             family->writingSystems[QFontDatabase::Other] = QtFontFamily::Supported;
1287             break;
1288         }
1289     }
1290     f->release(id);
1291 }
1292
1293 static void checkSymbolFonts(const QString &family = QString())
1294 {
1295 #ifndef QT_NO_FONTCONFIG
1296     QFontDatabasePrivate *d = privateDb();
1297
1298     if (family.isEmpty()) {
1299         for (int i = 0; i < d->count; ++i)
1300             checkSymbolFont(d->families[i]);
1301     } else {
1302         checkSymbolFont(d->family(family));
1303     }
1304 #endif
1305 }
1306
1307 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
1308
1309 static void initializeDb()
1310 {
1311     QFontDatabasePrivate *db = privateDb();
1312     if (!db || db->count)
1313         return;
1314
1315     QElapsedTimer t;
1316     t.start();
1317
1318 #ifndef QT_NO_FONTCONFIG
1319     if (db->reregisterAppFonts) {
1320         db->reregisterAppFonts = false;
1321         for (int i = 0; i < db->applicationFonts.count(); ++i)
1322             if (!db->applicationFonts.at(i).families.isEmpty()) {
1323                 registerFont(&db->applicationFonts[i]);
1324             }
1325     }
1326
1327     loadFontConfig();
1328     FD_DEBUG("QFontDatabase: loaded FontConfig: %d ms", int(t.elapsed()));
1329 #endif
1330
1331     t.start();
1332
1333 #ifndef QT_NO_FONTCONFIG
1334     for (int i = 0; i < db->count; i++) {
1335         for (int j = 0; j < db->families[i]->count; ++j) {        // each foundry
1336             QtFontFoundry *foundry = db->families[i]->foundries[j];
1337             for (int k = 0; k < foundry->count; ++k) {
1338                 QtFontStyle *style = foundry->styles[k];
1339                 if (style->key.style != QFont::StyleNormal) continue;
1340
1341                 QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE);
1342                 if (! size) continue; // should not happen
1343                 QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
1344                 if (! enc) continue; // should not happen either
1345
1346                 QtFontStyle::Key key = style->key;
1347
1348                 // does this style have an italic equivalent?
1349                 key.style = QFont::StyleItalic;
1350                 QtFontStyle *equiv = foundry->style(key);
1351                 if (equiv) continue;
1352
1353                 // does this style have an oblique equivalent?
1354                 key.style = QFont::StyleOblique;
1355                 equiv = foundry->style(key);
1356                 if (equiv) continue;
1357
1358                 // let's fake one...
1359                 equiv = foundry->style(key, true);
1360                 equiv->smoothScalable = true;
1361
1362                 QtFontSize *equiv_size = equiv->pixelSize(SMOOTH_SCALABLE, true);
1363                 QtFontEncoding *equiv_enc = equiv_size->encodingID(-1, 0, 0, 0, 0, true);
1364
1365                 // keep the same pitch
1366                 equiv_enc->pitch = enc->pitch;
1367             }
1368         }
1369     }
1370 #endif
1371
1372
1373 #ifdef QFONTDATABASE_DEBUG
1374 #ifndef QT_NO_FONTCONFIG
1375     if (!X11->has_fontconfig)
1376 #endif
1377         // load everything at startup in debug mode.
1378         loadXlfds(0, -1);
1379
1380     // print the database
1381     for (int f = 0; f < db->count; f++) {
1382         QtFontFamily *family = db->families[f];
1383         FD_DEBUG("'%s' %s  fixed=%s", family->name.latin1(), (family->fixedPitch ? "fixed" : ""),
1384                  (family->fixedPitch ? "yes" : "no"));
1385         for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
1386             QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
1387             FD_DEBUG("\t%s: %s", QFontDatabase::writingSystemName(ws).toLatin1().constData(),
1388                      ((family->writingSystems[i] & QtFontFamily::Supported) ? "Supported" :
1389                       (family->writingSystems[i] & QtFontFamily::Unsupported) == QtFontFamily::Unsupported ?
1390                       "Unsupported" : "Unknown"));
1391         }
1392
1393         for (int fd = 0; fd < family->count; fd++) {
1394             QtFontFoundry *foundry = family->foundries[fd];
1395             FD_DEBUG("\t\t'%s'", foundry->name.latin1());
1396             for (int s = 0; s < foundry->count; s++) {
1397                 QtFontStyle *style = foundry->styles[s];
1398                 FD_DEBUG("\t\t\tstyle: style=%d weight=%d (%s)\n"
1399                          "\t\t\tstretch=%d (%s)",
1400                          style->key.style, style->key.weight,
1401                          style->weightName, style->key.stretch,
1402                          style->setwidthName ? style->setwidthName : "nil");
1403                 if (style->smoothScalable)
1404                     FD_DEBUG("\t\t\t\tsmooth scalable");
1405                 else if (style->bitmapScalable)
1406                     FD_DEBUG("\t\t\t\tbitmap scalable");
1407                 if (style->pixelSizes) {
1408                     qDebug("\t\t\t\t%d pixel sizes", style->count);
1409                     for (int z = 0; z < style->count; ++z) {
1410                         QtFontSize *size = style->pixelSizes + z;
1411                         for (int e = 0; e < size->count; ++e) {
1412                             FD_DEBUG("\t\t\t\t  size %5d pitch %c encoding %s",
1413                                      size->pixelSize,
1414                                      size->encodings[e].pitch,
1415                                      xlfd_for_id(size->encodings[e].encoding));
1416                         }
1417                     }
1418                 }
1419             }
1420         }
1421     }
1422 #endif // QFONTDATABASE_DEBUG
1423 }
1424
1425
1426 // --------------------------------------------------------------------------------------
1427 // font loader
1428 // --------------------------------------------------------------------------------------
1429
1430 static const char *styleHint(const QFontDef &request)
1431 {
1432     const char *stylehint = 0;
1433     switch (request.styleHint) {
1434     case QFont::SansSerif:
1435         stylehint = "sans-serif";
1436         break;
1437     case QFont::Serif:
1438         stylehint = "serif";
1439         break;
1440     case QFont::TypeWriter:
1441         stylehint = "monospace";
1442         break;
1443     default:
1444         if (request.fixedPitch)
1445             stylehint = "monospace";
1446         break;
1447     }
1448     return stylehint;
1449 }
1450
1451 #ifndef QT_NO_FONTCONFIG
1452
1453 void qt_addPatternProps(FcPattern *pattern, int screen, int script, const QFontDef &request)
1454 {
1455     int weight_value = FC_WEIGHT_BLACK;
1456     if (request.weight == 0)
1457         weight_value = FC_WEIGHT_MEDIUM;
1458     else if (request.weight < (QFont::Light + QFont::Normal) / 2)
1459         weight_value = FC_WEIGHT_LIGHT;
1460     else if (request.weight < (QFont::Normal + QFont::DemiBold) / 2)
1461         weight_value = FC_WEIGHT_MEDIUM;
1462     else if (request.weight < (QFont::DemiBold + QFont::Bold) / 2)
1463         weight_value = FC_WEIGHT_DEMIBOLD;
1464     else if (request.weight < (QFont::Bold + QFont::Black) / 2)
1465         weight_value = FC_WEIGHT_BOLD;
1466     FcPatternDel(pattern, FC_WEIGHT);
1467     FcPatternAddInteger(pattern, FC_WEIGHT, weight_value);
1468
1469     int slant_value = FC_SLANT_ROMAN;
1470     if (request.style == QFont::StyleItalic)
1471         slant_value = FC_SLANT_ITALIC;
1472     else if (request.style == QFont::StyleOblique)
1473         slant_value = FC_SLANT_OBLIQUE;
1474     FcPatternDel(pattern, FC_SLANT);
1475     FcPatternAddInteger(pattern, FC_SLANT, slant_value);
1476
1477     double size_value = qMax(qreal(1.), request.pixelSize);
1478     FcPatternDel(pattern, FC_PIXEL_SIZE);
1479     FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size_value);
1480
1481     int stretch = request.stretch;
1482     if (!stretch)
1483         stretch = 100;
1484     FcPatternDel(pattern, FC_WIDTH);
1485     FcPatternAddInteger(pattern, FC_WIDTH, stretch);
1486
1487     if (X11->display && QX11Info::appDepth(screen) <= 8) {
1488         FcPatternDel(pattern, FC_ANTIALIAS);
1489         // can't do antialiasing on 8bpp
1490         FcPatternAddBool(pattern, FC_ANTIALIAS, false);
1491     } else if (request.styleStrategy & (QFont::PreferAntialias|QFont::NoAntialias)) {
1492         FcPatternDel(pattern, FC_ANTIALIAS);
1493         FcPatternAddBool(pattern, FC_ANTIALIAS,
1494                          !(request.styleStrategy & QFont::NoAntialias));
1495     }
1496
1497     if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') {
1498         Q_ASSERT(script < QUnicodeTables::ScriptCount);
1499         FcLangSet *ls = FcLangSetCreate();
1500         FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
1501         FcPatternDel(pattern, FC_LANG);
1502         FcPatternAddLangSet(pattern, FC_LANG, ls);
1503         FcLangSetDestroy(ls);
1504     }
1505 }
1506
1507 static bool preferScalable(const QFontDef &request)
1508 {
1509     return request.styleStrategy & (QFont::PreferOutline|QFont::ForceOutline|QFont::PreferQuality|QFont::PreferAntialias);
1510 }
1511
1512
1513 static FcPattern *getFcPattern(const QFontPrivate *fp, int script, const QFontDef &request)
1514 {
1515     if (!X11->has_fontconfig)
1516         return 0;
1517
1518     FcPattern *pattern = FcPatternCreate();
1519     if (!pattern)
1520         return 0;
1521
1522     FcValue value;
1523     value.type = FcTypeString;
1524
1525     QtFontDesc desc;
1526     QStringList families_and_foundries = familyList(request);
1527     for (int i = 0; i < families_and_foundries.size(); ++i) {
1528         QString family, foundry;
1529         parseFontName(families_and_foundries.at(i), foundry, family);
1530         if (!family.isEmpty()) {
1531             QByteArray cs = family.toUtf8();
1532             value.u.s = (const FcChar8 *)cs.data();
1533             FcPatternAdd(pattern, FC_FAMILY, value, FcTrue);
1534         }
1535         if (i == 0) {
1536             QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, -1, &desc);
1537             if (!foundry.isEmpty()) {
1538                 QByteArray cs = foundry.toUtf8();
1539                 value.u.s = (const FcChar8 *)cs.data();
1540                 FcPatternAddWeak(pattern, FC_FOUNDRY, value, FcTrue);
1541             }
1542         }
1543     }
1544
1545     const char *stylehint = styleHint(request);
1546     if (stylehint) {
1547         value.u.s = (const FcChar8 *)stylehint;
1548         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1549     }
1550
1551     if (!request.ignorePitch) {
1552         char pitch_value = FC_PROPORTIONAL;
1553         if (request.fixedPitch || (desc.family && desc.family->fixedPitch))
1554             pitch_value = FC_MONO;
1555         FcPatternAddInteger(pattern, FC_SPACING, pitch_value);
1556     }
1557     FcPatternAddBool(pattern, FC_OUTLINE, !(request.styleStrategy & QFont::PreferBitmap));
1558     if (preferScalable(request) || (desc.style && desc.style->smoothScalable))
1559         FcPatternAddBool(pattern, FC_SCALABLE, true);
1560
1561     qt_addPatternProps(pattern, fp->screen, script, request);
1562
1563     FcDefaultSubstitute(pattern);
1564     FcConfigSubstitute(0, pattern, FcMatchPattern);
1565     FcConfigSubstitute(0, pattern, FcMatchFont);
1566
1567     // these should only get added to the pattern _after_ substitution
1568     // append the default fallback font for the specified script
1569     extern QString qt_fallback_font_family(int);
1570     QString fallback = qt_fallback_font_family(script);
1571     if (!fallback.isEmpty()) {
1572         QByteArray cs = fallback.toUtf8();
1573         value.u.s = (const FcChar8 *)cs.data();
1574         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1575     }
1576
1577     // add the default family
1578     QString defaultFamily = QApplication::font().family();
1579     QByteArray cs = defaultFamily.toUtf8();
1580     value.u.s = (const FcChar8 *)cs.data();
1581     FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1582
1583     // add QFont::defaultFamily() to the list, for compatibility with
1584     // previous versions
1585     defaultFamily = QApplication::font().defaultFamily();
1586     cs = defaultFamily.toUtf8();
1587     value.u.s = (const FcChar8 *)cs.data();
1588     FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1589
1590     return pattern;
1591 }
1592
1593
1594 static void FcFontSetRemove(FcFontSet *fs, int at)
1595 {
1596     Q_ASSERT(at < fs->nfont);
1597     FcPatternDestroy(fs->fonts[at]);
1598     int len = (--fs->nfont - at) * sizeof(FcPattern *);;
1599     if (len > 0)
1600         memmove(fs->fonts + at, fs->fonts + at + 1, len);
1601 }
1602
1603 static QFontEngine *tryPatternLoad(FcPattern *p, int screen,
1604                                    const QFontDef &request, int script, FcPattern **matchedPattern = 0)
1605 {
1606 #ifdef FONT_MATCH_DEBUG
1607     FcChar8 *fam;
1608     FcPatternGetString(p, FC_FAMILY, 0, &fam);
1609     FM_DEBUG("==== trying %s\n", fam);
1610 #endif
1611     FM_DEBUG("passes charset test\n");
1612     FcPattern *pattern = FcPatternDuplicate(p);
1613     // add properties back in as the font selected from the
1614     // list doesn't contain them.
1615     qt_addPatternProps(pattern, screen, script, request);
1616
1617     FcConfigSubstitute(0, pattern, FcMatchPattern);
1618     FcDefaultSubstitute(pattern);
1619     FcResult res;
1620     FcPattern *match = FcFontMatch(0, pattern, &res);
1621
1622     if (matchedPattern)
1623         *matchedPattern = 0;
1624
1625     QFontEngineX11FT *engine = 0;
1626     if (!match) // probably no fonts available.
1627         goto done;
1628
1629     if (matchedPattern)
1630         *matchedPattern = FcPatternDuplicate(match);
1631
1632     if (script != QUnicodeTables::Common) {
1633         // skip font if it doesn't support the language we want
1634         if (specialChars[script]) {
1635             // need to check the charset, as the langset doesn't work for these scripts
1636             FcCharSet *cs;
1637             if (FcPatternGetCharSet(match, FC_CHARSET, 0, &cs) != FcResultMatch)
1638                 goto done;
1639             if (!FcCharSetHasChar(cs, specialChars[script]))
1640                 goto done;
1641         } else if (*specialLanguages[script] != '\0'){
1642             FcLangSet *langSet = 0;
1643             if (FcPatternGetLangSet(match, FC_LANG, 0, &langSet) != FcResultMatch)
1644                 goto done;
1645             if (FcLangSetHasLang(langSet, (const FcChar8*)specialLanguages[script]) != FcLangEqual)
1646                 goto done;
1647         }
1648     }
1649
1650     // enforce non-antialiasing if requested. the ft font engine looks at this property.
1651     if (request.styleStrategy & QFont::NoAntialias) {
1652         FcPatternDel(match, FC_ANTIALIAS);
1653         FcPatternAddBool(match, FC_ANTIALIAS, false);
1654     }
1655
1656     engine = new QFontEngineX11FT(match, qt_FcPatternToQFontDef(match, request), screen);
1657     if (engine->invalid()) {
1658         FM_DEBUG("   --> invalid!\n");
1659         delete engine;
1660         engine = 0;
1661     } else if (scriptRequiresOpenType(script)) {
1662         HB_Face hbFace = engine->harfbuzzFace();
1663         if (!hbFace || !hbFace->supported_scripts[script]) {
1664             FM_DEBUG("  OpenType support missing for script\n");
1665             delete engine;
1666             engine = 0;
1667         }
1668     }
1669 done:
1670     FcPatternDestroy(pattern);
1671     if (!engine && matchedPattern && *matchedPattern) {
1672         FcPatternDestroy(*matchedPattern);
1673         *matchedPattern = 0;
1674     }
1675     return engine;
1676 }
1677
1678 FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request)
1679 {
1680     FcResult result;
1681     FcFontSet *fs = FcFontSort(0, pattern, FcTrue, 0, &result);
1682 #ifdef FONT_MATCH_DEBUG
1683     FM_DEBUG("first font in fontset:\n");
1684     FcPatternPrint(fs->fonts[0]);
1685 #endif
1686
1687     FcBool forceScalable = request.styleStrategy & QFont::ForceOutline;
1688
1689     // remove fonts if they are not scalable (and should be)
1690     if (forceScalable && fs) {
1691         for (int i = 0; i < fs->nfont; ++i) {
1692             FcPattern *font = fs->fonts[i];
1693             FcResult res;
1694             FcBool scalable;
1695             res = FcPatternGetBool(font, FC_SCALABLE, 0, &scalable);
1696             if (res != FcResultMatch || !scalable) {
1697                 FcFontSetRemove(fs, i);
1698 #ifdef FONT_MATCH_DEBUG
1699                 FM_DEBUG("removing pattern:");
1700                 FcPatternPrint(font);
1701 #endif
1702                 --i; // go back one
1703             }
1704         }
1705     }
1706
1707     FM_DEBUG("final pattern contains %d fonts\n", fs->nfont);
1708
1709     return fs;
1710 }
1711
1712 static QFontEngine *loadFc(const QFontPrivate *fp, int script, const QFontDef &request)
1713 {
1714     FM_DEBUG("===================== loadFc: script=%d family='%s'\n", script, request.family.toLatin1().data());
1715     FcPattern *pattern = getFcPattern(fp, script, request);
1716
1717 #ifdef FONT_MATCH_DEBUG
1718     FM_DEBUG("\n\nfinal FcPattern contains:\n");
1719     FcPatternPrint(pattern);
1720 #endif
1721
1722     QFontEngine *fe = 0;
1723     FcPattern *matchedPattern = 0;
1724     fe = tryPatternLoad(pattern, fp->screen, request, script, &matchedPattern);
1725     if (!fe) {
1726         FcFontSet *fs = qt_fontSetForPattern(pattern, request);
1727
1728         if (fs) {
1729             for (int i = 0; !fe && i < fs->nfont; ++i)
1730                 fe = tryPatternLoad(fs->fonts[i], fp->screen, request, script, &matchedPattern);
1731             FcFontSetDestroy(fs);
1732         }
1733         FM_DEBUG("engine for script %d is %s\n", script, fe ? fe->fontDef.family.toLatin1().data(): "(null)");
1734     }
1735     if (fe
1736         && script == QUnicodeTables::Common
1737         && !(request.styleStrategy & QFont::NoFontMerging) && !fe->symbol) {
1738         fe = new QFontEngineMultiFT(fe, matchedPattern, pattern, fp->screen, request);
1739     } else {
1740         FcPatternDestroy(pattern);
1741         if (matchedPattern)
1742             FcPatternDestroy(matchedPattern);
1743     }
1744     return fe;
1745 }
1746
1747 static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
1748 {
1749 #if FC_VERSION < 20402
1750     Q_UNUSED(data)
1751     return FcFreeTypeQuery(file, id, blanks, count);
1752 #else
1753     if (data.isEmpty())
1754         return FcFreeTypeQuery(file, id, blanks, count);
1755
1756     extern FT_Library qt_getFreetype();
1757     FT_Library lib = qt_getFreetype();
1758
1759     FcPattern *pattern = 0;
1760
1761     FT_Face face;
1762     if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) {
1763         *count = face->num_faces;
1764
1765         pattern = FcFreeTypeQueryFace(face, file, id, blanks);
1766
1767         FT_Done_Face(face);
1768     }
1769
1770     return pattern;
1771 #endif
1772 }
1773 #endif // QT_NO_FONTCONFIG
1774
1775 static QFontEngine *loadRaw(const QFontPrivate *fp, const QFontDef &request)
1776 {
1777     Q_ASSERT(fp && fp->rawMode);
1778
1779     QByteArray xlfd = request.family.toLatin1();
1780     FM_DEBUG("Loading XLFD (rawmode) '%s'", xlfd.data());
1781
1782     QFontEngine *fe;
1783     XFontStruct *xfs;
1784     if (!(xfs = XLoadQueryFont(QX11Info::display(), xlfd.data())))
1785         if (!(xfs = XLoadQueryFont(QX11Info::display(), "fixed")))
1786             return 0;
1787
1788     fe = new QFontEngineXLFD(xfs, xlfd, 0);
1789     if (! qt_fillFontDef(xfs, &fe->fontDef, fp->dpi, 0) &&
1790         ! qt_fillFontDef(xlfd, &fe->fontDef, fp->dpi, 0))
1791         fe->fontDef = QFontDef();
1792     return fe;
1793 }
1794
1795 QFontEngine *QFontDatabase::loadXlfd(int screen, int script, const QFontDef &request, int force_encoding_id)
1796 {
1797     QMutexLocker locker(fontDatabaseMutex());
1798
1799     QtFontDesc desc;
1800     FM_DEBUG() << "---> loadXlfd: request is" << request.family;
1801     QStringList families_and_foundries = familyList(request);
1802     const char *stylehint = styleHint(request);
1803     if (stylehint)
1804         families_and_foundries << QString::fromLatin1(stylehint);
1805     families_and_foundries << QString();
1806     FM_DEBUG() << "loadXlfd: list is" << families_and_foundries;
1807     for (int i = 0; i < families_and_foundries.size(); ++i) {
1808         QString family, foundry;
1809         QT_PREPEND_NAMESPACE(parseFontName)(families_and_foundries.at(i), foundry, family);
1810         FM_DEBUG("loadXlfd: >>>>>>>>>>>>>>trying to match '%s' encoding=%d", family.toLatin1().data(), force_encoding_id);
1811         QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, force_encoding_id, &desc, QList<int>(), true);
1812         if (desc.family)
1813             break;
1814     }
1815
1816     QFontEngine *fe = 0;
1817     if (force_encoding_id != -1
1818         || (request.styleStrategy & QFont::NoFontMerging)
1819         || (desc.family && desc.family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
1820         if (desc.family) {
1821             int px = desc.size->pixelSize;
1822             if (desc.style->smoothScalable && px == SMOOTH_SCALABLE)
1823                 px = request.pixelSize;
1824             else if (desc.style->bitmapScalable && px == 0)
1825                 px = request.pixelSize;
1826
1827             QByteArray xlfd("-");
1828             xlfd += desc.foundry->name.isEmpty() ? QByteArray("*") : desc.foundry->name.toLatin1();
1829             xlfd += '-';
1830             xlfd += desc.family->name.isEmpty() ? QByteArray("*") : desc.family->name.toLatin1();
1831             xlfd += '-';
1832             xlfd += desc.style->weightName ? desc.style->weightName : "*";
1833             xlfd += '-';
1834             xlfd += (desc.style->key.style == QFont::StyleItalic
1835                      ? 'i'
1836                      : (desc.style->key.style == QFont::StyleOblique ? 'o' : 'r'));
1837             xlfd += '-';
1838             xlfd += desc.style->setwidthName ? desc.style->setwidthName : "*";
1839             // ### handle add-style
1840             xlfd += "-*-";
1841             xlfd += QByteArray::number(px);
1842             xlfd += '-';
1843             xlfd += QByteArray::number(desc.encoding->xpoint);
1844             xlfd += '-';
1845             xlfd += QByteArray::number(desc.encoding->xres);
1846             xlfd += '-';
1847             xlfd += QByteArray::number(desc.encoding->yres);
1848             xlfd += '-';
1849             xlfd += desc.encoding->pitch;
1850             xlfd += '-';
1851             xlfd += QByteArray::number(desc.encoding->avgwidth);
1852             xlfd += '-';
1853             xlfd += xlfd_for_id(desc.encoding->encoding);
1854
1855             FM_DEBUG("    using XLFD: %s\n", xlfd.data());
1856
1857             const int mib = xlfd_encoding[desc.encoding->encoding].mib;
1858             XFontStruct *xfs;
1859             if ((xfs = XLoadQueryFont(QX11Info::display(), xlfd))) {
1860                 fe = new QFontEngineXLFD(xfs, xlfd, mib);
1861                 const int dpi = QX11Info::appDpiY();
1862                 if (!qt_fillFontDef(xfs, &fe->fontDef, dpi, &desc)
1863                     && !qt_fillFontDef(xlfd, &fe->fontDef, dpi, &desc)) {
1864                     initFontDef(desc, request, &fe->fontDef);
1865                 }
1866             }
1867         }
1868         if (!fe) {
1869             fe = new QFontEngineBox(request.pixelSize);
1870             fe->fontDef = QFontDef();
1871         }
1872     } else {
1873         QList<int> encodings;
1874         if (desc.encoding) {
1875             if (desc.encoding->encoding >= 0)
1876                 encodings.append(int(desc.encoding->encoding));
1877         }
1878
1879         if (desc.size) {
1880             // append all other encodings for the matched font
1881             for (int i = 0; i < desc.size->count; ++i) {
1882                 QtFontEncoding *e = desc.size->encodings + i;
1883                 if (e == desc.encoding || e->encoding < 0)
1884                     continue;                
1885                 encodings.append(int(e->encoding));
1886             }
1887         }
1888         // fill in the missing encodings
1889         const XlfdEncoding *enc = xlfd_encoding;
1890         for (; enc->name; ++enc) {
1891             if (!encodings.contains(enc->id) && enc->id >= 0) {
1892                 encodings.append(enc->id);
1893             }
1894         }
1895
1896 #if defined(FONT_MATCH_DEBUG)
1897         FM_DEBUG("    using MultiXLFD, encodings:");
1898         for (int i = 0; i < encodings.size(); ++i) {
1899             const int id = encodings.at(i);
1900             FM_DEBUG("      %2d: %s", xlfd_encoding[id].id, xlfd_encoding[id].name);
1901         }
1902 #endif
1903
1904         fe = new QFontEngineMultiXLFD(request, encodings, screen);
1905     }
1906     return fe;
1907 }
1908
1909 #if (defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6)) && defined(Q_CC_GNU) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
1910 #define NEEDS_GCC_BUG_WORKAROUND
1911 #endif
1912
1913 #ifdef NEEDS_GCC_BUG_WORKAROUND
1914 static inline void gccBugWorkaround(const QFontDef &req)
1915 {
1916     char buffer[8];
1917     snprintf(buffer, 8, "%f", req.pixelSize);
1918 }
1919 #endif
1920
1921 /*! \internal
1922   Loads a QFontEngine for the specified \a script that matches the
1923   QFontDef \e request member variable.
1924 */
1925 void QFontDatabase::load(const QFontPrivate *d, int script)
1926 {
1927     Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
1928
1929     // normalize the request to get better caching
1930     QFontDef req = d->request;
1931     if (req.pixelSize <= 0)
1932         req.pixelSize = qFloor(qt_pixelSize(req.pointSize, d->dpi) * 100.0 + 0.5) * 0.01;
1933     if (req.pixelSize < 1)
1934         req.pixelSize = 1;
1935
1936 #ifdef NEEDS_GCC_BUG_WORKAROUND
1937     // req.pixelSize ends up with a bogus value unless this workaround is called
1938     gccBugWorkaround(req);
1939 #endif
1940
1941     if (req.weight == 0)
1942         req.weight = QFont::Normal;
1943     if (req.stretch == 0)
1944         req.stretch = 100;
1945
1946     QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
1947     if (!d->engineData)
1948         getEngineData(d, key);
1949
1950     // the cached engineData could have already loaded the engine we want
1951     if (d->engineData->engines[script])
1952         return;
1953
1954     // set it to the actual pointsize, so QFontInfo will do the right thing
1955     if (req.pointSize < 0)
1956         req.pointSize = qt_pointSize(req.pixelSize, d->dpi);
1957
1958
1959     QFontEngine *fe = QFontCache::instance()->findEngine(key);
1960
1961     if (!fe) {
1962         QMutexLocker locker(fontDatabaseMutex());
1963         if (!privateDb()->count)
1964             initializeDb();
1965
1966         const bool mainThread = (qApp->thread() == QThread::currentThread());
1967         if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
1968             fe = new QTestFontEngine(req.pixelSize);
1969             fe->fontDef = req;
1970         } else if (d->rawMode) {
1971             if (mainThread)
1972                 fe = loadRaw(d, req);
1973 #ifndef QT_NO_FONTCONFIG
1974         } else if (X11->has_fontconfig) {
1975             fe = loadFc(d, script, req);
1976 #endif
1977         } else if (mainThread && qt_is_gui_used) {
1978             fe = loadXlfd(d->screen, script, req);
1979         }
1980         if (!fe) {
1981             fe = new QFontEngineBox(req.pixelSize);
1982             fe->fontDef = QFontDef();
1983         }
1984     }
1985     if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
1986         for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
1987             if (!d->engineData->engines[i]) {
1988                 d->engineData->engines[i] = fe;
1989                 fe->ref.ref();
1990             }
1991         }
1992     } else {
1993         d->engineData->engines[script] = fe;
1994         fe->ref.ref();
1995     }
1996     QFontCache::instance()->insertEngine(key, fe);
1997 }
1998
1999 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
2000 {
2001 #if defined(QT_NO_FONTCONFIG)
2002     return;
2003 #else
2004     if (!X11->has_fontconfig)
2005         return;
2006
2007     FcConfig *config = FcConfigGetCurrent();
2008     if (!config)
2009         return;
2010
2011     FcFontSet *set = FcConfigGetFonts(config, FcSetApplication);
2012     if (!set) {
2013         FcConfigAppFontAddFile(config, (const FcChar8 *)":/non-existent");
2014         set = FcConfigGetFonts(config, FcSetApplication); // try again
2015         if (!set)
2016             return;
2017     }
2018
2019     QString fileNameForQuery = fnt->fileName;
2020 #if FC_VERSION < 20402
2021     QTemporaryFile tmp;
2022
2023     if (!fnt->data.isEmpty()) {
2024         if (!tmp.open())
2025             return;
2026         tmp.write(fnt->data);
2027         tmp.flush();
2028         fileNameForQuery = tmp.fileName();
2029     }
2030 #endif
2031
2032     int id = 0;
2033     FcBlanks *blanks = FcConfigGetBlanks(0);
2034     int count = 0;
2035
2036     QStringList families;
2037     QFontDatabasePrivate *db = privateDb();
2038
2039     FcPattern *pattern = 0;
2040     do {
2041         pattern = queryFont((const FcChar8 *)QFile::encodeName(fileNameForQuery).constData(),
2042                             fnt->data, id, blanks, &count);
2043         if (!pattern)
2044             return;
2045
2046         FcPatternDel(pattern, FC_FILE);
2047         FcPatternAddString(pattern, FC_FILE, (const FcChar8 *)fnt->fileName.toUtf8().constData());
2048
2049         FcChar8 *fam = 0, *familylang = 0;
2050         int i, n = 0;
2051         for (i = 0; ; i++) {
2052             if (FcPatternGetString(pattern, FC_FAMILYLANG, i, &familylang) != FcResultMatch)
2053                 break;
2054             QString familyLang = QString::fromUtf8((const char *) familylang);
2055             if (familyLang.compare(db->systemLang, Qt::CaseInsensitive) == 0) {
2056                 n = i;
2057                 break;
2058             }
2059         }
2060
2061         if (FcPatternGetString(pattern, FC_FAMILY, n, &fam) == FcResultMatch) {
2062             QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
2063             families << family;
2064         }
2065
2066         if (!FcFontSetAdd(set, pattern))
2067             return;
2068
2069         ++id;
2070     } while (pattern && id < count);
2071
2072     fnt->families = families;
2073 #endif
2074 }
2075
2076 bool QFontDatabase::removeApplicationFont(int handle)
2077 {
2078 #if defined(QT_NO_FONTCONFIG)
2079     return false;
2080 #else
2081     QMutexLocker locker(fontDatabaseMutex());
2082
2083     QFontDatabasePrivate *db = privateDb();
2084     if (handle < 0 || handle >= db->applicationFonts.count())
2085         return false;
2086
2087     FcConfigAppFontClear(0);
2088
2089     db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
2090
2091     db->reregisterAppFonts = true;
2092     db->invalidate();
2093     return true;
2094 #endif
2095 }
2096
2097 bool QFontDatabase::removeAllApplicationFonts()
2098 {
2099 #if defined(QT_NO_FONTCONFIG)
2100     return false;
2101 #else
2102     QMutexLocker locker(fontDatabaseMutex());
2103
2104     QFontDatabasePrivate *db = privateDb();
2105     if (db->applicationFonts.isEmpty())
2106         return false;
2107
2108     FcConfigAppFontClear(0);
2109     db->applicationFonts.clear();
2110     db->invalidate();
2111     return true;
2112 #endif
2113 }
2114
2115 bool QFontDatabase::supportsThreadedFontRendering()
2116 {
2117 #if defined(QT_NO_FONTCONFIG)
2118     return false;
2119 #else
2120     return X11->has_fontconfig;
2121 #endif
2122 }
2123
2124 QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
2125 {
2126 #if defined(QT_NO_FONTCONFIG)
2127     return family;
2128 #else
2129     FcPattern *pattern = FcPatternCreate();
2130     if (!pattern)
2131         return family;
2132
2133     FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) family.toUtf8().data());
2134     FcConfigSubstitute(0, pattern, FcMatchPattern);
2135     FcDefaultSubstitute(pattern);
2136
2137     FcChar8 *familyAfterSubstitution;
2138     FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
2139     QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
2140     FcPatternDestroy(pattern);
2141
2142     return resolved;
2143 #endif
2144 }
2145
2146 QT_END_NAMESPACE