source: trunk/src/gui/text/qfontdatabase_win.cpp@ 352

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

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

File size: 42.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qt_windows.h"
43#include <private/qapplication_p.h>
44#include "qfont_p.h"
45#include "qfontengine_p.h"
46#include "qpaintdevice.h"
47#include "qlibrary.h"
48#include "qabstractfileengine.h"
49#include "qendian.h"
50
51#ifdef Q_OS_WINCE
52# include <QTemporaryFile>
53#endif
54
55QT_BEGIN_NAMESPACE
56
57extern HDC shared_dc(); // common dc for all fonts
58
59#ifdef MAKE_TAG
60#undef MAKE_TAG
61#endif
62// GetFontData expects the tags in little endian ;(
63#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
64 (((quint32)(ch4)) << 24) | \
65 (((quint32)(ch3)) << 16) | \
66 (((quint32)(ch2)) << 8) | \
67 ((quint32)(ch1)) \
68 )
69
70static HFONT stock_sysfont = 0;
71
72static bool localizedName(const QString &name)
73{
74 const QChar *c = name.unicode();
75 for(int i = 0; i < name.length(); ++i) {
76 if(c[i].unicode() >= 0x100)
77 return true;
78 }
79 return false;
80}
81
82static inline quint16 getUShort(const unsigned char *p)
83{
84 quint16 val;
85 val = *p++ << 8;
86 val |= *p;
87
88 return val;
89}
90
91static QString getEnglishName(const uchar *table, quint32 bytes)
92{
93 QString i18n_name;
94 enum {
95 NameRecordSize = 12,
96 FamilyId = 1,
97 MS_LangIdEnglish = 0x009
98 };
99
100 // get the name table
101 quint16 count;
102 quint16 string_offset;
103 const unsigned char *names;
104
105 int microsoft_id = -1;
106 int apple_id = -1;
107 int unicode_id = -1;
108
109 if(getUShort(table) != 0)
110 goto error;
111
112 count = getUShort(table+2);
113 string_offset = getUShort(table+4);
114 names = table + 6;
115
116 if(string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
117 goto error;
118
119 for(int i = 0; i < count; ++i) {
120 // search for the correct name entry
121
122 quint16 platform_id = getUShort(names + i*NameRecordSize);
123 quint16 encoding_id = getUShort(names + 2 + i*NameRecordSize);
124 quint16 language_id = getUShort(names + 4 + i*NameRecordSize);
125 quint16 name_id = getUShort(names + 6 + i*NameRecordSize);
126
127 if(name_id != FamilyId)
128 continue;
129
130 enum {
131 PlatformId_Unicode = 0,
132 PlatformId_Apple = 1,
133 PlatformId_Microsoft = 3
134 };
135
136 quint16 length = getUShort(names + 8 + i*NameRecordSize);
137 quint16 offset = getUShort(names + 10 + i*NameRecordSize);
138 if(DWORD(string_offset + offset + length) >= bytes)
139 continue;
140
141 if ((platform_id == PlatformId_Microsoft
142 && (encoding_id == 0 || encoding_id == 1))
143 && (language_id & 0x3ff) == MS_LangIdEnglish
144 && microsoft_id == -1)
145 microsoft_id = i;
146 // not sure if encoding id 4 for Unicode is utf16 or ucs4...
147 else if(platform_id == PlatformId_Unicode && encoding_id < 4 && unicode_id == -1)
148 unicode_id = i;
149 else if(platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0)
150 apple_id = i;
151 }
152 {
153 bool unicode = false;
154 int id = -1;
155 if(microsoft_id != -1) {
156 id = microsoft_id;
157 unicode = true;
158 } else if(apple_id != -1) {
159 id = apple_id;
160 unicode = false;
161 } else if (unicode_id != -1) {
162 id = unicode_id;
163 unicode = true;
164 }
165 if(id != -1) {
166 quint16 length = getUShort(names + 8 + id*NameRecordSize);
167 quint16 offset = getUShort(names + 10 + id*NameRecordSize);
168 if(unicode) {
169 // utf16
170
171 length /= 2;
172 i18n_name.resize(length);
173 QChar *uc = (QChar *) i18n_name.unicode();
174 const unsigned char *string = table + string_offset + offset;
175 for(int i = 0; i < length; ++i)
176 uc[i] = getUShort(string + 2*i);
177 } else {
178 // Apple Roman
179
180 i18n_name.resize(length);
181 QChar *uc = (QChar *) i18n_name.unicode();
182 const unsigned char *string = table + string_offset + offset;
183 for(int i = 0; i < length; ++i)
184 uc[i] = QLatin1Char(string[i]);
185 }
186 }
187 }
188 error:
189 //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
190 return i18n_name;
191}
192
193static QString getEnglishName(const QString &familyName)
194{
195 QString i18n_name;
196
197 HDC hdc = GetDC( 0 );
198 HFONT hfont;
199 QT_WA( {
200 LOGFONTW lf;
201 memset( &lf, 0, sizeof( LOGFONTW ) );
202 memcpy( lf.lfFaceName, familyName.utf16(), qMin(LF_FACESIZE, familyName.length())*sizeof(QChar) );
203 lf.lfCharSet = DEFAULT_CHARSET;
204 hfont = CreateFontIndirectW( &lf );
205 }, {
206 LOGFONTA lf;
207 memset( &lf, 0, sizeof( LOGFONTA ) );
208 QByteArray lfam = familyName.toLocal8Bit();
209 memcpy( lf.lfFaceName, lfam, qMin(LF_FACESIZE, lfam.size()) );
210 lf.lfCharSet = DEFAULT_CHARSET;
211 hfont = CreateFontIndirectA( &lf );
212 } );
213 if(!hfont) {
214 ReleaseDC(0, hdc);
215 return QString();
216 }
217
218 HGDIOBJ oldobj = SelectObject( hdc, hfont );
219
220 const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
221
222 // get the name table
223 unsigned char *table = 0;
224
225 DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
226 if ( bytes == GDI_ERROR ) {
227 // ### Unused variable
228 /* int err = GetLastError(); */
229 goto error;
230 }
231
232 table = new unsigned char[bytes];
233 GetFontData(hdc, name_tag, 0, table, bytes);
234 if ( bytes == GDI_ERROR )
235 goto error;
236
237 i18n_name = getEnglishName(table, bytes);
238error:
239 delete [] table;
240 SelectObject( hdc, oldobj );
241 DeleteObject( hfont );
242 ReleaseDC( 0, hdc );
243
244 //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
245 return i18n_name;
246}
247
248static void getFontSignature(const QString &familyName,
249 NEWTEXTMETRICEX *textmetric,
250 FONTSIGNATURE *signature)
251{
252 QT_WA({
253 Q_UNUSED(familyName);
254 *signature = textmetric->ntmFontSig;
255 }, {
256 // the textmetric structure we get from EnumFontFamiliesEx on Win9x has
257 // a FONTSIGNATURE, but that one is uninitialized and doesn't work. Have to go
258 // the hard way and load the font to find out.
259 HDC hdc = GetDC(0);
260 LOGFONTA lf;
261 memset(&lf, 0, sizeof(LOGFONTA));
262 QByteArray lfam = familyName.toLocal8Bit();
263 memcpy(lf.lfFaceName, lfam.data(), qMin(LF_FACESIZE, lfam.length()));
264 lf.lfCharSet = DEFAULT_CHARSET;
265 HFONT hfont = CreateFontIndirectA(&lf);
266 HGDIOBJ oldobj = SelectObject(hdc, hfont);
267 GetTextCharsetInfo(hdc, signature, 0);
268 SelectObject(hdc, oldobj);
269 DeleteObject(hfont);
270 ReleaseDC(0, hdc);
271 });
272}
273
274static
275void addFontToDatabase(QString familyName, const QString &scriptName,
276 TEXTMETRIC *textmetric,
277 const FONTSIGNATURE *signature,
278 int type)
279{
280 const int script = -1;
281 const QString foundryName;
282 Q_UNUSED(script);
283
284 bool italic = false;
285 int weight;
286 bool fixed;
287 bool ttf;
288 bool scalable;
289 int size;
290
291// QString escript = QString::fromUtf16((ushort *)f->elfScript);
292// qDebug("script=%s", escript.latin1());
293
294 QT_WA({
295 NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric;
296 fixed = !(tm->tmPitchAndFamily & TMPF_FIXED_PITCH);
297 ttf = (tm->tmPitchAndFamily & TMPF_TRUETYPE);
298 scalable = tm->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
299 size = scalable ? SMOOTH_SCALABLE : tm->tmHeight;
300 italic = tm->tmItalic;
301 weight = tm->tmWeight;
302 } , {
303 NEWTEXTMETRICA *tm = (NEWTEXTMETRICA *)textmetric;
304 fixed = !(tm->tmPitchAndFamily & TMPF_FIXED_PITCH);
305 ttf = (tm->tmPitchAndFamily & TMPF_TRUETYPE);
306 scalable = tm->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
307 size = scalable ? SMOOTH_SCALABLE : tm->tmHeight;
308 italic = tm->tmItalic;
309 weight = tm->tmWeight;
310 });
311 // the "@family" fonts are just the same as "family". Ignore them.
312 if (familyName[0] != QLatin1Char('@') && !familyName.startsWith(QLatin1String("WST_"))) {
313 QtFontStyle::Key styleKey;
314 styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
315 if (weight < 400)
316 styleKey.weight = QFont::Light;
317 else if (weight < 600)
318 styleKey.weight = QFont::Normal;
319 else if (weight < 700)
320 styleKey.weight = QFont::DemiBold;
321 else if (weight < 800)
322 styleKey.weight = QFont::Bold;
323 else
324 styleKey.weight = QFont::Black;
325
326 QtFontFamily *family = privateDb()->family(familyName, true);
327
328 if(ttf && localizedName(familyName) && family->english_name.isEmpty())
329 family->english_name = getEnglishName(familyName);
330
331 QtFontFoundry *foundry = family->foundry(foundryName, true);
332 QtFontStyle *style = foundry->style(styleKey, true);
333 style->smoothScalable = scalable;
334 style->pixelSize( size, TRUE);
335
336 // add fonts windows can generate for us:
337 if (styleKey.weight <= QFont::DemiBold) {
338 QtFontStyle::Key key(styleKey);
339 key.weight = QFont::Bold;
340 QtFontStyle *style = foundry->style(key, true);
341 style->smoothScalable = scalable;
342 style->pixelSize( size, TRUE);
343 }
344 if (styleKey.style != QFont::StyleItalic) {
345 QtFontStyle::Key key(styleKey);
346 key.style = QFont::StyleItalic;
347 QtFontStyle *style = foundry->style(key, true);
348 style->smoothScalable = scalable;
349 style->pixelSize( size, TRUE);
350 }
351 if (styleKey.weight <= QFont::DemiBold && styleKey.style != QFont::StyleItalic) {
352 QtFontStyle::Key key(styleKey);
353 key.weight = QFont::Bold;
354 key.style = QFont::StyleItalic;
355 QtFontStyle *style = foundry->style(key, true);
356 style->smoothScalable = scalable;
357 style->pixelSize( size, TRUE);
358 }
359
360 family->fixedPitch = fixed;
361
362 if (!family->writingSystemCheck && type & TRUETYPE_FONTTYPE) {
363 quint32 unicodeRange[4] = {
364 signature->fsUsb[0], signature->fsUsb[1],
365 signature->fsUsb[2], signature->fsUsb[3]
366 };
367#ifdef Q_OS_WINCE
368 if (signature->fsUsb[0] == 0) {
369 // If the unicode ranges bit mask is zero then
370 // EnumFontFamiliesEx failed to determine it properly.
371 // In this case we just pretend that the font supports all languages.
372 unicodeRange[0] = 0xbfffffff; // second most significant bit must be zero
373 unicodeRange[1] = 0xffffffff;
374 unicodeRange[2] = 0xffffffff;
375 unicodeRange[3] = 0xffffffff;
376 }
377#endif
378 quint32 codePageRange[2] = {
379 signature->fsCsb[0], signature->fsCsb[1]
380 };
381 QList<QFontDatabase::WritingSystem> systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
382 for (int i = 0; i < systems.count(); ++i)
383 family->writingSystems[systems.at(i)] = QtFontFamily::Supported;
384 } else if (!family->writingSystemCheck) {
385 //qDebug("family='%s' script=%s", family->name.latin1(), script.latin1());
386 if (scriptName == QLatin1String("Western")
387 || scriptName == QLatin1String("Baltic")
388 || scriptName == QLatin1String("Central European")
389 || scriptName == QLatin1String("Turkish")
390 || scriptName == QLatin1String("Vietnamese"))
391 family->writingSystems[QFontDatabase::Latin] = QtFontFamily::Supported;
392 else if (scriptName == QLatin1String("Thai"))
393 family->writingSystems[QFontDatabase::Thai] = QtFontFamily::Supported;
394 else if (scriptName == QLatin1String("Symbol")
395 || scriptName == QLatin1String("Other"))
396 family->writingSystems[QFontDatabase::Symbol] = QtFontFamily::Supported;
397 else if (scriptName == QLatin1String("OEM/Dos"))
398 family->writingSystems[QFontDatabase::Latin] = QtFontFamily::Supported;
399 else if (scriptName == QLatin1String("CHINESE_GB2312"))
400 family->writingSystems[QFontDatabase::SimplifiedChinese] = QtFontFamily::Supported;
401 else if (scriptName == QLatin1String("CHINESE_BIG5"))
402 family->writingSystems[QFontDatabase::TraditionalChinese] = QtFontFamily::Supported;
403 else if (scriptName == QLatin1String("Cyrillic"))
404 family->writingSystems[QFontDatabase::Cyrillic] = QtFontFamily::Supported;
405 else if (scriptName == QLatin1String("Hangul"))
406 family->writingSystems[QFontDatabase::Korean] = QtFontFamily::Supported;
407 else if (scriptName == QLatin1String("Hebrew"))
408 family->writingSystems[QFontDatabase::Hebrew] = QtFontFamily::Supported;
409 else if (scriptName == QLatin1String("Greek"))
410 family->writingSystems[QFontDatabase::Greek] = QtFontFamily::Supported;
411 else if (scriptName == QLatin1String("Japanese"))
412 family->writingSystems[QFontDatabase::Japanese] = QtFontFamily::Supported;
413 else if (scriptName == QLatin1String("Arabic"))
414 family->writingSystems[QFontDatabase::Arabic] = QtFontFamily::Supported;
415 }
416 }
417}
418
419static
420int CALLBACK
421storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, int type, LPARAM /*p*/)
422{
423 QString familyName;
424 QT_WA({
425 familyName = QString::fromUtf16((ushort*)f->elfLogFont.lfFaceName);
426 },{
427 ENUMLOGFONTEXA *fa = (ENUMLOGFONTEXA *)f;
428 familyName = QString::fromLocal8Bit(fa->elfLogFont.lfFaceName);
429 });
430 QString script = QT_WA_INLINE(QString::fromUtf16((const ushort *)f->elfScript),
431 QString::fromLocal8Bit((const char *)((ENUMLOGFONTEXA *)f)->elfScript));
432
433 FONTSIGNATURE signature;
434 getFontSignature(familyName, textmetric, &signature);
435
436 // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
437 // identical to a TEXTMETRIC except for the last four members, which we don't use
438 // anyway
439 addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type);
440 // keep on enumerating
441 return 1;
442}
443
444static
445void populate_database(const QString& fam)
446{
447 QFontDatabasePrivate *d = privateDb();
448 if (!d)
449 return;
450
451 QtFontFamily *family = 0;
452 if(!fam.isEmpty()) {
453 family = d->family(fam);
454 if(family && family->loaded)
455 return;
456 } else if (d->count) {
457 return;
458 }
459
460 HDC dummy = GetDC(0);
461
462 QT_WA({
463 LOGFONT lf;
464 lf.lfCharSet = DEFAULT_CHARSET;
465 if (fam.isNull()) {
466 lf.lfFaceName[0] = 0;
467 } else {
468 memcpy(lf.lfFaceName, fam.utf16(), sizeof(TCHAR)*qMin(fam.length()+1,32)); // 32 = Windows hard-coded
469 }
470 lf.lfPitchAndFamily = 0;
471
472 EnumFontFamiliesEx(dummy, &lf,
473 (FONTENUMPROC)storeFont, (LPARAM)privateDb(), 0);
474 } , {
475 LOGFONTA lf;
476 lf.lfCharSet = DEFAULT_CHARSET;
477 if (fam.isNull()) {
478 lf.lfFaceName[0] = 0;
479 } else {
480 QByteArray lname = fam.toLocal8Bit();
481 memcpy(lf.lfFaceName,lname.data(),
482 qMin(lname.length()+1,32)); // 32 = Windows hard-coded
483 }
484 lf.lfPitchAndFamily = 0;
485
486 EnumFontFamiliesExA(dummy, &lf,
487 (FONTENUMPROCA)storeFont, (LPARAM)privateDb(), 0);
488 });
489
490 ReleaseDC(0, dummy);
491
492 for (int i = 0; i < d->applicationFonts.count(); ++i) {
493 QFontDatabasePrivate::ApplicationFont fnt = d->applicationFonts.at(i);
494 if (!fnt.memoryFont)
495 continue;
496 for (int j = 0; j < fnt.families.count(); ++j) {
497 const QString familyName = fnt.families.at(j);
498 HDC hdc = GetDC(0);
499 HFONT hfont;
500 QT_WA({
501 LOGFONTW lf;
502 memset(&lf, 0, sizeof(LOGFONTW));
503 memcpy(lf.lfFaceName, familyName.utf16(), qMin(LF_FACESIZE, familyName.size()));
504 lf.lfCharSet = DEFAULT_CHARSET;
505 hfont = CreateFontIndirectW(&lf);
506 } , {
507 LOGFONTA lf;
508 memset(&lf, 0, sizeof(LOGFONTA));
509 QByteArray lfam = familyName.toLocal8Bit();
510 memcpy(lf.lfFaceName, lfam.data(), qMin(LF_FACESIZE, lfam.length()));
511 lf.lfCharSet = DEFAULT_CHARSET;
512 hfont = CreateFontIndirectA(&lf);
513 });
514 HGDIOBJ oldobj = SelectObject(hdc, hfont);
515
516 TEXTMETRIC textMetrics;
517 GetTextMetrics(hdc, &textMetrics);
518
519 addFontToDatabase(familyName, QString(),
520 &textMetrics,
521 &fnt.signatures.at(j),
522 TRUETYPE_FONTTYPE);
523
524 SelectObject(hdc, oldobj);
525 DeleteObject(hfont);
526 ReleaseDC(0, hdc);
527 }
528 }
529
530 if(!fam.isEmpty()) {
531 family = d->family(fam);
532 if(family) {
533 if(!family->writingSystemCheck) {
534 }
535 family->loaded = true;
536 }
537 }
538}
539
540static void initializeDb()
541{
542 QFontDatabasePrivate *db = privateDb();
543 if (!db || db->count)
544 return;
545
546 populate_database(QString());
547
548#ifdef QFONTDATABASE_DEBUG
549 // print the database
550 for (int f = 0; f < db->count; f++) {
551 QtFontFamily *family = db->families[f];
552 qDebug(" %s: %p", family->name.latin1(), family);
553 populate_database(family->name);
554
555#if 0
556 qDebug(" scripts supported:");
557 for (int i = 0; i < QUnicodeTables::ScriptCount; i++)
558 if(family->writingSystems[i] & QtFontFamily::Supported)
559 qDebug(" %d", i);
560 for (int fd = 0; fd < family->count; fd++) {
561 QtFontFoundry *foundry = family->foundries[fd];
562 qDebug(" %s", foundry->name.latin1());
563 for (int s = 0; s < foundry->count; s++) {
564 QtFontStyle *style = foundry->styles[s];
565 qDebug(" style: style=%d weight=%d smooth=%d", style->key.style,
566 style->key.weight, style->smoothScalable );
567 if(!style->smoothScalable) {
568 for(int i = 0; i < style->count; ++i) {
569 qDebug(" %d", style->pixelSizes[i].pixelSize);
570 }
571 }
572 }
573 }
574#endif
575 }
576#endif // QFONTDATABASE_DEBUG
577
578}
579
580static inline void load(const QString &family = QString(), int = -1)
581{
582 populate_database(family);
583}
584
585
586
587
588
589// --------------------------------------------------------------------------------------
590// font loader
591// --------------------------------------------------------------------------------------
592
593
594
595static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, const QFontPrivate *fp)
596{
597 fe->fontDef = request; // most settings are equal
598
599 HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fp->hdc) ? fp->hdc : shared_dc();
600 SelectObject(dc, fe->hfont);
601 QT_WA({
602 TCHAR n[64];
603 GetTextFaceW(dc, 64, n);
604 fe->fontDef.family = QString::fromUtf16((ushort*)n);
605 fe->fontDef.fixedPitch = !(fe->tm.w.tmPitchAndFamily & TMPF_FIXED_PITCH);
606 } , {
607 char an[64];
608 GetTextFaceA(dc, 64, an);
609 fe->fontDef.family = QString::fromLocal8Bit(an);
610 fe->fontDef.fixedPitch = !(fe->tm.a.tmPitchAndFamily & TMPF_FIXED_PITCH);
611 });
612 if (fe->fontDef.pointSize < 0) {
613 fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi;
614 } else if (fe->fontDef.pixelSize == -1) {
615 fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.);
616 }
617}
618
619
620static const char *other_tryFonts[] = {
621 "Arial",
622 "MS UI Gothic",
623 "Gulim",
624 "SimSun",
625 "PMingLiU",
626 "Arial Unicode MS",
627 0
628};
629
630static const char *jp_tryFonts [] = {
631 "MS UI Gothic",
632 "Arial",
633 "Gulim",
634 "SimSun",
635 "PMingLiU",
636 "Arial Unicode MS",
637 0
638};
639
640static const char *ch_CN_tryFonts [] = {
641 "SimSun",
642 "Arial",
643 "PMingLiU",
644 "Gulim",
645 "MS UI Gothic",
646 "Arial Unicode MS",
647 0
648};
649
650static const char *ch_TW_tryFonts [] = {
651 "PMingLiU",
652 "Arial",
653 "SimSun",
654 "Gulim",
655 "MS UI Gothic",
656 "Arial Unicode MS",
657 0
658};
659
660static const char *kr_tryFonts[] = {
661 "Gulim",
662 "Arial",
663 "PMingLiU",
664 "SimSun",
665 "MS UI Gothic",
666 "Arial Unicode MS",
667 0
668};
669
670static const char **tryFonts = 0;
671
672
673static inline HFONT systemFont()
674{
675 if (stock_sysfont == 0)
676 stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT);
677 return stock_sysfont;
678}
679
680#if !defined(DEFAULT_GUI_FONT)
681#define DEFAULT_GUI_FONT 17
682#endif
683
684static
685QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &request, const QtFontDesc *desc,
686 const QStringList &family_list)
687{
688 LOGFONT lf;
689 memset(&lf, 0, sizeof(LOGFONT));
690
691 bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fp->hdc;
692
693 HDC hdc = shared_dc();
694 QString font_name = desc->family->name;
695
696 if (useDevice) {
697 hdc = fp->hdc;
698 font_name = request.family;
699 }
700
701 bool stockFont = false;
702
703 HFONT hfont = 0;
704
705 if (fp->rawMode) { // will choose a stock font
706 int f, deffnt;
707 // ### why different?
708 if ((QSysInfo::WindowsVersion & QSysInfo::WV_NT_based) || QSysInfo::WindowsVersion == QSysInfo::WV_32s)
709 deffnt = SYSTEM_FONT;
710 else
711 deffnt = DEFAULT_GUI_FONT;
712 QString fam = desc->family->name.toLower();
713 if (fam == QLatin1String("default"))
714 f = deffnt;
715 else if (fam == QLatin1String("system"))
716 f = SYSTEM_FONT;
717#ifndef Q_OS_WINCE
718 else if (fam == QLatin1String("system_fixed"))
719 f = SYSTEM_FIXED_FONT;
720 else if (fam == QLatin1String("ansi_fixed"))
721 f = ANSI_FIXED_FONT;
722 else if (fam == QLatin1String("ansi_var"))
723 f = ANSI_VAR_FONT;
724 else if (fam == QLatin1String("device_default"))
725 f = DEVICE_DEFAULT_FONT;
726 else if (fam == QLatin1String("oem_fixed"))
727 f = OEM_FIXED_FONT;
728#endif
729 else if (fam[0] == QLatin1Char('#'))
730 f = fam.right(fam.length()-1).toInt();
731 else
732 f = deffnt;
733 hfont = (HFONT)GetStockObject(f);
734 if (!hfont) {
735 qErrnoWarning("QFontEngine::loadEngine: GetStockObject failed");
736 hfont = systemFont();
737 }
738 stockFont = true;
739 } else {
740
741 int hint = FF_DONTCARE;
742 switch (request.styleHint) {
743 case QFont::Helvetica:
744 hint = FF_SWISS;
745 break;
746 case QFont::Times:
747 hint = FF_ROMAN;
748 break;
749 case QFont::Courier:
750 hint = FF_MODERN;
751 break;
752 case QFont::OldEnglish:
753 hint = FF_DECORATIVE;
754 break;
755 case QFont::System:
756 hint = FF_MODERN;
757 break;
758 default:
759 break;
760 }
761
762 lf.lfHeight = -request.pixelSize;
763 lf.lfWidth = 0;
764 lf.lfEscapement = 0;
765 lf.lfOrientation = 0;
766 if (desc->style->key.weight == 50)
767 lf.lfWeight = FW_DONTCARE;
768 else
769 lf.lfWeight = (desc->style->key.weight*900)/99;
770 lf.lfItalic = (desc->style->key.style != QFont::StyleNormal);
771 lf.lfCharSet = DEFAULT_CHARSET;
772
773 int strat = OUT_DEFAULT_PRECIS;
774 if (request.styleStrategy & QFont::PreferBitmap) {
775 strat = OUT_RASTER_PRECIS;
776#ifndef Q_OS_WINCE
777 } else if (request.styleStrategy & QFont::PreferDevice) {
778 strat = OUT_DEVICE_PRECIS;
779 } else if (request.styleStrategy & QFont::PreferOutline) {
780 QT_WA({
781 strat = OUT_OUTLINE_PRECIS;
782 } , {
783 strat = OUT_TT_PRECIS;
784 });
785 } else if (request.styleStrategy & QFont::ForceOutline) {
786 strat = OUT_TT_ONLY_PRECIS;
787#endif
788 }
789
790 lf.lfOutPrecision = strat;
791
792 int qual = DEFAULT_QUALITY;
793
794 if (request.styleStrategy & QFont::PreferMatch)
795 qual = DRAFT_QUALITY;
796#ifndef Q_OS_WINCE
797 else if (request.styleStrategy & QFont::PreferQuality)
798 qual = PROOF_QUALITY;
799#endif
800
801 if (request.styleStrategy & QFont::PreferAntialias) {
802 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP)
803 qual = 5; // == CLEARTYPE_QUALITY;
804 else
805 qual = ANTIALIASED_QUALITY;
806 } else if (request.styleStrategy & QFont::NoAntialias) {
807 qual = NONANTIALIASED_QUALITY;
808 }
809
810 lf.lfQuality = qual;
811
812 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
813 lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
814
815 QString fam = font_name;
816
817 if(fam.isEmpty())
818 fam = QLatin1String("MS Sans Serif");
819
820 if ((fam == QLatin1String("MS Sans Serif"))
821 && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
822 fam = QLatin1String("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
823 }
824 if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
825 fam = QLatin1String("Courier New");
826
827 QT_WA({
828 memcpy(lf.lfFaceName, fam.utf16(), sizeof(TCHAR)*qMin(fam.length()+1,32)); // 32 = Windows hard-coded
829 hfont = CreateFontIndirect(&lf);
830 } , {
831 // LOGFONTA and LOGFONTW are binary compatible
832 QByteArray lname = fam.toLocal8Bit();
833 memcpy(lf.lfFaceName,lname.data(),
834 qMin(lname.length()+1,32)); // 32 = Windows hard-coded
835 hfont = CreateFontIndirectA((LOGFONTA*)&lf);
836 });
837 if (!hfont)
838 qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect failed");
839
840 stockFont = (hfont == 0);
841 bool ttf = false;
842 int avWidth = 0;
843 BOOL res;
844 HGDIOBJ oldObj = SelectObject(hdc, hfont);
845 QT_WA({
846 TEXTMETRICW tm;
847 res = GetTextMetricsW(hdc, &tm);
848 avWidth = tm.tmAveCharWidth;
849 ttf = tm.tmPitchAndFamily & TMPF_TRUETYPE;
850 } , {
851 TEXTMETRICA tm;
852 res = GetTextMetricsA(hdc, &tm);
853 avWidth = tm.tmAveCharWidth;
854 ttf = tm.tmPitchAndFamily & TMPF_TRUETYPE;
855 });
856 SelectObject(hdc, oldObj);
857
858 if (hfont && (!ttf || request.stretch != 100)) {
859 DeleteObject(hfont);
860 if (!res)
861 qErrnoWarning("QFontEngine::loadEngine: GetTextMetrics failed");
862 lf.lfWidth = avWidth * request.stretch/100;
863 QT_WA({
864 hfont = CreateFontIndirect(&lf);
865 } , {
866 hfont = CreateFontIndirectA((LOGFONTA*)&lf);
867 });
868 if (!hfont)
869 qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect with stretch failed");
870 }
871
872#ifndef Q_OS_WINCE
873 if (hfont == 0) {
874 hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
875 stockFont = true;
876 }
877#else
878 if (hfont == 0) {
879 hfont = (HFONT)GetStockObject(SYSTEM_FONT);
880 stockFont = true;
881 }
882#endif
883
884 }
885 QFontEngineWin *few = new QFontEngineWin(font_name, hfont, stockFont, lf);
886
887 // Also check for OpenType tables when using complex scripts
888 // ### TODO: This only works for scripts that require OpenType. More generally
889 // for scripts that do not require OpenType we should just look at the list of
890 // supported writing systems in the font's OS/2 table.
891 if (scriptRequiresOpenType(script)) {
892 HB_Face hbFace = few->harfbuzzFace();
893 if (!hbFace || !hbFace->supported_scripts[script]) {
894 FM_DEBUG(" OpenType support missing for script\n");
895 delete few;
896 return 0;
897 }
898 }
899
900 QFontEngine *fe = few;
901 initFontInfo(few, request, fp);
902 if(script == QUnicodeTables::Common
903 && !(request.styleStrategy & QFont::NoFontMerging)
904 && !(desc->family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
905 if(!tryFonts) {
906 LANGID lid = GetUserDefaultLangID();
907 switch( lid&0xff ) {
908 case LANG_CHINESE: // Chinese (Taiwan)
909 if ( lid == 0x0804 ) // Taiwan
910 tryFonts = ch_TW_tryFonts;
911 else
912 tryFonts = ch_CN_tryFonts;
913 break;
914 case LANG_JAPANESE:
915 tryFonts = jp_tryFonts;
916 break;
917 case LANG_KOREAN:
918 tryFonts = kr_tryFonts;
919 break;
920 default:
921 tryFonts = other_tryFonts;
922 break;
923 }
924 }
925 QStringList fm = QFontDatabase().families();
926 QStringList list = family_list;
927 const char **tf = tryFonts;
928 while(tf && *tf) {
929 if(fm.contains(QLatin1String(*tf)))
930 list << QLatin1String(*tf);
931 ++tf;
932 }
933 QFontEngine *mfe = new QFontEngineMultiWin(few, list);
934 mfe->fontDef = fe->fontDef;
935 fe = mfe;
936 }
937 return fe;
938}
939
940const char *styleHint(const QFontDef &request)
941{
942 const char *stylehint = 0;
943 switch (request.styleHint) {
944 case QFont::SansSerif:
945 stylehint = "Arial";
946 break;
947 case QFont::Serif:
948 stylehint = "Times New Roman";
949 break;
950 case QFont::TypeWriter:
951 stylehint = "Courier New";
952 break;
953 default:
954 if (request.fixedPitch)
955 stylehint = "Courier New";
956 break;
957 }
958 return stylehint;
959}
960
961static QFontEngine *loadWin(const QFontPrivate *d, int script, const QFontDef &req)
962{
963 // list of families to try
964 QStringList family_list = familyList(req);
965
966 if(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based && req.family.toLower() == QLatin1String("ms sans serif")) {
967 // small hack for Dos based machines to get the right font for non
968 // latin text when using the default font.
969 family_list << QLatin1String("Arial");
970 }
971
972 const char *stylehint = styleHint(d->request);
973 if (stylehint)
974 family_list << QLatin1String(stylehint);
975
976 // append the default fallback font for the specified script
977 // family_list << ... ; ###########
978
979 // add the default family
980 QString defaultFamily = QApplication::font().family();
981 if (! family_list.contains(defaultFamily))
982 family_list << defaultFamily;
983
984 // add QFont::defaultFamily() to the list, for compatibility with
985 // previous versions
986 family_list << QApplication::font().defaultFamily();
987
988 // null family means find the first font matching the specified script
989 family_list << QString();
990
991 QtFontDesc desc;
992 QFontEngine *fe = 0;
993 QList<int> blacklistedFamilies;
994
995 while (!fe) {
996 for (int i = 0; i < family_list.size(); ++i) {
997 QString family, foundry;
998 parseFontName(family_list.at(i), foundry, family);
999 FM_DEBUG("loadWin: >>>>>>>>>>>>>>trying to match '%s'", family.toLatin1().data());
1000 QT_PREPEND_NAMESPACE(match)(script, req, family, foundry, -1, &desc, blacklistedFamilies);
1001 if (desc.family)
1002 break;
1003 }
1004 if (!desc.family)
1005 break;
1006 fe = loadEngine(script, d, req, &desc, family_list);
1007 if (!fe)
1008 blacklistedFamilies.append(desc.familyIndex);
1009 }
1010 return fe;
1011}
1012
1013
1014void QFontDatabase::load(const QFontPrivate *d, int script)
1015{
1016 // sanity checks
1017 if (!qApp)
1018 qWarning("QFontDatabase::load: Must construct QApplication first");
1019 Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
1020
1021 // normalize the request to get better caching
1022 QFontDef req = d->request;
1023 if (req.pixelSize <= 0)
1024 req.pixelSize = qMax(1, qRound(req.pointSize * d->dpi / 72.));
1025 req.pointSize = 0;
1026 if (req.weight == 0)
1027 req.weight = QFont::Normal;
1028 if (req.stretch == 0)
1029 req.stretch = 100;
1030
1031 QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
1032 if (!d->engineData)
1033 getEngineData(d, key);
1034
1035 // the cached engineData could have already loaded the engine we want
1036 if (d->engineData->engines[script])
1037 return;
1038
1039 QFontEngine *fe = QFontCache::instance()->findEngine(key);
1040
1041 // set it to the actual pointsize, so QFontInfo will do the right thing
1042 req.pointSize = req.pixelSize*72./d->dpi;
1043
1044 if (!fe) {
1045 if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
1046 fe = new QTestFontEngine(req.pixelSize);
1047 fe->fontDef = req;
1048 } else {
1049 QMutexLocker locker(fontDatabaseMutex());
1050 if (!privateDb()->count)
1051 initializeDb();
1052 fe = loadWin(d, script, req);
1053 }
1054 if (!fe) {
1055 fe = new QFontEngineBox(req.pixelSize);
1056 fe->fontDef = QFontDef();
1057 }
1058 }
1059 d->engineData->engines[script] = fe;
1060 fe->ref.ref();
1061 QFontCache::instance()->insertEngine(key, fe);
1062}
1063
1064#if !defined(FR_PRIVATE)
1065#define FR_PRIVATE 0x10
1066#endif
1067
1068typedef int (WINAPI *PtrAddFontResourceExW)(LPCWSTR, DWORD, PVOID);
1069typedef HANDLE (WINAPI *PtrAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
1070typedef BOOL (WINAPI *PtrRemoveFontResourceExW)(LPCWSTR, DWORD, PVOID);
1071typedef BOOL (WINAPI *PtrRemoveFontMemResourceEx)(HANDLE);
1072
1073static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
1074{
1075 QList<quint32> offsets;
1076 const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
1077 if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
1078 if (headerTag != MAKE_TAG(0, 1, 0, 0)
1079 && headerTag != MAKE_TAG('O', 'T', 'T', 'O')
1080 && headerTag != MAKE_TAG('t', 'r', 'u', 'e')
1081 && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
1082 return offsets;
1083 offsets << 0;
1084 return offsets;
1085 }
1086 const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
1087 for (uint i = 0; i < numFonts; ++i) {
1088 offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
1089 }
1090 return offsets;
1091}
1092
1093static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
1094{
1095 const quint16 numTables = qFromBigEndian<quint16>(data + 4);
1096 for (uint i = 0; i < numTables; ++i) {
1097 const quint32 offset = 12 + 16 * i;
1098 if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
1099 *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
1100 *length = qFromBigEndian<quint32>(data + offset + 12);
1101 return;
1102 }
1103 }
1104 *table = 0;
1105 *length = 0;
1106 return;
1107}
1108
1109static void getFamiliesAndSignatures(const QByteArray &fontData, QFontDatabasePrivate::ApplicationFont *appFont)
1110{
1111 const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
1112
1113 QList<quint32> offsets = getTrueTypeFontOffsets(data);
1114 if (offsets.isEmpty())
1115 return;
1116
1117 for (int i = 0; i < offsets.count(); ++i) {
1118 const uchar *font = data + offsets.at(i);
1119 const uchar *table;
1120 quint32 length;
1121 getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
1122 if (!table)
1123 continue;
1124 QString name = getEnglishName(table, length);
1125 if (name.isEmpty())
1126 continue;
1127
1128 appFont->families << name;
1129 FONTSIGNATURE signature;
1130 getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
1131 if (table && length >= 86) {
1132 // See also qfontdatabase_mac.cpp, offsets taken from OS/2 table in the TrueType spec
1133 signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42);
1134 signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46);
1135 signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50);
1136 signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54);
1137
1138 signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78);
1139 signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82);
1140 }
1141 appFont->signatures << signature;
1142 }
1143}
1144
1145static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
1146{
1147 if(!fnt->data.isEmpty()) {
1148#ifndef Q_OS_WINCE
1149 PtrAddFontMemResourceEx ptrAddFontMemResourceEx = (PtrAddFontMemResourceEx)QLibrary::resolve(QLatin1String("gdi32"),
1150 "AddFontMemResourceEx");
1151 if (!ptrAddFontMemResourceEx)
1152 return;
1153#endif
1154 getFamiliesAndSignatures(fnt->data, fnt);
1155 if (fnt->families.isEmpty())
1156 return;
1157
1158#ifdef Q_OS_WINCE
1159 HANDLE handle = 0;
1160
1161 {
1162#ifdef QT_NO_TEMPORARYFILE
1163 TCHAR lpBuffer[MAX_PATH];
1164 GetTempPath(MAX_PATH, lpBuffer);
1165 QString s = QString::fromUtf16((const ushort *) lpBuffer);
1166 QFile tempfile(s + QLatin1String("/font") + QString::number(GetTickCount()) + QLatin1String(".ttf"));
1167 if (!tempfile.open(QIODevice::ReadWrite))
1168#else
1169 QTemporaryFile tempfile(QLatin1String("XXXXXXXX.ttf"));
1170 if (!tempfile.open())
1171#endif
1172 return;
1173 if (tempfile.write(fnt->data) == -1)
1174 return;
1175
1176#ifndef QT_NO_TEMPORARYFILE
1177 tempfile.setAutoRemove(false);
1178#endif
1179 fnt->fileName = QFileInfo(tempfile.fileName()).absoluteFilePath();
1180 }
1181
1182 if (AddFontResource((LPCWSTR)fnt->fileName.utf16()) == 0) {
1183 QFile(fnt->fileName).remove();
1184 return;
1185 }
1186#else
1187 DWORD dummy = 0;
1188 HANDLE handle = ptrAddFontMemResourceEx((void *)fnt->data.constData(),
1189 fnt->data.size(),
1190 0,
1191 &dummy);
1192 if (handle == 0)
1193 return;
1194#endif
1195
1196 fnt->handle = handle;
1197 fnt->data = QByteArray();
1198 fnt->memoryFont = true;
1199 } else {
1200 QFile f(fnt->fileName);
1201 if (!f.open(QIODevice::ReadOnly))
1202 return;
1203 QByteArray data = f.readAll();
1204 f.close();
1205 getFamiliesAndSignatures(data, fnt);
1206
1207#ifdef Q_OS_WINCE
1208 QFileInfo fileinfo(fnt->fileName);
1209 fnt->fileName = fileinfo.absoluteFilePath();
1210 if (AddFontResource((LPCWSTR)fnt->fileName.utf16()) == 0)
1211 return;
1212#else
1213 // supported from 2000 on, so no need to deal with the *A variant
1214 PtrAddFontResourceExW ptrAddFontResourceExW = (PtrAddFontResourceExW)QLibrary::resolve(QLatin1String("gdi32"),
1215 "AddFontResourceExW");
1216 if (!ptrAddFontResourceExW)
1217 return;
1218
1219 if (ptrAddFontResourceExW((LPCWSTR)fnt->fileName.utf16(), FR_PRIVATE, 0) == 0)
1220 return;
1221#endif
1222
1223 fnt->memoryFont = false;
1224 }
1225}
1226
1227bool QFontDatabase::removeApplicationFont(int handle)
1228{
1229 QMutexLocker locker(fontDatabaseMutex());
1230
1231 QFontDatabasePrivate *db = privateDb();
1232 if (handle < 0 || handle >= db->applicationFonts.count())
1233 return false;
1234
1235 const QFontDatabasePrivate::ApplicationFont font = db->applicationFonts.at(handle);
1236 db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
1237 if (font.memoryFont) {
1238#ifdef Q_OS_WINCE
1239 bool removeSucceeded = RemoveFontResource((LPCWSTR)font.fileName.utf16());
1240 QFile tempfile(font.fileName);
1241 tempfile.remove();
1242 if (!removeSucceeded)
1243 return false;
1244#else
1245 PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx = (PtrRemoveFontMemResourceEx)QLibrary::resolve(QLatin1String("gdi32"),
1246 "RemoveFontMemResourceEx");
1247 if (!ptrRemoveFontMemResourceEx)
1248 return false;
1249
1250 if (!ptrRemoveFontMemResourceEx(font.handle))
1251 return false;
1252#endif
1253 } else {
1254#ifdef Q_OS_WINCE
1255 if (!RemoveFontResource((LPCWSTR)font.fileName.utf16()))
1256 return false;
1257#else
1258 PtrRemoveFontResourceExW ptrRemoveFontResourceExW = (PtrRemoveFontResourceExW)QLibrary::resolve(QLatin1String("gdi32"),
1259 "RemoveFontResourceExW");
1260 if (!ptrRemoveFontResourceExW)
1261 return false;
1262
1263 if (!ptrRemoveFontResourceExW((LPCWSTR)font.fileName.utf16(), FR_PRIVATE, 0))
1264 return false;
1265#endif
1266 }
1267
1268 db->invalidate();
1269 return true;
1270}
1271
1272bool QFontDatabase::removeAllApplicationFonts()
1273{
1274 QMutexLocker locker(fontDatabaseMutex());
1275
1276 QFontDatabasePrivate *db = privateDb();
1277 for (int i = 0; i < db->applicationFonts.count(); ++i)
1278 if (!removeApplicationFont(i))
1279 return false;
1280 return true;
1281}
1282
1283bool QFontDatabase::supportsThreadedFontRendering()
1284{
1285 return true;
1286}
1287
1288QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.