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

Last change on this file since 563 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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