1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the text module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include <qplatformdefs.h>
31
#include <qdatetime.h>
32
#include <qpaintdevice.h>
34
#include <private/qt_x11_p.h>
35
#include "qx11info_x11.h"
40
#include <sys/types.h>
45
#ifndef QT_NO_FONTCONFIG
47
#include FT_FREETYPE_H
51
extern double qt_pointSize(double pixelSize, int dpi);
52
extern double qt_pixelSize(double pointSize, int dpi);
54
static inline void capitalize (char *s)
67
To regenerate the writingSystems_for_xlfd_encoding table, run
68
'util/unicode/x11/makeencodings' and paste the generated
71
// ----- begin of generated code -----
73
#define make_tag( c1, c2, c3, c4 ) \
74
((((unsigned int)c1)<<24) | (((unsigned int)c2)<<16) | \
75
(((unsigned int)c3)<<8) | ((unsigned int)c4))
85
static const XlfdEncoding xlfd_encoding[] = {
86
{ "iso8859-1", 0, 4, make_tag('i','s','o','8'), make_tag('5','9','-','1') },
87
{ "iso8859-2", 1, 5, make_tag('i','s','o','8'), make_tag('5','9','-','2') },
88
{ "iso8859-3", 2, 6, make_tag('i','s','o','8'), make_tag('5','9','-','3') },
89
{ "iso8859-4", 3, 7, make_tag('i','s','o','8'), make_tag('5','9','-','4') },
90
{ "iso8859-9", 4, 12, make_tag('i','s','o','8'), make_tag('5','9','-','9') },
91
{ "iso8859-10", 5, 13, make_tag('i','s','o','8'), make_tag('9','-','1','0') },
92
{ "iso8859-13", 6, 109, make_tag('i','s','o','8'), make_tag('9','-','1','3') },
93
{ "iso8859-14", 7, 110, make_tag('i','s','o','8'), make_tag('9','-','1','4') },
94
{ "iso8859-15", 8, 111, make_tag('i','s','o','8'), make_tag('9','-','1','5') },
95
{ "hp-roman8", 9, 2004, make_tag('h','p','-','r'), make_tag('m','a','n','8') },
96
{ "iso8859-5", 10, 8, make_tag('i','s','o','8'), make_tag('5','9','-','5') },
97
{ "*-cp1251", 11, 2251, 0, make_tag('1','2','5','1') },
98
{ "koi8-ru", 12, 2084, make_tag('k','o','i','8'), make_tag('8','-','r','u') },
99
{ "koi8-u", 13, 2088, make_tag('k','o','i','8'), make_tag('i','8','-','u') },
100
{ "koi8-r", 14, 2084, make_tag('k','o','i','8'), make_tag('i','8','-','r') },
101
{ "iso8859-7", 15, 10, make_tag('i','s','o','8'), make_tag('5','9','-','7') },
102
{ "iso8859-8", 16, 85, make_tag('i','s','o','8'), make_tag('5','9','-','8') },
103
{ "gb18030-0", 17, -114, make_tag('g','b','1','8'), make_tag('3','0','-','0') },
104
{ "gb18030.2000-0", 18, -113, make_tag('g','b','1','8'), make_tag('0','0','-','0') },
105
{ "gbk-0", 19, -113, make_tag('g','b','k','-'), make_tag('b','k','-','0') },
106
{ "gb2312.*-0", 20, 57, make_tag('g','b','2','3'), 0 },
107
{ "jisx0201*-0", 21, 15, make_tag('j','i','s','x'), 0 },
108
{ "jisx0208*-0", 22, 63, make_tag('j','i','s','x'), 0 },
109
{ "ksc5601*-*", 23, 36, make_tag('k','s','c','5'), 0 },
110
{ "big5hkscs-0", 24, -2101, make_tag('b','i','g','5'), make_tag('c','s','-','0') },
111
{ "hkscs-1", 25, -2101, make_tag('h','k','s','c'), make_tag('c','s','-','1') },
112
{ "big5*-*", 26, -2026, make_tag('b','i','g','5'), 0 },
113
{ "tscii-*", 27, 2028, make_tag('t','s','c','i'), 0 },
114
{ "tis620*-*", 28, 2259, make_tag('t','i','s','6'), 0 },
115
{ "iso8859-11", 29, 2259, make_tag('i','s','o','8'), make_tag('9','-','1','1') },
116
{ "mulelao-1", 30, -4242, make_tag('m','u','l','e'), make_tag('a','o','-','1') },
117
{ "ethiopic-unicode", 31, 0, make_tag('e','t','h','i'), make_tag('c','o','d','e') },
118
{ "iso10646-1", 32, 0, make_tag('i','s','o','1'), make_tag('4','6','-','1') },
119
{ "unicode-*", 33, 0, make_tag('u','n','i','c'), 0 },
120
{ "*-symbol", 34, 0, 0, make_tag('m','b','o','l') },
121
{ "*-fontspecific", 35, 0, 0, make_tag('i','f','i','c') },
122
{ "fontspecific-*", 36, 0, make_tag('f','o','n','t'), 0 },
126
static const char writingSystems_for_xlfd_encoding[37][39] = {
128
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
129
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131
0, 0, 0, 0, 0, 0, 0, 0, 0 },
133
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
134
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
135
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
136
0, 0, 0, 0, 0, 0, 0, 0, 0 },
138
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
139
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
140
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
141
0, 0, 0, 0, 0, 0, 0, 0, 0 },
143
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
144
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
145
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
146
0, 0, 0, 0, 0, 0, 0, 0, 0 },
148
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
149
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
151
0, 0, 0, 0, 0, 0, 0, 0, 0 },
153
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
154
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
155
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
156
0, 0, 0, 0, 0, 0, 0, 0, 0 },
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, 0, 0, 0, 0, 0, 0, 0 },
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, 0, 0, 0, 0, 0, 0, 0 },
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, 0, 0, 0, 0, 0, 0, 0 },
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, 0, 0, 0, 0, 0, 0, 0 },
178
{ 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0 },
183
{ 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0 },
188
{ 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0 },
193
{ 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0 },
198
{ 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0 },
203
{ 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0 },
208
{ 0, 0, 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0 },
213
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
214
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
215
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
216
0, 0, 0, 0, 0, 0, 0, 0, 0 },
218
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
219
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
220
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
221
0, 0, 0, 0, 0, 0, 0, 0, 0 },
223
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
224
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
225
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
226
0, 0, 0, 0, 0, 0, 0, 0, 0 },
228
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
229
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
230
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
231
0, 0, 0, 0, 0, 0, 0, 0, 0 },
233
{ 0, 0, 0, 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, 1, 0, 0,
236
0, 0, 0, 0, 0, 0, 0, 0, 0 },
238
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
240
0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
241
0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 1, 0,
246
0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 1, 0, 0, 0,
251
0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 1, 0, 0, 0,
256
0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 1, 0, 0, 0,
261
0, 0, 0, 0, 0, 0, 0, 0, 0 },
263
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
264
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
265
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
266
0, 0, 0, 0, 0, 0, 0, 0, 0 },
268
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
269
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
270
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
271
0, 0, 0, 0, 0, 0, 0, 0, 0 },
273
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
274
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
275
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
276
0, 0, 0, 0, 0, 0, 0, 0, 0 },
278
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
279
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
280
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
281
0, 0, 0, 0, 0, 0, 0, 0, 0 },
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, 0, 0, 0, 0,
286
0, 0, 0, 0, 0, 0, 0, 0, 1 },
288
{ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
289
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
290
1, 1, 0, 1, 0, 1, 1, 0, 0, 0,
291
0, 0, 0, 0, 0, 0, 0, 0, 0 },
293
{ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
294
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
295
1, 1, 0, 1, 0, 1, 1, 0, 0, 0,
296
0, 0, 0, 0, 0, 0, 0, 0, 0 },
298
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
299
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
300
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
301
0, 0, 0, 0, 0, 0, 0, 0, 1 },
303
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
304
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
305
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
306
0, 0, 0, 0, 0, 0, 0, 0, 1 },
308
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
309
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
310
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
311
0, 0, 0, 0, 0, 0, 0, 0, 1 }
315
// ----- end of generated code -----
318
const int numEncodings = sizeof(xlfd_encoding) / sizeof(XlfdEncoding) - 1;
320
int qt_xlfd_encoding_id(const char *encoding)
322
// qDebug("looking for encoding id for '%s'", encoding);
323
int len = strlen(encoding);
326
unsigned int hash1 = make_tag(encoding[0], encoding[1], encoding[2], encoding[3]);
327
const char *ch = encoding + len - 4;
328
unsigned int hash2 = make_tag(ch[0], ch[1], ch[2], ch[3]);
330
const XlfdEncoding *enc = xlfd_encoding;
331
for (; enc->name; ++enc) {
332
if ((enc->hash1 && enc->hash1 != hash1) ||
333
(enc->hash2 && enc->hash2 != hash2))
335
// hashes match, do a compare if strings match
336
// the enc->name can contain '*'s we have to interpret correctly
337
const char *n = enc->name;
338
const char *e = encoding;
340
// qDebug("bol: *e='%c', *n='%c'", *e, *n);
344
// qDebug("found encoding id %d", enc->id);
355
// qDebug("skip: *e='%c', *n='%c'", *e, *n);
356
while (*e && *e != *n)
360
// qDebug("couldn't find encoding %s", encoding);
364
int qt_mib_for_xlfd_encoding(const char *encoding)
366
int id = qt_xlfd_encoding_id(encoding);
367
if (id != -1) return xlfd_encoding[id].mib;
371
int qt_encoding_id_for_mib(int mib)
373
const XlfdEncoding *enc = xlfd_encoding;
374
for (; enc->name; ++enc) {
381
static const char * xlfd_for_id(int id)
383
// special case: -1 returns the "*-*" encoding, allowing us to do full
384
// database population in a single X server round trip.
385
if (id < 0 || id > numEncodings)
387
return xlfd_encoding[id].name;
390
enum XLFDFieldNames {
408
// Splits an X font name into fields separated by '-'
409
static bool parseXFontName(char *fontName, char **tokens)
411
if (! fontName || fontName[0] == '0' || fontName[0] != '-') {
418
for (i = 0; i < NFontFields && fontName && fontName[0]; ++i) {
419
tokens[i] = fontName;
420
for (;; ++fontName) {
421
if (*fontName == '-')
429
if (fontName) *fontName++ = '\0';
432
if (i < NFontFields) {
433
for (int j = i ; j < NFontFields; ++j)
441
static inline bool isZero(char *x)
443
return (x[0] == '0' && x[1] == 0);
446
static inline bool isScalable(char **tokens)
448
return (isZero(tokens[PixelSize]) &&
449
isZero(tokens[PointSize]) &&
450
isZero(tokens[AverageWidth]));
453
static inline bool isSmoothlyScalable(char **tokens)
455
return (isZero(tokens[ResolutionX]) &&
456
isZero(tokens[ResolutionY]));
459
static inline bool isFixedPitch(char **tokens)
461
return (tokens[Spacing][0] == 'm' ||
462
tokens[Spacing][0] == 'c' ||
463
tokens[Spacing][0] == 'M' ||
464
tokens[Spacing][0] == 'C');
468
Fills in a font definition (QFontDef) from an XLFD (X Logical Font
471
Returns true if the the given xlfd is valid.
473
bool qt_fillFontDef(const QByteArray &xlfd, QFontDef *fd, int dpi)
475
char *tokens[NFontFields];
476
QByteArray buffer = xlfd;
477
if (! parseXFontName(buffer.data(), tokens))
480
capitalize(tokens[Family]);
481
capitalize(tokens[Foundry]);
483
fd->family = QString::fromLatin1(tokens[Family]);
484
QString foundry = QString::fromLatin1(tokens[Foundry]);
485
if (! foundry.isEmpty() && foundry != QString::fromLatin1("*"))
487
QString::fromLatin1(" [") + foundry + QString::fromLatin1("]");
489
if (qstrlen(tokens[AddStyle]) > 0)
490
fd->addStyle = QString::fromLatin1(tokens[AddStyle]);
492
fd->addStyle.clear();
494
fd->pointSize = atoi(tokens[PointSize]);
495
fd->styleHint = QFont::AnyStyle; // ### any until we match families
497
char slant = tolower((uchar) tokens[Slant][0]);
498
fd->style = (slant == 'o' ? QFont::StyleOblique : (slant == 'i' ? QFont::StyleItalic : QFont::StyleNormal));
499
char fixed = tolower((uchar) tokens[Spacing][0]);
500
fd->fixedPitch = (fixed == 'm' || fixed == 'c');
501
fd->weight = getFontWeight(tokens[Weight]);
503
int r = atoi(tokens[ResolutionY]);
504
fd->pixelSize = atoi(tokens[PixelSize]);
505
// not "0" or "*", or required DPI
506
if (r && fd->pixelSize && r != dpi) {
507
// calculate actual pointsize for display DPI
508
fd->pointSize = qt_pointSize(fd->pixelSize, dpi);
509
} else if (fd->pixelSize == 0 && fd->pointSize) {
510
// calculate pixel size from pointsize/dpi
511
fd->pixelSize = qRound(qt_pixelSize(fd->pointSize, dpi));
518
Fills in a font definition (QFontDef) from the font properties in an
521
Returns true if the QFontDef could be filled with properties from
524
static bool qt_fillFontDef(XFontStruct *fs, QFontDef *fd, int dpi)
527
if (fs && !XGetFontProperty(fs, XA_FONT, &value))
530
char *n = XGetAtomName(QX11Info::display(), value);
534
return qt_fillFontDef(xlfd.toLower(), fd, dpi);
538
static QtFontStyle::Key getStyle(char ** tokens)
540
QtFontStyle::Key key;
542
char slant0 = tolower((uchar) tokens[Slant][0]);
545
if (tokens[Slant][1]) {
546
char slant1 = tolower((uchar) tokens[Slant][1]);
549
key.style = QFont::StyleOblique;
550
else if (slant1 == 'i')
551
key.style = QFont::StyleItalic;
553
} else if (slant0 == 'o')
554
key.style = QFont::StyleOblique;
555
else if (slant0 == 'i')
556
key.style = QFont::StyleItalic;
558
key.weight = getFontWeight(tokens[Weight]);
560
if (qstrcmp(tokens[Width], "normal") == 0) {
562
} else if (qstrcmp(tokens[Width], "semi condensed") == 0 ||
563
qstrcmp(tokens[Width], "semicondensed") == 0) {
565
} else if (qstrcmp(tokens[Width], "condensed") == 0) {
567
} else if (qstrcmp(tokens[Width], "narrow") == 0) {
575
static bool xlfdsFullyLoaded = false;
576
static unsigned char encodingLoaded[numEncodings];
578
static void loadXlfds(const char *reqFamily, int encoding_id)
580
QFontDatabasePrivate *db = privateDb();
581
QtFontFamily *fontFamily = reqFamily ? db->family(reqFamily) : 0;
583
// make sure we don't load twice
584
if ((encoding_id == -1 && xlfdsFullyLoaded)
585
|| (encoding_id != -1 && encodingLoaded[encoding_id]))
587
if (fontFamily && fontFamily->xlfdLoaded)
591
// force the X server to give us XLFDs
592
QByteArray xlfd_pattern("-*-");
593
xlfd_pattern += reqFamily ? reqFamily : "*";
594
xlfd_pattern += "-*-*-*-*-*-*-*-*-*-*-";
595
xlfd_pattern += xlfd_for_id(encoding_id);
597
char **fontList = XListFonts(QX11Info::display(),
600
// qDebug("requesting xlfd='%s', got %d fonts", xlfd_pattern.data(), fontCount);
603
char *tokens[NFontFields];
605
for(int i = 0 ; i < fontCount ; i++) {
606
if (! parseXFontName(fontList[i], tokens))
609
// get the encoding_id for this xlfd. we need to do this
610
// here, since we can pass -1 to this function to do full
611
// database population
612
*(tokens[CharsetEncoding] - 1) = '-';
613
int encoding_id = qt_xlfd_encoding_id(tokens[CharsetRegistry]);
614
if (encoding_id == -1)
617
char *familyName = tokens[Family];
618
capitalize(familyName);
619
char *foundryName = tokens[Foundry];
620
capitalize(foundryName);
621
QtFontStyle::Key styleKey = getStyle(tokens);
623
bool smooth_scalable = false;
624
bool bitmap_scalable = false;
625
if (isScalable(tokens)) {
626
if (isSmoothlyScalable(tokens))
627
smooth_scalable = true;
629
bitmap_scalable = true;
631
uint pixelSize = atoi(tokens[PixelSize]);
632
uint xpointSize = atoi(tokens[PointSize]);
633
uint xres = atoi(tokens[ResolutionX]);
634
uint yres = atoi(tokens[ResolutionY]);
635
uint avgwidth = atoi(tokens[AverageWidth]);
636
bool fixedPitch = isFixedPitch(tokens);
638
if (avgwidth == 0 && pixelSize != 0) {
640
Ignore bitmap scalable fonts that are automatically
641
generated by some X servers. We know they are bitmap
642
scalable because even though they have a specified pixel
643
size, the average width is zero.
648
QtFontFamily *family = fontFamily ? fontFamily : db->family(familyName, true);
649
family->fontFileIndex = -1;
650
QtFontFoundry *foundry = family->foundry(foundryName, true);
651
QtFontStyle *style = foundry->style(styleKey, true);
653
delete [] style->weightName;
654
style->weightName = qstrdup(tokens[Weight]);
655
delete [] style->setwidthName;
656
style->setwidthName = qstrdup(tokens[Width]);
658
if (smooth_scalable) {
659
style->smoothScalable = true;
660
style->bitmapScalable = false;
661
pixelSize = SMOOTH_SCALABLE;
663
if (!style->smoothScalable && bitmap_scalable)
664
style->bitmapScalable = true;
666
family->fixedPitch = false;
668
QtFontSize *size = style->pixelSize(pixelSize, true);
669
QtFontEncoding *enc =
670
size->encodingID(encoding_id, xpointSize, xres, yres, avgwidth, true);
671
enc->pitch = *tokens[Spacing];
672
if (!enc->pitch) enc->pitch = '*';
674
for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
675
if (writingSystems_for_xlfd_encoding[encoding_id][i])
676
family->writingSystems[i] = QtFontFamily::Supported;
678
family->writingSystems[i] |= QtFontFamily::UnsupportedXLFD;
680
if (encoding_id == -1)
681
family->xlfdLoaded = true;
684
// mark encoding as loaded
685
if (encoding_id == -1)
686
xlfdsFullyLoaded = true;
688
encodingLoaded[encoding_id] = true;
691
XFreeFontNames(fontList);
695
#ifndef QT_NO_FONTCONFIG
696
static int getFCWeight(int fc_weight)
698
int qtweight = QFont::Black;
699
if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2)
700
qtweight = QFont::Light;
701
else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2)
702
qtweight = QFont::Normal;
703
else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2)
704
qtweight = QFont::DemiBold;
705
else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2)
706
qtweight = QFont::Bold;
711
QFontDef FcPatternToQFontDef(FcPattern *pattern)
716
if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) == FcResultMatch) {
717
fontDef.family = QString::fromUtf8(reinterpret_cast<const char *>(value));
718
fontDef.family.replace('-', ' ');
719
fontDef.family.replace("/", "");
723
if (FcPatternGetDouble(pattern, FC_DPI, 0, &dpi) != FcResultMatch)
724
dpi = QX11Info::appDpiY();
727
if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
728
fontDef.pixelSize = qRound(size);
730
fontDef.pixelSize = 12;
732
fontDef.pointSize = qt_pointSize(fontDef.pixelSize, qRound(dpi));
735
fontDef.styleStrategy
740
if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight) != FcResultMatch)
741
weight = FC_WEIGHT_MEDIUM;
742
fontDef.weight = getFCWeight(weight);
745
if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant) != FcResultMatch)
746
slant = FC_SLANT_ROMAN;
747
fontDef.style = (slant == FC_SLANT_ITALIC)
749
: ((slant == FC_SLANT_OBLIQUE)
750
? QFont::StyleOblique
751
: QFont::StyleNormal);
754
if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch)
759
if (FcPatternGetMatrix(pattern, FC_MATRIX, 0, &matrix) != FcResultMatch) {
760
FcMatrixInit(&identity);
763
if (matrix->yx == 0.0 && matrix->yy == 1.0) {
765
fontDef.stretch = qRound(matrix->xx * 100.0);
767
if (matrix->xy != 0.0) {
768
// yup... we're using our "fake oblique" trick
769
fontDef.style = QFont::StyleOblique;
773
fontDef.stretch = 100;
776
#if FC_VERSION >= 20193
778
if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width) == FcResultMatch)
779
fontDef.stretch = width;
782
fontDef.stretch = 100;
786
if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing) == FcResultMatch) {
787
fontDef.fixedPitch = (spacing >= FC_MONO);
788
fontDef.ignorePitch = false;
790
fontDef.ignorePitch = true;
796
static const char *specialLanguages[] = {
819
enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) };
821
// this could become a list of all languages used for each writing
822
// system, instead of using the single most common language.
823
static const char *languageForWritingSystem[] = {
849
"zh-cn", // SimplifiedChinese
850
"zh-tw", // TraditionalChinese
855
enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) };
857
static void loadFontConfig()
859
if (!X11->has_fontconfig)
862
Q_ASSERT_X(int(QUnicodeTables::ScriptCount) == SpecialLanguageCount,
863
"QFontDatabase", "New scripts have been added.");
864
Q_ASSERT_X((QFontDatabase::WritingSystemsCount - 1) == LanguageCount,
865
"QFontDatabase", "New writing systems have been added.");
867
QFontDatabasePrivate *db = privateDb();
878
FcChar8 *foundry_value;
882
FcObjectSet *os = FcObjectSetCreate();
883
FcPattern *pattern = FcPatternCreate();
884
const char *properties [] = {
885
FC_FAMILY, FC_WEIGHT, FC_SLANT,
886
FC_SPACING, FC_FILE, FC_INDEX,
887
FC_LANG, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT,
888
#if FC_VERSION >= 20193
893
const char **p = properties;
895
FcObjectSetAdd(os, *p);
898
fonts = FcFontList(0, pattern, os);
899
FcObjectSetDestroy(os);
900
FcPatternDestroy(pattern);
903
for (int i = 0; i < fonts->nfont; i++) {
904
if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
906
// capitalize(value);
907
rawName = familyName = QString::fromUtf8((const char *)value);
908
familyName.replace('-', ' ');
909
familyName.replace("/", "");
910
slant_value = FC_SLANT_ROMAN;
911
weight_value = FC_WEIGHT_MEDIUM;
912
spacing_value = FC_PROPORTIONAL;
917
if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch)
918
slant_value = FC_SLANT_ROMAN;
919
if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch)
920
weight_value = FC_WEIGHT_MEDIUM;
921
if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch)
922
spacing_value = FC_PROPORTIONAL;
923
if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch)
925
if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &index_value) != FcResultMatch)
927
if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch)
929
if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
931
QtFontFamily *family = db->family(familyName, true);
932
family->rawName = rawName;
933
family->hasFT = true;
935
FcLangSet *langset = 0;
936
FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset);
937
if (res == FcResultMatch) {
938
for (int i = 1; i < LanguageCount; ++i) {
939
const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i];
941
family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
943
FcLangResult langRes = FcLangSetHasLang(langset, lang);
944
if (langRes != FcLangDifferentLang)
945
family->writingSystems[i] = QtFontFamily::Supported;
947
family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
950
family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
951
family->ftWritingSystemCheck = true;
953
// we set Other to supported for symbol fonts. It makes no
954
// sense to merge these with other ones, as they are
956
for (int i = 1; i < LanguageCount; ++i)
957
family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
958
family->writingSystems[QFontDatabase::Other] = QtFontFamily::Supported;
961
QByteArray file((const char *)file_value);
962
family->fontFilename = file;
963
family->fontFileIndex = index_value;
965
QtFontStyle::Key styleKey;
966
styleKey.style = (slant_value == FC_SLANT_ITALIC)
968
: ((slant_value == FC_SLANT_OBLIQUE)
969
? QFont::StyleOblique
970
: QFont::StyleNormal);
971
styleKey.weight = getFCWeight(weight_value);
974
#if FC_VERSION >= 20193
975
FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width);
977
styleKey.stretch = width;
980
QtFontFoundry *foundry
981
= family->foundry(foundry_value ? QString::fromUtf8((const char *)foundry_value) : QString(), true);
982
QtFontStyle *style = foundry->style(styleKey, true);
984
if (spacing_value < FC_MONO)
985
family->fixedPitch = false;
989
style->smoothScalable = true;
990
size = style->pixelSize(SMOOTH_SCALABLE, true);
992
double pixel_size = 0;
993
FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size);
994
size = style->pixelSize((int)pixel_size, true);
996
QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
997
enc->pitch = (spacing_value >= FC_CHARCELL ? 'c' :
998
(spacing_value >= FC_MONO ? 'm' : 'p'));
1001
FcFontSetDestroy (fonts);
1003
struct FcDefaultFont {
1005
const char *rawname;
1008
const FcDefaultFont defaults[] = {
1009
{ "Serif", "serif", false },
1010
{ "Sans Serif", "sans-serif", false },
1011
{ "Monospace", "monospace", true },
1014
const FcDefaultFont *f = defaults;
1016
QtFontFamily *family = db->family(f->qtname, true);
1017
family->rawName = f->rawname;
1018
family->hasFT = true;
1019
family->synthetic = true;
1020
QtFontFoundry *foundry = family->foundry(QString(), true);
1022
// aliases only make sense for 'common', not for any of the specials
1023
for (int i = 1; i < LanguageCount; ++i) {
1024
if (requiresOpenType(i))
1025
family->writingSystems[i] = QtFontFamily::UnsupportedFT;
1027
family->writingSystems[i] = QtFontFamily::Supported;
1029
family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
1031
QtFontStyle::Key styleKey;
1032
for (int i = 0; i < 4; ++i) {
1033
styleKey.style = (i%2) ? QFont::StyleNormal : QFont::StyleItalic;
1034
styleKey.weight = (i > 1) ? QFont::Bold : QFont::Normal;
1035
QtFontStyle *style = foundry->style(styleKey, true);
1036
style->smoothScalable = true;
1037
QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE, true);
1038
QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
1039
enc->pitch = (f->fixed ? 'm' : 'p');
1044
#endif // QT_NO_FONTCONFIG
1046
static void load(const QString &family = QString(), int script = -1)
1048
if (X11->has_fontconfig)
1051
#ifdef QFONTDATABASE_DEBUG
1056
if (family.isNull() && script == -1) {
1059
if (family.isNull()) {
1060
// load all families in all writing systems that match \a script
1061
for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
1062
if (scriptForWritingSystem[ws] != script)
1064
for (int i = 0; i < numEncodings; ++i) {
1065
if (writingSystems_for_xlfd_encoding[i][ws])
1070
QtFontFamily *f = privateDb()->family(family, true);
1071
// could reduce this further with some more magic:
1072
// would need to remember the encodings loaded for the family.
1074
loadXlfds(family.toLatin1(), -1);
1078
#ifdef QFONTDATABASE_DEBUG
1079
FD_DEBUG("QFontDatabase: load(%s, %d) took %d ms",
1080
family.toLatin1().constData(), script, t.elapsed());
1084
static void initializeDb()
1086
QFontDatabasePrivate *db = privateDb();
1087
if (!db || db->count)
1093
#ifndef QT_NO_FONTCONFIG
1095
FD_DEBUG("QFontDatabase: loaded FontConfig: %d ms", t.elapsed());
1100
#ifndef QT_NO_FONTCONFIG
1101
for (int i = 0; i < db->count; i++) {
1102
for (int j = 0; j < db->families[i]->count; ++j) { // each foundry
1103
QtFontFoundry *foundry = db->families[i]->foundries[j];
1104
for (int k = 0; k < foundry->count; ++k) {
1105
QtFontStyle *style = foundry->styles[k];
1106
if (style->key.style != QFont::StyleNormal) continue;
1108
QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE);
1109
if (! size) continue; // should not happen
1110
QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
1111
if (! enc) continue; // should not happen either
1113
QtFontStyle::Key key = style->key;
1115
// does this style have an italic equivalent?
1116
key.style = QFont::StyleItalic;
1117
QtFontStyle *equiv = foundry->style(key);
1118
if (equiv) continue;
1120
// does this style have an oblique equivalent?
1121
key.style = QFont::StyleOblique;
1122
equiv = foundry->style(key);
1123
if (equiv) continue;
1125
// let's fake one...
1126
equiv = foundry->style(key, true);
1127
equiv->smoothScalable = true;
1128
equiv->fakeOblique = true;
1130
QtFontSize *equiv_size = equiv->pixelSize(SMOOTH_SCALABLE, true);
1131
QtFontEncoding *equiv_enc = equiv_size->encodingID(-1, 0, 0, 0, 0, true);
1133
// keep the same pitch
1134
equiv_enc->pitch = enc->pitch;
1141
#ifdef QFONTDATABASE_DEBUG
1142
#ifndef QT_NO_FONTCONFIG
1143
if (!X11->has_fontconfig)
1145
// load everything at startup in debug mode.
1148
// print the database
1149
for (int f = 0; f < db->count; f++) {
1150
QtFontFamily *family = db->families[f];
1151
FD_DEBUG("'%s' %s hasFT=%s", family->name.latin1(), (family->fixedPitch ? "fixed" : ""),
1152
(family->hasFT ? "yes" : "no"));
1153
for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
1154
QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
1155
FD_DEBUG("\t%s: %s", QFontDatabase::writingSystemName(ws).toLatin1().constData(),
1156
((family->writingSystems[i] & QtFontFamily::Supported) ? "Supported" :
1157
(family->writingSystems[i] & QtFontFamily::Unsupported) == QtFontFamily::Unsupported ?
1158
"Unsupported" : "Unknown"));
1161
for (int fd = 0; fd < family->count; fd++) {
1162
QtFontFoundry *foundry = family->foundries[fd];
1163
FD_DEBUG("\t\t'%s'", foundry->name.latin1());
1164
for (int s = 0; s < foundry->count; s++) {
1165
QtFontStyle *style = foundry->styles[s];
1166
FD_DEBUG("\t\t\tstyle: style=%d weight=%d (%s)\n"
1167
"\t\t\tstretch=%d (%s)",
1168
style->key.style, style->key.weight,
1169
style->weightName, style->key.stretch,
1170
style->setwidthName ? style->setwidthName : "nil");
1171
if (style->smoothScalable)
1172
FD_DEBUG("\t\t\t\tsmooth scalable");
1173
else if (style->bitmapScalable)
1174
FD_DEBUG("\t\t\t\tbitmap scalable");
1175
if (style->pixelSizes) {
1176
qDebug("\t\t\t\t%d pixel sizes", style->count);
1177
for (int z = 0; z < style->count; ++z) {
1178
QtFontSize *size = style->pixelSizes + z;
1179
for (int e = 0; e < size->count; ++e) {
1180
FD_DEBUG("\t\t\t\t size %5d pitch %c encoding %s",
1182
size->encodings[e].pitch,
1183
xlfd_for_id(size->encodings[e].encoding));
1190
#endif // QFONTDATABASE_DEBUG
1194
// --------------------------------------------------------------------------------------
1196
// --------------------------------------------------------------------------------------
1198
#ifndef QT_NO_FONTCONFIG
1200
static void addPatternProps(FcPattern *pattern, const QtFontStyle::Key &key,
1201
bool fakeOblique, bool smoothScalable,
1202
const QFontPrivate *fp, const QFontDef &request, int script)
1204
int weight_value = FC_WEIGHT_BLACK;
1205
if (key.weight == 0)
1206
weight_value = FC_WEIGHT_MEDIUM;
1207
else if (key.weight < (QFont::Light + QFont::Normal) / 2)
1208
weight_value = FC_WEIGHT_LIGHT;
1209
else if (key.weight < (QFont::Normal + QFont::DemiBold) / 2)
1210
weight_value = FC_WEIGHT_MEDIUM;
1211
else if (key.weight < (QFont::DemiBold + QFont::Bold) / 2)
1212
weight_value = FC_WEIGHT_DEMIBOLD;
1213
else if (key.weight < (QFont::Bold + QFont::Black) / 2)
1214
weight_value = FC_WEIGHT_BOLD;
1215
FcPatternAddInteger(pattern, FC_WEIGHT, weight_value);
1217
int slant_value = FC_SLANT_ROMAN;
1218
if (key.style == QFont::StyleItalic)
1219
slant_value = FC_SLANT_ITALIC;
1220
else if (key.style == QFont::StyleOblique && !fakeOblique)
1221
slant_value = FC_SLANT_OBLIQUE;
1222
FcPatternAddInteger(pattern, FC_SLANT, slant_value);
1224
double size_value = request.pixelSize;
1225
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size_value);
1227
if (!smoothScalable) {
1228
#if FC_VERSION >= 20193
1229
int stretch = request.stretch;
1232
FcPatternAddInteger(pattern, FC_WIDTH, stretch);
1235
FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
1237
if ((request.stretch > 0 && request.stretch != 100) ||
1238
(key.style == QFont::StyleOblique && fakeOblique)) {
1241
FcMatrixInit(&matrix);
1243
if (request.stretch > 0 && request.stretch != 100)
1244
FcMatrixScale(&matrix, double(request.stretch) / 100.0, 1.0);
1245
if (key.style == QFont::StyleOblique && fakeOblique)
1246
FcMatrixShear(&matrix, 0.20, 0.0);
1248
FcPatternAddMatrix(pattern, FC_MATRIX, &matrix);
1252
if (QX11Info::appDepth(fp->screen) <= 8) {
1253
// can't do antialiasing on 8bpp
1254
FcPatternAddBool(pattern, FC_ANTIALIAS, false);
1255
} else if (request.styleStrategy & (QFont::PreferAntialias|QFont::NoAntialias)) {
1256
FcPatternAddBool(pattern, FC_ANTIALIAS,
1257
!(request.styleStrategy & QFont::NoAntialias));
1260
if (script != QUnicodeTables::Common) {
1261
Q_ASSERT(script < QUnicodeTables::ScriptCount);
1262
FcLangSet *ls = FcLangSetCreate();
1263
FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
1264
FcPatternAddLangSet(pattern, FC_LANG, ls);
1265
FcLangSetDestroy(ls);
1269
static void FcFontSetRemove(FcFontSet *fs, int at)
1271
Q_ASSERT(at < fs->nfont);
1272
FcPatternDestroy(fs->fonts[at]);
1273
int len = (--fs->nfont - at) * sizeof(FcPattern *);;
1275
memmove(fs->fonts + at, fs->fonts + at + 1, len);
1278
static QFontEngine *loadFcEngineFromPattern(FcPattern *pattern, const QFontPrivate *fp,
1279
const QFontDef &request, int script)
1281
FcBool forceScalable = true;
1282
FcPatternGetBool(pattern, FC_SCALABLE, 0, &forceScalable);
1284
FcDefaultSubstitute(pattern);
1285
FcConfigSubstitute(0, pattern, FcMatchPattern);
1286
FcConfigSubstitute(0, pattern, FcMatchFont);
1288
#ifdef FONT_MATCH_DEBUG
1289
printf("forceScalable=%d", forceScalable);
1290
printf("final FcPattern contains:\n");
1291
FcPatternPrint(pattern);
1295
FcFontSet *fs = FcFontSort(0, pattern, FcTrue, 0, &result);
1296
FcPatternDestroy(pattern);
1300
double size_value = request.pixelSize;
1302
// remove fonts if their size isn't close enough, or if they are
1303
// not scalable (and should be)
1304
for (int i = 0; i < fs->nfont; ++i) {
1305
FcPattern *font = fs->fonts[i];
1308
res = FcPatternGetBool(font, FC_SCALABLE, 0, &scalable);
1309
if (res != FcResultMatch || !scalable) {
1310
if (forceScalable) {
1311
FcFontSetRemove(fs, i);
1312
#ifdef FONT_MATCH_DEBUG
1313
printf("removing pattern:");
1314
FcPatternPrint(font);
1319
res = FcPatternGetDouble(font, FC_PIXEL_SIZE, 0, &pixelSize);
1320
if (res != FcResultMatch || qAbs((size_value-pixelSize)/size_value) > 0.2) {
1321
FcFontSetRemove(fs, i);
1322
#ifdef FONT_MATCH_DEBUG
1323
printf("removing pattern:");
1324
FcPatternPrint(font);
1332
QtFontStyle::Key key;
1333
key.style = request.style;
1334
key.weight = request.weight;
1335
key.stretch = request.stretch;
1337
QFontEngine *fe = 0;
1338
if (script != QUnicodeTables::Common) {
1339
// load a single font for the script
1341
for (int i = 0; !fe && i < fs->nfont; ++i) {
1342
// skip font if it doesn't support the language we want
1343
FcLangSet *langSet = 0;
1344
if (FcPatternGetLangSet(fs->fonts[i], FC_LANG, 0, &langSet) != FcResultMatch)
1346
if (FcLangSetHasLang(langSet, (const FcChar8*)specialLanguages[script]) != FcLangEqual)
1349
FcPattern *pattern = FcPatternDuplicate(fs->fonts[i]);
1350
// add properties back in as the font selected from the
1351
// list doesn't contain them.
1352
addPatternProps(pattern, key, false, true, fp, request, script);
1354
FcConfigSubstitute(0, pattern, FcMatchPattern);
1355
FcDefaultSubstitute(pattern);
1357
FcPattern *match = FcFontMatch(0, pattern, &res);
1358
QFontEngineFT *engine = new QFontEngineFT(match, request, fp->screen);
1359
if (engine->invalid())
1365
// create a multi engine for the fontset fontconfig gave us
1366
FcFontSet *fontSet = FcFontSetCreate();
1367
for (int i = 0; i < fs->nfont; ++i) {
1368
FcPattern *pattern = FcPatternDuplicate(fs->fonts[i]);
1369
// add properties back in as the font selected from the
1370
// list doesn't contain them.
1371
addPatternProps(pattern, key, false, true, fp, request, script);
1372
FcFontSetAdd(fontSet, pattern);
1375
fe = new QFontEngineMultiFT(fontSet, fp->screen);
1376
fe->fontDef = request;
1379
FcFontSetDestroy(fs);
1383
#endif // QT_NO_FONTCONFIG
1386
QFontEngine *loadEngine(int script,
1387
const QFontPrivate *fp, const QFontDef &request,
1388
QtFontFamily *family, QtFontFoundry *foundry,
1389
QtFontStyle *style, QtFontSize *size,
1390
QtFontEncoding *encoding, bool forced_encoding)
1394
if (fp && fp->rawMode) {
1395
QByteArray xlfd = request.family.toLatin1();
1396
FM_DEBUG("Loading XLFD (rawmode) '%s'", xlfd.data());
1399
if (! (xfs = XLoadQueryFont(QX11Info::display(), xlfd.data())))
1402
QFontEngine *fe = new QFontEngineXLFD(xfs, xlfd.data(), 0);
1403
if (! qt_fillFontDef(xfs, &fe->fontDef, fp->dpi) &&
1404
! qt_fillFontDef(xlfd, &fe->fontDef, fp->dpi))
1405
fe->fontDef = QFontDef();
1410
#ifndef QT_NO_FONTCONFIG
1411
if (X11->has_fontconfig && encoding->encoding == -1) {
1413
FM_DEBUG(" using FontConfig");
1415
FcPattern *pattern = FcPatternCreate();
1419
if (!foundry->name.isEmpty()) {
1420
FcPatternAddString(pattern, FC_FOUNDRY,
1421
(const FcChar8 *)foundry->name.toUtf8().constData());
1424
QStringList familyList;
1425
if (!family->rawName.isEmpty()) {
1426
FcPatternAddString(pattern, FC_FAMILY,
1427
(const FcChar8 *)family->rawName.toUtf8().constData());
1428
familyList << family->name;
1432
switch (request.styleHint) {
1433
case QFont::SansSerif:
1434
stylehint = "sans-serif";
1437
stylehint = "serif";
1439
case QFont::TypeWriter:
1440
stylehint = "monospace";
1443
if (request.fixedPitch)
1444
stylehint = "monospace";
1447
if (!stylehint.isEmpty()) {
1448
FcPatternAddString(pattern, FC_FAMILY,
1449
(const FcChar8 *)stylehint.toUtf8().constData());
1450
familyList << family->name;
1454
value.type = FcTypeString;
1456
// these should only get added to the pattern _after_ substitution
1457
// append the default fallback font for the specified script
1458
extern QString qt_fallback_font_family(int);
1459
QString fallback = qt_fallback_font_family(script);
1460
if (!fallback.isEmpty() && !familyList.contains(fallback)) {
1461
QByteArray cs = fallback.toUtf8();
1462
value.u.s = (const FcChar8 *)cs.data();
1463
FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1466
// add the default family
1467
QString defaultFamily = QApplication::font().family();
1468
if (!familyList.contains(defaultFamily)) {
1469
QByteArray cs = defaultFamily.toUtf8();
1470
value.u.s = (const FcChar8 *)cs.data();
1471
FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1474
// add QFont::defaultFamily() to the list, for compatibility with
1475
// previous versions
1476
defaultFamily = QApplication::font().defaultFamily();
1477
if (!familyList.contains(defaultFamily)) {
1478
QByteArray cs = defaultFamily.toUtf8();
1479
value.u.s = (const FcChar8 *)cs.data();
1480
FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
1483
char pitch_value = (encoding->pitch == 'c' ? FC_CHARCELL :
1484
(encoding->pitch == 'm' ? FC_MONO : FC_PROPORTIONAL));
1485
FcPatternAddInteger(pattern, FC_SPACING, pitch_value);
1486
FcPatternAddBool(pattern, FC_SCALABLE, style->smoothScalable);
1488
addPatternProps(pattern, style->key, style->fakeOblique, style->smoothScalable,
1489
fp, request, script);
1490
return loadFcEngineFromPattern(pattern, fp, request, script);
1492
#endif // QT_NO_FONTCONFIG
1494
int px = size->pixelSize;
1495
if (style->smoothScalable && px == SMOOTH_SCALABLE)
1496
px = request.pixelSize;
1497
else if (style->bitmapScalable && px == 0)
1498
px = request.pixelSize;
1500
QFontEngine *fe = 0;
1501
if (forced_encoding || script != QUnicodeTables::Common) {
1502
QByteArray xlfd("-");
1503
xlfd += foundry->name.isEmpty() ? QByteArray("*") : foundry->name.toLatin1();
1505
xlfd += family->name.isEmpty() ? QByteArray("*") : family->name.toLatin1();
1507
xlfd += style->weightName ? style->weightName : "*";
1509
xlfd += (style->key.style == QFont::StyleItalic
1511
: (style->key.style == QFont::StyleOblique ? "o" : "r"));
1513
xlfd += style->setwidthName ? style->setwidthName : "*";
1514
// ### handle add-style
1516
xlfd += QByteArray::number(px);
1518
xlfd += QByteArray::number(encoding->xpoint);
1520
xlfd += QByteArray::number(encoding->xres);
1522
xlfd += QByteArray::number(encoding->yres);
1524
xlfd += encoding->pitch;
1526
xlfd += QByteArray::number(encoding->avgwidth);
1528
xlfd += xlfd_for_id(encoding->encoding);
1530
FM_DEBUG(" using XLFD: %s\n", xlfd.data());
1532
const int mib = xlfd_encoding[encoding->encoding].mib;
1534
if (! (xfs = XLoadQueryFont(QX11Info::display(), xlfd)))
1536
fe = new QFontEngineXLFD(xfs, xlfd, mib);
1538
QList<int> encodings;
1539
encodings.append(int(encoding->encoding));
1541
// append all other encodings for the matched font
1542
for (int i = 0; i < style->count; ++i) {
1543
QtFontEncoding *e = size->encodings + i;
1546
encodings.append(int(e->encoding));
1548
// fill in the missing encodings
1549
const XlfdEncoding *enc = xlfd_encoding;
1550
for (; enc->name; ++enc) {
1551
if (!encodings.contains(enc->id))
1552
encodings.append(enc->id);
1555
#if defined(FONT_MATCH_DEBUG)
1556
FM_DEBUG(" using MultiXLFD, encodings:");
1557
for (int i = 0; i < encodings.size(); ++i) {
1558
const int id = encodings.at(i);
1559
FM_DEBUG(" %2d: %s", xlfd_encoding[id].id, xlfd_encoding[id].name);
1563
fe = new QFontEngineMultiXLFD(request, encodings, fp->screen);