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