source: trunk/src/gui/text/qfontdatabase_x11.cpp@ 172

Last change on this file since 172 was 2, checked in by Dmitry A. Kuminov, 17 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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