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