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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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