source: trunk/src/gui/text/qfontdatabase.cpp@ 605

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

trunk: Merged in qt 4.6.1 sources.

File size: 80.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <qdir.h>
43#include "qfontdatabase.h"
44#include "qdebug.h"
45#include "qalgorithms.h"
46#include "qapplication.h"
47#include "qvarlengtharray.h" // here or earlier - workaround for VC++6
48#include "qthread.h"
49#include "qmutex.h"
50#include "private/qunicodetables_p.h"
51#include "qfontengine_p.h"
52
53#ifdef Q_WS_X11
54#include <locale.h>
55#endif
56
57#include <stdlib.h>
58#include <limits.h>
59
60#if (defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
61# include <ft2build.h>
62# include FT_TRUETYPE_TABLES_H
63#endif
64
65// #define QFONTDATABASE_DEBUG
66#ifdef QFONTDATABASE_DEBUG
67# define FD_DEBUG qDebug
68#else
69# define FD_DEBUG if (false) qDebug
70#endif
71
72// #define FONT_MATCH_DEBUG
73#ifdef FONT_MATCH_DEBUG
74# define FM_DEBUG qDebug
75#else
76# define FM_DEBUG if (false) qDebug
77#endif
78
79#if defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
80# define for if(0){}else for
81#endif
82
83#define SMOOTH_SCALABLE 0xffff
84
85QT_BEGIN_NAMESPACE
86
87#define SMOOTH_SCALABLE 0xffff
88
89extern int qt_defaultDpiY(); // in qfont.cpp
90
91bool qt_enable_test_font = false;
92
93Q_AUTOTEST_EXPORT void qt_setQtEnableTestFont(bool value)
94{
95 qt_enable_test_font = value;
96}
97
98static int getFontWeight(const QString &weightString)
99{
100 QString s = weightString.toLower();
101
102 // Test in decreasing order of commonness
103 if (s == QLatin1String("medium") ||
104 s == QLatin1String("normal")
105 || s.compare(QApplication::translate("QFontDatabase", "Normal"), Qt::CaseInsensitive) == 0)
106 return QFont::Normal;
107 if (s == QLatin1String("bold")
108 || s.compare(QApplication::translate("QFontDatabase", "Bold"), Qt::CaseInsensitive) == 0)
109 return QFont::Bold;
110 if (s == QLatin1String("demibold") || s == QLatin1String("demi bold")
111 || s.compare(QApplication::translate("QFontDatabase", "Demi Bold"), Qt::CaseInsensitive) == 0)
112 return QFont::DemiBold;
113 if (s == QLatin1String("black")
114 || s.compare(QApplication::translate("QFontDatabase", "Black"), Qt::CaseInsensitive) == 0)
115 return QFont::Black;
116 if (s == QLatin1String("light"))
117 return QFont::Light;
118
119 if (s.contains(QLatin1String("bold"))
120 || s.contains(QApplication::translate("QFontDatabase", "Bold"), Qt::CaseInsensitive)) {
121 if (s.contains(QLatin1String("demi"))
122 || s.compare(QApplication::translate("QFontDatabase", "Demi"), Qt::CaseInsensitive) == 0)
123 return (int) QFont::DemiBold;
124 return (int) QFont::Bold;
125 }
126
127 if (s.contains(QLatin1String("light"))
128 || s.compare(QApplication::translate("QFontDatabase", "Light"), Qt::CaseInsensitive) == 0)
129 return (int) QFont::Light;
130
131 if (s.contains(QLatin1String("black"))
132 || s.compare(QApplication::translate("QFontDatabase", "Black"), Qt::CaseInsensitive) == 0)
133 return (int) QFont::Black;
134
135 return (int) QFont::Normal;
136}
137
138struct QtFontEncoding
139{
140 signed int encoding : 16;
141
142 uint xpoint : 16;
143 uint xres : 8;
144 uint yres : 8;
145 uint avgwidth : 16;
146 uchar pitch : 8;
147};
148
149struct QtFontSize
150{
151 unsigned short pixelSize;
152
153#ifdef Q_WS_X11
154 int count;
155 QtFontEncoding *encodings;
156 QtFontEncoding *encodingID(int id, uint xpoint = 0, uint xres = 0,
157 uint yres = 0, uint avgwidth = 0, bool add = false);
158#endif // Q_WS_X11
159#ifdef Q_WS_PM
160 QList<QFontDatabase::WritingSystem> systems;
161#endif
162#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_PM)
163 QByteArray fileName;
164 int fileIndex;
165#endif // defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
166};
167
168
169#ifdef Q_WS_X11
170QtFontEncoding *QtFontSize::encodingID(int id, uint xpoint, uint xres,
171 uint yres, uint avgwidth, bool add)
172{
173 // we don't match using the xpoint, xres and yres parameters, only the id
174 for (int i = 0; i < count; ++i) {
175 if (encodings[i].encoding == id)
176 return encodings + i;
177 }
178
179 if (!add) return 0;
180
181 if (!(count % 4)) {
182 QtFontEncoding *newEncodings = (QtFontEncoding *)
183 realloc(encodings,
184 (((count+4) >> 2) << 2) * sizeof(QtFontEncoding));
185 Q_CHECK_PTR(newEncodings);
186 encodings = newEncodings;
187 }
188 encodings[count].encoding = id;
189 encodings[count].xpoint = xpoint;
190 encodings[count].xres = xres;
191 encodings[count].yres = yres;
192 encodings[count].avgwidth = avgwidth;
193 encodings[count].pitch = '*';
194 return encodings + count++;
195}
196#endif // Q_WS_X11
197
198struct QtFontStyle
199{
200 struct Key {
201 Key(const QString &styleString);
202 Key() : style(QFont::StyleNormal),
203 weight(QFont::Normal), stretch(0) { }
204 Key(const Key &o) : style(o.style),
205 weight(o.weight), stretch(o.stretch) { }
206 uint style : 2;
207 signed int weight : 8;
208 signed int stretch : 12;
209
210 bool operator==(const Key & other) {
211 return (style == other.style &&
212 weight == other.weight &&
213 (stretch == 0 || other.stretch == 0 || stretch == other.stretch));
214 }
215 bool operator!=(const Key &other) {
216 return !operator==(other);
217 }
218 bool operator <(const Key &o) {
219 int x = (style << 12) + (weight << 14) + stretch;
220 int y = (o.style << 12) + (o.weight << 14) + o.stretch;
221 return (x < y);
222 }
223 };
224
225 QtFontStyle(const Key &k)
226 : key(k), bitmapScalable(false), smoothScalable(false),
227 count(0), pixelSizes(0)
228 {
229#if defined(Q_WS_X11)
230 weightName = setwidthName = 0;
231#endif // Q_WS_X11
232 }
233
234 ~QtFontStyle() {
235#ifdef Q_WS_X11
236 delete [] weightName;
237 delete [] setwidthName;
238#endif
239#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
240 while (count) {
241 // bitfield count-- in while condition does not work correctly in mwccsym2
242 count--;
243#ifdef Q_WS_X11
244 free(pixelSizes[count].encodings);
245#endif
246#ifdef Q_WS_PM
247 pixelSizes[count].systems.~QList<QFontDatabase::WritingSystem>();
248#endif
249#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_PM)
250 pixelSizes[count].fileName.~QByteArray();
251#endif
252 }
253#endif
254 free(pixelSizes);
255 }
256
257 Key key;
258 bool bitmapScalable : 1;
259 bool smoothScalable : 1;
260 signed int count : 30;
261 QtFontSize *pixelSizes;
262
263#ifdef Q_WS_X11
264 const char *weightName;
265 const char *setwidthName;
266#endif // Q_WS_X11
267#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_PM)
268 bool antialiased;
269#endif
270
271 QtFontSize *pixelSize(unsigned short size, bool = false);
272};
273
274QtFontStyle::Key::Key(const QString &styleString)
275 : style(QFont::StyleNormal), weight(QFont::Normal), stretch(0)
276{
277 weight = getFontWeight(styleString);
278
279 if (styleString.contains(QLatin1String("Italic"))
280 || styleString.contains(QApplication::translate("QFontDatabase", "Italic")))
281 style = QFont::StyleItalic;
282 else if (styleString.contains(QLatin1String("Oblique"))
283 || styleString.contains(QApplication::translate("QFontDatabase", "Oblique")))
284 style = QFont::StyleOblique;
285}
286
287QtFontSize *QtFontStyle::pixelSize(unsigned short size, bool add)
288{
289 for (int i = 0; i < count; i++) {
290 if (pixelSizes[i].pixelSize == size)
291 return pixelSizes + i;
292 }
293 if (!add)
294 return 0;
295
296 if (!(count % 8)) {
297 QtFontSize *newPixelSizes = (QtFontSize *)
298 realloc(pixelSizes,
299 (((count+8) >> 3) << 3) * sizeof(QtFontSize));
300 Q_CHECK_PTR(newPixelSizes);
301 pixelSizes = newPixelSizes;
302 }
303 pixelSizes[count].pixelSize = size;
304#ifdef Q_WS_X11
305 pixelSizes[count].count = 0;
306 pixelSizes[count].encodings = 0;
307#endif
308#ifdef Q_WS_PM
309 new (&pixelSizes[count].systems) QList<QFontDatabase::WritingSystem>;
310#endif
311#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_PM)
312 new (&pixelSizes[count].fileName) QByteArray;
313 pixelSizes[count].fileIndex = 0;
314#endif
315 return pixelSizes + (count++);
316}
317
318struct QtFontFoundry
319{
320 QtFontFoundry(const QString &n) : name(n), count(0), styles(0) {}
321 ~QtFontFoundry() {
322 while (count--)
323 delete styles[count];
324 free(styles);
325 }
326
327 QString name;
328
329 int count;
330 QtFontStyle **styles;
331 QtFontStyle *style(const QtFontStyle::Key &, bool = false);
332};
333
334QtFontStyle *QtFontFoundry::style(const QtFontStyle::Key &key, bool create)
335{
336 int pos = 0;
337 if (count) {
338 int low = 0;
339 int high = count;
340 pos = count / 2;
341 while (high > low) {
342 if (styles[pos]->key == key)
343 return styles[pos];
344 if (styles[pos]->key < key)
345 low = pos + 1;
346 else
347 high = pos;
348 pos = (high + low) / 2;
349 }
350 pos = low;
351 }
352 if (!create)
353 return 0;
354
355// qDebug("adding key (weight=%d, style=%d, oblique=%d stretch=%d) at %d", key.weight, key.style, key.oblique, key.stretch, pos);
356 if (!(count % 8)) {
357 QtFontStyle **newStyles = (QtFontStyle **)
358 realloc(styles, (((count+8) >> 3) << 3) * sizeof(QtFontStyle *));
359 Q_CHECK_PTR(newStyles);
360 styles = newStyles;
361 }
362
363 QtFontStyle *style = new QtFontStyle(key);
364 memmove(styles + pos + 1, styles + pos, (count-pos)*sizeof(QtFontStyle *));
365 styles[pos] = style;
366 count++;
367 return styles[pos];
368}
369
370
371struct QtFontFamily
372{
373 enum WritingSystemStatus {
374 Unknown = 0,
375 Supported = 1,
376 UnsupportedFT = 2,
377 UnsupportedXLFD = 4,
378 Unsupported = UnsupportedFT | UnsupportedXLFD
379 };
380
381 QtFontFamily(const QString &n)
382 :
383#ifdef Q_WS_X11
384 fixedPitch(true), ftWritingSystemCheck(false),
385 xlfdLoaded(false), synthetic(false), symbol_checked(false),
386#else
387 fixedPitch(false),
388#endif
389#ifdef Q_WS_WIN
390 writingSystemCheck(false),
391 loaded(false),
392#endif
393#if !defined(QWS) && defined(Q_OS_MAC)
394 fixedPitchComputed(false),
395#endif
396 name(n), count(0), foundries(0)
397#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
398 , bogusWritingSystems(false)
399#endif
400 {
401 memset(writingSystems, 0, sizeof(writingSystems));
402 }
403 ~QtFontFamily() {
404 while (count--)
405 delete foundries[count];
406 free(foundries);
407 }
408
409 bool fixedPitch : 1;
410#ifdef Q_WS_X11
411 bool ftWritingSystemCheck : 1;
412 bool xlfdLoaded : 1;
413 bool synthetic : 1;
414#endif
415#ifdef Q_WS_WIN
416 bool writingSystemCheck : 1;
417 bool loaded : 1;
418#endif
419#if !defined(QWS) && defined(Q_OS_MAC)
420 bool fixedPitchComputed : 1;
421#endif
422#ifdef Q_WS_X11
423 bool symbol_checked;
424#endif
425
426 QString name;
427#if defined(Q_WS_X11) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
428 QByteArray fontFilename;
429 int fontFileIndex;
430#endif
431#ifdef Q_WS_WIN
432 QString english_name;
433#endif
434 int count;
435 QtFontFoundry **foundries;
436
437#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
438 bool bogusWritingSystems;
439 QStringList fallbackFamilies;
440#endif
441 unsigned char writingSystems[QFontDatabase::WritingSystemsCount];
442
443 QtFontFoundry *foundry(const QString &f, bool = false);
444};
445
446#if !defined(QWS) && defined(Q_OS_MAC)
447inline static void qt_mac_get_fixed_pitch(QtFontFamily *f)
448{
449 if(f && !f->fixedPitchComputed) {
450 QFontMetrics fm(f->name);
451 f->fixedPitch = fm.width(QLatin1Char('i')) == fm.width(QLatin1Char('m'));
452 f->fixedPitchComputed = true;
453 }
454}
455#endif
456
457
458QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create)
459{
460 if (f.isNull() && count == 1)
461 return foundries[0];
462
463 for (int i = 0; i < count; i++) {
464 if (foundries[i]->name.compare(f, Qt::CaseInsensitive) == 0)
465 return foundries[i];
466 }
467 if (!create)
468 return 0;
469
470 if (!(count % 8)) {
471 QtFontFoundry **newFoundries = (QtFontFoundry **)
472 realloc(foundries,
473 (((count+8) >> 3) << 3) * sizeof(QtFontFoundry *));
474 Q_CHECK_PTR(newFoundries);
475 foundries = newFoundries;
476 }
477
478 foundries[count] = new QtFontFoundry(f);
479 return foundries[count++];
480}
481
482// ### copied to tools/makeqpf/qpf2.cpp
483
484#if ((defined(Q_WS_QWS) || defined(Q_WS_PM)) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || (defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA))
485// see the Unicode subset bitfields in the MSDN docs
486static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
487 // Any,
488 { 127, 127 },
489 // Latin,
490 { 0, 127 },
491 // Greek,
492 { 7, 127 },
493 // Cyrillic,
494 { 9, 127 },
495 // Armenian,
496 { 10, 127 },
497 // Hebrew,
498 { 11, 127 },
499 // Arabic,
500 { 13, 127 },
501 // Syriac,
502 { 71, 127 },
503 //Thaana,
504 { 72, 127 },
505 //Devanagari,
506 { 15, 127 },
507 //Bengali,
508 { 16, 127 },
509 //Gurmukhi,
510 { 17, 127 },
511 //Gujarati,
512 { 18, 127 },
513 //Oriya,
514 { 19, 127 },
515 //Tamil,
516 { 20, 127 },
517 //Telugu,
518 { 21, 127 },
519 //Kannada,
520 { 22, 127 },
521 //Malayalam,
522 { 23, 127 },
523 //Sinhala,
524 { 73, 127 },
525 //Thai,
526 { 24, 127 },
527 //Lao,
528 { 25, 127 },
529 //Tibetan,
530 { 70, 127 },
531 //Myanmar,
532 { 74, 127 },
533 // Georgian,
534 { 26, 127 },
535 // Khmer,
536 { 80, 127 },
537 // SimplifiedChinese,
538 { 126, 127 },
539 // TraditionalChinese,
540 { 126, 127 },
541 // Japanese,
542 { 126, 127 },
543 // Korean,
544 { 56, 127 },
545 // Vietnamese,
546 { 0, 127 }, // same as latin1
547 // Other,
548 { 126, 127 },
549 // Ogham,
550 { 78, 127 },
551 // Runic,
552 { 79, 127 },
553 // Nko,
554 { 14, 127 },
555};
556
557#define SimplifiedChineseCsbBit 18
558#define TraditionalChineseCsbBit 20
559#define JapaneseCsbBit 17
560#define KoreanCsbBit 21
561
562static QList<QFontDatabase::WritingSystem> determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2])
563{
564 QList<QFontDatabase::WritingSystem> writingSystems;
565 bool hasScript = false;
566
567 int i;
568 for(i = 0; i < QFontDatabase::WritingSystemsCount; i++) {
569 int bit = requiredUnicodeBits[i][0];
570 int index = bit/32;
571 int flag = 1 << (bit&31);
572 if (bit != 126 && unicodeRange[index] & flag) {
573 bit = requiredUnicodeBits[i][1];
574 index = bit/32;
575
576 flag = 1 << (bit&31);
577 if (bit == 127 || unicodeRange[index] & flag) {
578 writingSystems.append(QFontDatabase::WritingSystem(i));
579 hasScript = true;
580 // qDebug("font %s: index=%d, flag=%8x supports script %d", familyName.latin1(), index, flag, i);
581 }
582 }
583 }
584 if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) {
585 writingSystems.append(QFontDatabase::SimplifiedChinese);
586 hasScript = true;
587 //qDebug("font %s supports Simplified Chinese", familyName.latin1());
588 }
589 if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
590 writingSystems.append(QFontDatabase::TraditionalChinese);
591 hasScript = true;
592 //qDebug("font %s supports Traditional Chinese", familyName.latin1());
593 }
594 if(codePageRange[0] & (1 << JapaneseCsbBit)) {
595 writingSystems.append(QFontDatabase::Japanese);
596 hasScript = true;
597 //qDebug("font %s supports Japanese", familyName.latin1());
598 }
599 if(codePageRange[0] & (1 << KoreanCsbBit)) {
600 writingSystems.append(QFontDatabase::Korean);
601 hasScript = true;
602 //qDebug("font %s supports Korean", familyName.latin1());
603 }
604 if (!hasScript)
605 writingSystems.append(QFontDatabase::Symbol);
606
607 return writingSystems;
608}
609#endif
610
611#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
612// class with virtual destructor, derived in qfontdatabase_s60.cpp
613class QFontDatabaseS60Store
614{
615public:
616 virtual ~QFontDatabaseS60Store() {}
617};
618#endif
619
620class QFontDatabasePrivate
621{
622public:
623 QFontDatabasePrivate()
624 : count(0), families(0), reregisterAppFonts(false)
625#if defined(Q_WS_QWS)
626 , stream(0)
627#endif
628#if defined(Q_WS_PM)
629 , valid(false)
630#endif
631#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
632 , s60Store(0)
633#endif
634 { }
635 ~QFontDatabasePrivate() {
636 free();
637 }
638 QtFontFamily *family(const QString &f, bool = false);
639 void free() {
640 while (count--)
641 delete families[count];
642 ::free(families);
643 families = 0;
644 count = 0;
645#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
646 if (s60Store) {
647 delete s60Store;
648 s60Store = 0;
649 }
650#endif
651 // don't clear the memory fonts!
652 }
653
654 int count;
655 QtFontFamily **families;
656
657 struct ApplicationFont {
658 QString fileName;
659 QByteArray data;
660#if defined(Q_OS_WIN)
661 HANDLE handle;
662 bool memoryFont;
663 QVector<FONTSIGNATURE> signatures;
664#elif defined(Q_WS_MAC)
665 ATSFontContainerRef handle;
666#endif
667 QStringList families;
668 };
669 QVector<ApplicationFont> applicationFonts;
670 int addAppFont(const QByteArray &fontData, const QString &fileName);
671 bool reregisterAppFonts;
672 bool isApplicationFont(const QString &fileName);
673
674 void invalidate();
675
676#if defined(Q_WS_QWS)
677 bool loadFromCache(const QString &fontPath);
678 void addQPF2File(const QByteArray &file);
679#endif // Q_WS_QWS
680#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
681 void addFont(const QString &familyname, const char *foundryname, int weight,
682 bool italic, int pixelSize, const QByteArray &file, int fileIndex,
683 bool antialiased,
684 const QList<QFontDatabase::WritingSystem> &writingSystems = QList<QFontDatabase::WritingSystem>());
685#ifndef QT_NO_FREETYPE
686 QStringList addTTFile(const QByteArray &file, const QByteArray &fontData = QByteArray());
687#endif // QT_NO_FREETYPE
688#endif
689#if defined(Q_WS_QWS)
690 QDataStream *stream;
691 QStringList fallbackFamilies;
692#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
693 const QFontDatabaseS60Store *s60Store;
694#endif
695
696#if defined(Q_WS_PM)
697 bool valid;
698#endif
699};
700
701void QFontDatabasePrivate::invalidate()
702{
703 QFontCache::instance()->clear();
704 free();
705#if defined(Q_WS_PM)
706 valid = false;
707#endif
708 emit static_cast<QApplication *>(QApplication::instance())->fontDatabaseChanged();
709}
710
711QtFontFamily *QFontDatabasePrivate::family(const QString &f, bool create)
712{
713 int low = 0;
714 int high = count;
715 int pos = count / 2;
716 int res = 1;
717 if (count) {
718 while ((res = families[pos]->name.compare(f, Qt::CaseInsensitive)) && pos != low) {
719 if (res > 0)
720 high = pos;
721 else
722 low = pos;
723 pos = (high + low) / 2;
724 }
725 if (!res)
726 return families[pos];
727 }
728 if (!create)
729 return 0;
730
731 if (res < 0)
732 pos++;
733
734 // qDebug("adding family %s at %d total=%d", f.latin1(), pos, count);
735 if (!(count % 8)) {
736 QtFontFamily **newFamilies = (QtFontFamily **)
737 realloc(families,
738 (((count+8) >> 3) << 3) * sizeof(QtFontFamily *));
739 Q_CHECK_PTR(newFamilies);
740 families = newFamilies;
741 }
742
743 QtFontFamily *family = new QtFontFamily(f);
744 memmove(families + pos + 1, families + pos, (count-pos)*sizeof(QtFontFamily *));
745 families[pos] = family;
746 count++;
747 return families[pos];
748}
749
750#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
751void QFontDatabasePrivate::addFont(const QString &familyname, const char *foundryname, int weight, bool italic, int pixelSize,
752 const QByteArray &file, int fileIndex, bool antialiased,
753 const QList<QFontDatabase::WritingSystem> &writingSystems)
754{
755// qDebug() << "Adding font" << familyname << weight << italic << pixelSize << file << fileIndex << antialiased;
756 QtFontStyle::Key styleKey;
757 styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
758 styleKey.weight = weight;
759 styleKey.stretch = 100;
760 QtFontFamily *f = family(familyname, true);
761
762 if (writingSystems.isEmpty()) {
763 for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
764 f->writingSystems[ws] = QtFontFamily::Supported;
765 }
766 f->bogusWritingSystems = true;
767 } else {
768 for (int i = 0; i < writingSystems.count(); ++i) {
769 f->writingSystems[writingSystems.at(i)] = QtFontFamily::Supported;
770 }
771 }
772
773 QtFontFoundry *foundry = f->foundry(QString::fromLatin1(foundryname), true);
774 QtFontStyle *style = foundry->style(styleKey, true);
775 style->smoothScalable = (pixelSize == 0);
776 style->antialiased = antialiased;
777 QtFontSize *size = style->pixelSize(pixelSize?pixelSize:SMOOTH_SCALABLE, true);
778 size->fileName = file;
779 size->fileIndex = fileIndex;
780
781#if defined(Q_WS_QWS)
782 if (stream) {
783 *stream << familyname << foundry->name << weight << quint8(italic) << pixelSize
784 << file << fileIndex << quint8(antialiased);
785 *stream << quint8(writingSystems.count());
786 for (int i = 0; i < writingSystems.count(); ++i)
787 *stream << quint8(writingSystems.at(i));
788 }
789#else // ..in case of defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
790 f->fontFilename = file;
791 f->fontFileIndex = fileIndex;
792#endif
793}
794#endif
795
796#if (defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
797QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteArray &fontData)
798{
799 QStringList families;
800 extern FT_Library qt_getFreetype();
801 FT_Library library = qt_getFreetype();
802
803 int index = 0;
804 int numFaces = 0;
805 do {
806 FT_Face face;
807 FT_Error error;
808 if (!fontData.isEmpty()) {
809 error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face);
810 } else {
811 error = FT_New_Face(library, file, index, &face);
812 }
813 if (error != FT_Err_Ok) {
814 qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error;
815 break;
816 }
817 numFaces = face->num_faces;
818
819 int weight = QFont::Normal;
820 bool italic = face->style_flags & FT_STYLE_FLAG_ITALIC;
821
822 if (face->style_flags & FT_STYLE_FLAG_BOLD)
823 weight = QFont::Bold;
824
825 QList<QFontDatabase::WritingSystem> writingSystems;
826 // detect symbol fonts
827 for (int i = 0; i < face->num_charmaps; ++i) {
828 FT_CharMap cm = face->charmaps[i];
829 if (cm->encoding == ft_encoding_adobe_custom
830 || cm->encoding == ft_encoding_symbol) {
831 writingSystems.append(QFontDatabase::Symbol);
832 break;
833 }
834 }
835 if (writingSystems.isEmpty()) {
836 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
837 if (os2) {
838 quint32 unicodeRange[4] = {
839 os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4
840 };
841 quint32 codePageRange[2] = {
842 os2->ulCodePageRange1, os2->ulCodePageRange2
843 };
844
845 writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
846 //for (int i = 0; i < writingSystems.count(); ++i)
847 // qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i));
848 }
849 }
850
851 QString family = QString::fromAscii(face->family_name);
852 families.append(family);
853 addFont(family, /*foundry*/ "", weight, italic,
854 /*pixelsize*/ 0, file, index, /*antialias*/ true, writingSystems);
855
856 FT_Done_Face(face);
857 ++index;
858 } while (index < numFaces);
859 return families;
860}
861#endif
862
863static const int scriptForWritingSystem[] = {
864 QUnicodeTables::Common, // Any
865 QUnicodeTables::Latin, // Latin
866 QUnicodeTables::Greek, // Greek
867 QUnicodeTables::Cyrillic, // Cyrillic
868 QUnicodeTables::Armenian, // Armenian
869 QUnicodeTables::Hebrew, // Hebrew
870 QUnicodeTables::Arabic, // Arabic
871 QUnicodeTables::Syriac, // Syriac
872 QUnicodeTables::Thaana, // Thaana
873 QUnicodeTables::Devanagari, // Devanagari
874 QUnicodeTables::Bengali, // Bengali
875 QUnicodeTables::Gurmukhi, // Gurmukhi
876 QUnicodeTables::Gujarati, // Gujarati
877 QUnicodeTables::Oriya, // Oriya
878 QUnicodeTables::Tamil, // Tamil
879 QUnicodeTables::Telugu, // Telugu
880 QUnicodeTables::Kannada, // Kannada
881 QUnicodeTables::Malayalam, // Malayalam
882 QUnicodeTables::Sinhala, // Sinhala
883 QUnicodeTables::Thai, // Thai
884 QUnicodeTables::Lao, // Lao
885 QUnicodeTables::Tibetan, // Tibetan
886 QUnicodeTables::Myanmar, // Myanmar
887 QUnicodeTables::Georgian, // Georgian
888 QUnicodeTables::Khmer, // Khmer
889 QUnicodeTables::Common, // SimplifiedChinese
890 QUnicodeTables::Common, // TraditionalChinese
891 QUnicodeTables::Common, // Japanese
892 QUnicodeTables::Hangul, // Korean
893 QUnicodeTables::Common, // Vietnamese
894 QUnicodeTables::Common, // Yi
895 QUnicodeTables::Common, // Tagalog
896 QUnicodeTables::Common, // Hanunoo
897 QUnicodeTables::Common, // Buhid
898 QUnicodeTables::Common, // Tagbanwa
899 QUnicodeTables::Common, // Limbu
900 QUnicodeTables::Common, // TaiLe
901 QUnicodeTables::Common, // Braille
902 QUnicodeTables::Common, // Symbol
903 QUnicodeTables::Ogham, // Ogham
904 QUnicodeTables::Runic, // Runic
905 QUnicodeTables::Nko // Nko
906};
907
908
909#if defined Q_WS_QWS || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)) || defined(Q_WS_WIN)
910static inline bool requiresOpenType(int writingSystem)
911{
912 return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala)
913 || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko);
914}
915static inline bool scriptRequiresOpenType(int script)
916{
917 return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
918 || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
919}
920#endif
921
922
923/*!
924 \internal
925
926 This makes sense of the font family name:
927
928 if the family name contains a '[' and a ']', then we take the text
929 between the square brackets as the foundry, and the text before the
930 square brackets as the family (ie. "Arial [Monotype]")
931*/
932static void parseFontName(const QString &name, QString &foundry, QString &family)
933{
934 int i = name.indexOf(QLatin1Char('['));
935 int li = name.lastIndexOf(QLatin1Char(']'));
936 if (i >= 0 && li >= 0 && i < li) {
937 foundry = name.mid(i + 1, li - i - 1);
938 if (i > 0 && name[i - 1] == QLatin1Char(' '))
939 i--;
940 family = name.left(i);
941 } else {
942 foundry.clear();
943 family = name;
944 }
945
946 // capitalize the family/foundry names
947 bool space = true;
948 QChar *s = family.data();
949 int len = family.length();
950 while(len--) {
951 if (space) *s = s->toUpper();
952 space = s->isSpace();
953 ++s;
954 }
955
956 space = true;
957 s = foundry.data();
958 len = foundry.length();
959 while(len--) {
960 if (space) *s = s->toUpper();
961 space = s->isSpace();
962 ++s;
963 }
964}
965
966
967struct QtFontDesc
968{
969 inline QtFontDesc() : family(0), foundry(0), style(0), size(0), encoding(0), familyIndex(-1) {}
970 QtFontFamily *family;
971 QtFontFoundry *foundry;
972 QtFontStyle *style;
973 QtFontSize *size;
974 QtFontEncoding *encoding;
975 int familyIndex;
976};
977
978#if !defined(Q_WS_MAC)
979static void match(int script, const QFontDef &request,
980 const QString &family_name, const QString &foundry_name, int force_encoding_id,
981 QtFontDesc *desc, const QList<int> &blacklistedFamilies = QList<int>(), bool forceXLFD=false);
982
983#if defined(Q_WS_X11) || defined(Q_WS_QWS)
984static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef)
985{
986 fontDef->family = desc.family->name;
987 if (! desc.foundry->name.isEmpty() && desc.family->count > 1) {
988 fontDef->family += QString::fromLatin1(" [");
989 fontDef->family += desc.foundry->name;
990 fontDef->family += QLatin1Char(']');
991 }
992
993 if (desc.style->smoothScalable)
994 fontDef->pixelSize = request.pixelSize;
995 else if ((desc.style->bitmapScalable && (request.styleStrategy & QFont::PreferMatch)))
996 fontDef->pixelSize = request.pixelSize;
997 else
998 fontDef->pixelSize = desc.size->pixelSize;
999
1000 fontDef->styleHint = request.styleHint;
1001 fontDef->styleStrategy = request.styleStrategy;
1002
1003 fontDef->weight = desc.style->key.weight;
1004 fontDef->style = desc.style->key.style;
1005 fontDef->fixedPitch = desc.family->fixedPitch;
1006 fontDef->stretch = desc.style->key.stretch;
1007 fontDef->ignorePitch = false;
1008}
1009#endif
1010#endif
1011
1012#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || defined(Q_WS_PM)
1013static void getEngineData(const QFontPrivate *d, const QFontCache::Key &key)
1014{
1015 // look for the requested font in the engine data cache
1016 d->engineData = QFontCache::instance()->findEngineData(key);
1017 if (!d->engineData) {
1018 // create a new one
1019 d->engineData = new QFontEngineData;
1020 QFontCache::instance()->insertEngineData(key, d->engineData);
1021 } else {
1022 d->engineData->ref.ref();
1023 }
1024}
1025#endif
1026
1027static QStringList familyList(const QFontDef &req)
1028{
1029 // list of families to try
1030 QStringList family_list;
1031 if (req.family.isEmpty())
1032 return family_list;
1033
1034 QStringList list = req.family.split(QLatin1Char(','));
1035 for (int i = 0; i < list.size(); ++i) {
1036 QString str = list.at(i).trimmed();
1037 if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
1038 || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
1039 str = str.mid(1, str.length() - 2);
1040 family_list << str;
1041 }
1042
1043 // append the substitute list for each family in family_list
1044 QStringList subs_list;
1045 QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
1046 for (; it != end; ++it)
1047 subs_list += QFont::substitutes(*it);
1048// qDebug() << "adding substs: " << subs_list;
1049
1050 family_list += subs_list;
1051
1052 return family_list;
1053}
1054
1055Q_GLOBAL_STATIC(QFontDatabasePrivate, privateDb)
1056Q_GLOBAL_STATIC_WITH_ARGS(QMutex, fontDatabaseMutex, (QMutex::Recursive))
1057
1058// used in qfontengine_x11.cpp
1059QMutex *qt_fontdatabase_mutex()
1060{
1061 return fontDatabaseMutex();
1062}
1063
1064QT_BEGIN_INCLUDE_NAMESPACE
1065#if defined(Q_WS_X11)
1066# include "qfontdatabase_x11.cpp"
1067#elif defined(Q_WS_MAC)
1068# include "qfontdatabase_mac.cpp"
1069#elif defined(Q_WS_WIN)
1070# include "qfontdatabase_win.cpp"
1071#elif defined(Q_WS_PM)
1072# include "qfontdatabase_pm.cpp"
1073#elif defined(Q_WS_QWS)
1074# include "qfontdatabase_qws.cpp"
1075#elif defined(Q_OS_SYMBIAN)
1076# include "qfontdatabase_s60.cpp"
1077#endif
1078QT_END_INCLUDE_NAMESPACE
1079
1080static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey)
1081{
1082 int best = 0;
1083 int dist = 0xffff;
1084
1085 for ( int i = 0; i < foundry->count; i++ ) {
1086 QtFontStyle *style = foundry->styles[i];
1087
1088 int d = qAbs( styleKey.weight - style->key.weight );
1089
1090 if ( styleKey.stretch != 0 && style->key.stretch != 0 ) {
1091 d += qAbs( styleKey.stretch - style->key.stretch );
1092 }
1093
1094 if (styleKey.style != style->key.style) {
1095 if (styleKey.style != QFont::StyleNormal && style->key.style != QFont::StyleNormal)
1096 // one is italic, the other oblique
1097 d += 0x0001;
1098 else
1099 d += 0x1000;
1100 }
1101
1102 if ( d < dist ) {
1103 best = i;
1104 dist = d;
1105 }
1106 }
1107
1108 FM_DEBUG( " best style has distance 0x%x", dist );
1109 return foundry->styles[best];
1110}
1111
1112#if defined(Q_WS_X11)
1113static QtFontEncoding *findEncoding(int script, int styleStrategy,
1114 QtFontSize *size, int force_encoding_id)
1115{
1116 QtFontEncoding *encoding = 0;
1117
1118 if (force_encoding_id >= 0) {
1119 encoding = size->encodingID(force_encoding_id);
1120 if (!encoding)
1121 FM_DEBUG(" required encoding_id not available");
1122 return encoding;
1123 }
1124
1125 if (styleStrategy & (QFont::OpenGLCompatible | QFont::PreferBitmap)) {
1126 FM_DEBUG(" PreferBitmap and/or OpenGL set, skipping Freetype");
1127 } else {
1128 encoding = size->encodingID(-1); // -1 == prefer Freetype
1129 if (encoding)
1130 return encoding;
1131 }
1132
1133 // FT not available, find an XLFD font, trying the default encoding first
1134 encoding = size->encodingID(QFontPrivate::defaultEncodingID);
1135 if (encoding) {
1136 // does it support the requested script?
1137 bool supportsScript = false;
1138 for (int ws = 1; !supportsScript && ws < QFontDatabase::WritingSystemsCount; ++ws) {
1139 if (scriptForWritingSystem[ws] != script)
1140 continue;
1141 supportsScript = writingSystems_for_xlfd_encoding[encoding->encoding][ws];
1142 }
1143 if (!supportsScript)
1144 encoding = 0;
1145 }
1146 // find the first encoding that supports the requested script
1147 for (int ws = 1; !encoding && ws < QFontDatabase::WritingSystemsCount; ++ws) {
1148 if (scriptForWritingSystem[ws] != script)
1149 continue;
1150 for (int x = 0; !encoding && x < size->count; ++x) {
1151 const int enc = size->encodings[x].encoding;
1152 if (writingSystems_for_xlfd_encoding[enc][ws])
1153 encoding = size->encodings + x;
1154 }
1155 }
1156
1157 return encoding;
1158}
1159#endif // Q_WS_X11
1160
1161#if defined(Q_WS_PM)
1162static bool sizeSupportsScript(int script, QtFontSize *size)
1163{
1164 // empty writing system list means we support all
1165 // (see qfontdatabase_pm.cpp for explanation)
1166 if (size->systems.isEmpty())
1167 return true;
1168 foreach (QFontDatabase::WritingSystem ws, size->systems) {
1169 if (scriptForWritingSystem[ws] == script)
1170 return true;
1171 }
1172 return false;
1173}
1174#endif // Q_WS_PM
1175
1176#if !defined(Q_WS_MAC)
1177static
1178unsigned int bestFoundry(int script, unsigned int score, int styleStrategy,
1179 const QtFontFamily *family, const QString &foundry_name,
1180 QtFontStyle::Key styleKey, int pixelSize, char pitch,
1181 QtFontDesc *desc, int force_encoding_id)
1182{
1183 Q_UNUSED(force_encoding_id);
1184 Q_UNUSED(script);
1185 Q_UNUSED(pitch);
1186
1187 desc->foundry = 0;
1188 desc->style = 0;
1189 desc->size = 0;
1190 desc->encoding = 0;
1191
1192
1193 FM_DEBUG(" REMARK: looking for best foundry for family '%s' [%d]", family->name.toLatin1().constData(), family->count);
1194
1195 for (int x = 0; x < family->count; ++x) {
1196 QtFontFoundry *foundry = family->foundries[x];
1197 if (!foundry_name.isEmpty() && foundry->name.compare(foundry_name, Qt::CaseInsensitive) != 0)
1198 continue;
1199
1200 FM_DEBUG(" looking for matching style in foundry '%s' %d",
1201 foundry->name.isEmpty() ? "-- none --" : foundry->name.toLatin1().constData(), foundry->count);
1202
1203 QtFontStyle *style = bestStyle(foundry, styleKey);
1204
1205 if (!style->smoothScalable && (styleStrategy & QFont::ForceOutline)) {
1206 FM_DEBUG(" ForceOutline set, but not smoothly scalable");
1207 continue;
1208 }
1209
1210 int px = -1;
1211 QtFontSize *size = 0;
1212
1213 // 1. see if we have an exact matching size
1214 if (!(styleStrategy & QFont::ForceOutline)) {
1215 size = style->pixelSize(pixelSize);
1216 if (size) {
1217 FM_DEBUG(" found exact size match (%d pixels)", size->pixelSize);
1218 px = size->pixelSize;
1219 }
1220 }
1221
1222 // 2. see if we have a smoothly scalable font
1223 if (!size && style->smoothScalable && ! (styleStrategy & QFont::PreferBitmap)) {
1224 size = style->pixelSize(SMOOTH_SCALABLE);
1225 if (size) {
1226 FM_DEBUG(" found smoothly scalable font (%d pixels)", pixelSize);
1227 px = pixelSize;
1228 }
1229 }
1230
1231 // 3. see if we have a bitmap scalable font
1232 if (!size && style->bitmapScalable && (styleStrategy & QFont::PreferMatch)) {
1233 size = style->pixelSize(0);
1234 if (size) {
1235 FM_DEBUG(" found bitmap scalable font (%d pixels)", pixelSize);
1236 px = pixelSize;
1237 }
1238 }
1239
1240#ifdef Q_WS_X11
1241 QtFontEncoding *encoding = 0;
1242#endif
1243
1244 // 4. find closest size match
1245 if (! size) {
1246 unsigned int distance = ~0u;
1247 for (int x = 0; x < style->count; ++x) {
1248#ifdef Q_WS_X11
1249 encoding =
1250 findEncoding(script, styleStrategy, style->pixelSizes + x, force_encoding_id);
1251 if (!encoding) {
1252 FM_DEBUG(" size %3d does not support the script we want",
1253 style->pixelSizes[x].pixelSize);
1254 continue;
1255 }
1256#endif
1257#ifdef Q_WS_PM
1258 if (!sizeSupportsScript(script, style->pixelSizes + x)) {
1259 FM_DEBUG(" size %3d does not support the script we want",
1260 style->pixelSizes[x].pixelSize);
1261 continue;
1262 }
1263#endif
1264
1265 unsigned int d;
1266 if (style->pixelSizes[x].pixelSize < pixelSize) {
1267 // penalize sizes that are smaller than the
1268 // requested size, due to truncation from floating
1269 // point to integer conversions
1270 d = pixelSize - style->pixelSizes[x].pixelSize + 1;
1271 } else {
1272 d = style->pixelSizes[x].pixelSize - pixelSize;
1273 }
1274
1275 if (d < distance) {
1276 distance = d;
1277 size = style->pixelSizes + x;
1278 FM_DEBUG(" best size so far: %3d (%d)", size->pixelSize, pixelSize);
1279 }
1280 }
1281
1282 if (!size) {
1283 FM_DEBUG(" no size supports the script we want");
1284 continue;
1285 }
1286
1287 if (style->bitmapScalable && ! (styleStrategy & QFont::PreferQuality) &&
1288 (distance * 10 / pixelSize) >= 2) {
1289 // the closest size is not close enough, go ahead and
1290 // use a bitmap scaled font
1291 size = style->pixelSize(0);
1292 px = pixelSize;
1293 } else {
1294 px = size->pixelSize;
1295 }
1296 }
1297
1298#ifdef Q_WS_X11
1299 if (size) {
1300 encoding = findEncoding(script, styleStrategy, size, force_encoding_id);
1301 if (!encoding) size = 0;
1302 }
1303 if (! encoding) {
1304 FM_DEBUG(" foundry doesn't support the script we want");
1305 continue;
1306 }
1307#endif // Q_WS_X11
1308#ifdef Q_WS_PM
1309 if (size) {
1310 if (!sizeSupportsScript(script, size)) {
1311 size = 0;
1312 FM_DEBUG(" foundry doesn't support the script we want");
1313 continue;
1314 }
1315 }
1316#endif
1317
1318 unsigned int this_score = 0x0000;
1319 enum {
1320 PitchMismatch = 0x4000,
1321 StyleMismatch = 0x2000,
1322 BitmapScaledPenalty = 0x1000,
1323 EncodingMismatch = 0x0002,
1324 XLFDPenalty = 0x0001
1325 };
1326#ifdef Q_WS_X11
1327 if (encoding->encoding != -1) {
1328 this_score += XLFDPenalty;
1329 if (encoding->encoding != QFontPrivate::defaultEncodingID)
1330 this_score += EncodingMismatch;
1331 }
1332 if (pitch != '*') {
1333 if (!(pitch == 'm' && encoding->pitch == 'c') && pitch != encoding->pitch)
1334 this_score += PitchMismatch;
1335 }
1336#else
1337 if (pitch != '*') {
1338#if !defined(QWS) && defined(Q_OS_MAC)
1339 qt_mac_get_fixed_pitch(const_cast<QtFontFamily*>(family));
1340#endif
1341 if ((pitch == 'm' && !family->fixedPitch)
1342 || (pitch == 'p' && family->fixedPitch))
1343 this_score += PitchMismatch;
1344 }
1345#endif
1346 if (styleKey != style->key)
1347 this_score += StyleMismatch;
1348 if (!style->smoothScalable && px != size->pixelSize) // bitmap scaled
1349 this_score += BitmapScaledPenalty;
1350 if (px != pixelSize) // close, but not exact, size match
1351 this_score += qAbs(px - pixelSize);
1352
1353 if (this_score < score) {
1354 FM_DEBUG(" found a match: score %x best score so far %x",
1355 this_score, score);
1356
1357 score = this_score;
1358 desc->foundry = foundry;
1359 desc->style = style;
1360 desc->size = size;
1361#ifdef Q_WS_X11
1362 desc->encoding = encoding;
1363#endif // Q_WS_X11
1364 } else {
1365 FM_DEBUG(" score %x no better than best %x", this_score, score);
1366 }
1367 }
1368
1369 return score;
1370}
1371#endif
1372
1373#if !defined(Q_WS_MAC)
1374/*!
1375 \internal
1376
1377 Tries to find the best match for a given request and family/foundry
1378*/
1379static void match(int script, const QFontDef &request,
1380 const QString &family_name, const QString &foundry_name, int force_encoding_id,
1381 QtFontDesc *desc, const QList<int> &blacklistedFamilies, bool forceXLFD)
1382{
1383 Q_UNUSED(force_encoding_id);
1384
1385 QtFontStyle::Key styleKey;
1386 styleKey.style = request.style;
1387 styleKey.weight = request.weight;
1388 styleKey.stretch = request.stretch;
1389 char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
1390
1391 FM_DEBUG("QFontDatabase::match\n"
1392 " request:\n"
1393 " family: %s [%s], script: %d\n"
1394 " weight: %d, style: %d\n"
1395 " stretch: %d\n"
1396 " pixelSize: %g\n"
1397 " pitch: %c",
1398 family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
1399 foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
1400 script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
1401#if defined(FONT_MATCH_DEBUG) && defined(Q_WS_X11)
1402 if (force_encoding_id >= 0) {
1403 FM_DEBUG(" required encoding: %d", force_encoding_id);
1404 }
1405#endif
1406
1407 desc->family = 0;
1408 desc->foundry = 0;
1409 desc->style = 0;
1410 desc->size = 0;
1411 desc->encoding = 0;
1412 desc->familyIndex = -1;
1413
1414 unsigned int score = ~0u;
1415
1416#ifdef Q_WS_X11
1417 load(family_name, script, forceXLFD);
1418#else
1419 Q_UNUSED(forceXLFD);
1420 load(family_name, script);
1421#endif
1422
1423 QFontDatabasePrivate *db = privateDb();
1424 for (int x = 0; x < db->count; ++x) {
1425 if (blacklistedFamilies.contains(x))
1426 continue;
1427 QtFontDesc test;
1428 test.family = db->families[x];
1429 test.familyIndex = x;
1430
1431 if (!family_name.isEmpty()
1432 && test.family->name.compare(family_name, Qt::CaseInsensitive) != 0
1433#ifdef Q_WS_WIN
1434 && test.family->english_name.compare(family_name, Qt::CaseInsensitive) != 0
1435#endif
1436 )
1437 continue;
1438
1439 if (family_name.isEmpty())
1440 load(test.family->name, script);
1441
1442 uint score_adjust = 0;
1443
1444 bool supported = (script == QUnicodeTables::Common);
1445 for (int ws = 1; !supported && ws < QFontDatabase::WritingSystemsCount; ++ws) {
1446 if (scriptForWritingSystem[ws] != script)
1447 continue;
1448 if (test.family->writingSystems[ws] & QtFontFamily::Supported)
1449 supported = true;
1450 }
1451 if (!supported) {
1452 // family not supported in the script we want
1453 continue;
1454 }
1455
1456 // as we know the script is supported, we can be sure
1457 // to find a matching font here.
1458 unsigned int newscore =
1459 bestFoundry(script, score, request.styleStrategy,
1460 test.family, foundry_name, styleKey, request.pixelSize, pitch,
1461 &test, force_encoding_id);
1462 if (test.foundry == 0) {
1463 // the specific foundry was not found, so look for
1464 // any foundry matching our requirements
1465 newscore = bestFoundry(script, score, request.styleStrategy, test.family,
1466 QString(), styleKey, request.pixelSize,
1467 pitch, &test, force_encoding_id);
1468 }
1469 newscore += score_adjust;
1470
1471 if (newscore < score) {
1472 score = newscore;
1473 *desc = test;
1474 }
1475 if (newscore < 10) // xlfd instead of FT... just accept it
1476 break;
1477 }
1478}
1479#endif
1480
1481static QString styleStringHelper(int weight, QFont::Style style)
1482{
1483 QString result;
1484 if (weight >= QFont::Black)
1485 result = QApplication::translate("QFontDatabase", "Black");
1486 else if (weight >= QFont::Bold)
1487 result = QApplication::translate("QFontDatabase", "Bold");
1488 else if (weight >= QFont::DemiBold)
1489 result = QApplication::translate("QFontDatabase", "Demi Bold");
1490 else if (weight < QFont::Normal)
1491 result = QApplication::translate("QFontDatabase", "Light");
1492
1493 if (style == QFont::StyleItalic)
1494 result += QLatin1Char(' ') + QApplication::translate("QFontDatabase", "Italic");
1495 else if (style == QFont::StyleOblique)
1496 result += QLatin1Char(' ') + QApplication::translate("QFontDatabase", "Oblique");
1497
1498 if (result.isEmpty())
1499 result = QApplication::translate("QFontDatabase", "Normal");
1500
1501 return result.simplified();
1502}
1503
1504/*!
1505 Returns a string that describes the style of the \a font. For
1506 example, "Bold Italic", "Bold", "Italic" or "Normal". An empty
1507 string may be returned.
1508*/
1509QString QFontDatabase::styleString(const QFont &font)
1510{
1511 return styleStringHelper(font.weight(), font.style());
1512}
1513
1514/*!
1515 Returns a string that describes the style of the \a fontInfo. For
1516 example, "Bold Italic", "Bold", "Italic" or "Normal". An empty
1517 string may be returned.
1518*/
1519QString QFontDatabase::styleString(const QFontInfo &fontInfo)
1520{
1521 return styleStringHelper(fontInfo.weight(), fontInfo.style());
1522}
1523
1524
1525/*!
1526 \class QFontDatabase
1527 \threadsafe
1528
1529 \brief The QFontDatabase class provides information about the fonts available in the underlying window system.
1530
1531 \ingroup appearance
1532
1533 The most common uses of this class are to query the database for
1534 the list of font families() and for the pointSizes() and styles()
1535 that are available for each family. An alternative to pointSizes()
1536 is smoothSizes() which returns the sizes at which a given family
1537 and style will look attractive.
1538
1539 If the font family is available from two or more foundries the
1540 foundry name is included in the family name; for example:
1541 "Helvetica [Adobe]" and "Helvetica [Cronyx]". When you specify a
1542 family, you can either use the old hyphenated "foundry-family"
1543 format or the bracketed "family [foundry]" format; for example:
1544 "Cronyx-Helvetica" or "Helvetica [Cronyx]". If the family has a
1545 foundry it is always returned using the bracketed format, as is
1546 the case with the value returned by families().
1547
1548 The font() function returns a QFont given a family, style and
1549 point size.
1550
1551 A family and style combination can be checked to see if it is
1552 italic() or bold(), and to retrieve its weight(). Similarly we can
1553 call isBitmapScalable(), isSmoothlyScalable(), isScalable() and
1554 isFixedPitch().
1555
1556 Use the styleString() to obtain a text version of a style.
1557
1558 The QFontDatabase class also supports some static functions, for
1559 example, standardSizes(). You can retrieve the description of a
1560 writing system using writingSystemName(), and a sample of
1561 characters in a writing system with writingSystemSample().
1562
1563 Example:
1564
1565 \snippet doc/src/snippets/qfontdatabase/main.cpp 0
1566 \snippet doc/src/snippets/qfontdatabase/main.cpp 1
1567
1568 This example gets the list of font families, the list of
1569 styles for each family, and the point sizes that are available for
1570 each combination of family and style, displaying this information
1571 in a tree view.
1572
1573 \sa QFont, QFontInfo, QFontMetrics, QFontComboBox, {Character Map Example}
1574*/
1575
1576/*!
1577 Creates a font database object.
1578*/
1579QFontDatabase::QFontDatabase()
1580{
1581 QMutexLocker locker(fontDatabaseMutex());
1582 createDatabase();
1583 d = privateDb();
1584}
1585
1586/*!
1587 \enum QFontDatabase::WritingSystem
1588
1589 \value Any
1590 \value Latin
1591 \value Greek
1592 \value Cyrillic
1593 \value Armenian
1594 \value Hebrew
1595 \value Arabic
1596 \value Syriac
1597 \value Thaana
1598 \value Devanagari
1599 \value Bengali
1600 \value Gurmukhi
1601 \value Gujarati
1602 \value Oriya
1603 \value Tamil
1604 \value Telugu
1605 \value Kannada
1606 \value Malayalam
1607 \value Sinhala
1608 \value Thai
1609 \value Lao
1610 \value Tibetan
1611 \value Myanmar
1612 \value Georgian
1613 \value Khmer
1614 \value SimplifiedChinese
1615 \value TraditionalChinese
1616 \value Japanese
1617 \value Korean
1618 \value Vietnamese
1619 \value Symbol
1620 \value Other (the same as Symbol)
1621 \value Ogham
1622 \value Runic
1623 \value Nko
1624
1625 \omitvalue WritingSystemsCount
1626*/
1627
1628/*!
1629 Returns a sorted list of the available writing systems. This is
1630 list generated from information about all installed fonts on the
1631 system.
1632
1633 \sa families()
1634*/
1635QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems() const
1636{
1637 QMutexLocker locker(fontDatabaseMutex());
1638
1639 QT_PREPEND_NAMESPACE(load)();
1640#ifdef Q_WS_X11
1641 checkSymbolFonts();
1642#endif
1643
1644 QList<WritingSystem> list;
1645 for (int i = 0; i < d->count; ++i) {
1646 QtFontFamily *family = d->families[i];
1647 if (family->count == 0)
1648 continue;
1649 for (int x = Latin; x < WritingSystemsCount; ++x) {
1650 const WritingSystem writingSystem = WritingSystem(x);
1651 if (!(family->writingSystems[writingSystem] & QtFontFamily::Supported))
1652 continue;
1653 if (!list.contains(writingSystem))
1654 list.append(writingSystem);
1655 }
1656 }
1657 qSort(list);
1658 return list;
1659}
1660
1661
1662/*!
1663 Returns a sorted list of the writing systems supported by a given
1664 font \a family.
1665
1666 \sa families()
1667*/
1668QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems(const QString &family) const
1669{
1670 QString familyName, foundryName;
1671 parseFontName(family, foundryName, familyName);
1672
1673 QMutexLocker locker(fontDatabaseMutex());
1674
1675 QT_PREPEND_NAMESPACE(load)();
1676#ifdef Q_WS_X11
1677 checkSymbolFonts(familyName);
1678#endif
1679
1680 QList<WritingSystem> list;
1681 QtFontFamily *f = d->family(familyName);
1682 if (!f || f->count == 0)
1683 return list;
1684
1685 for (int x = Latin; x < WritingSystemsCount; ++x) {
1686 const WritingSystem writingSystem = WritingSystem(x);
1687 if (f->writingSystems[writingSystem] & QtFontFamily::Supported)
1688 list.append(writingSystem);
1689 }
1690 return list;
1691}
1692
1693
1694/*!
1695 Returns a sorted list of the available font families which support
1696 the \a writingSystem.
1697
1698 If a family exists in several foundries, the returned name for
1699 that font is in the form "family [foundry]". Examples: "Times
1700 [Adobe]", "Times [Cronyx]", "Palatino".
1701
1702 \sa writingSystems()
1703*/
1704QStringList QFontDatabase::families(WritingSystem writingSystem) const
1705{
1706 QMutexLocker locker(fontDatabaseMutex());
1707
1708 QT_PREPEND_NAMESPACE(load)();
1709#ifdef Q_WS_X11
1710 if (writingSystem != Any)
1711 checkSymbolFonts();
1712#endif
1713
1714 QStringList flist;
1715 for (int i = 0; i < d->count; i++) {
1716 QtFontFamily *f = d->families[i];
1717 if (f->count == 0)
1718 continue;
1719 if (writingSystem != Any && (f->writingSystems[writingSystem] != QtFontFamily::Supported))
1720 continue;
1721 if (f->count == 1) {
1722 flist.append(f->name);
1723 } else {
1724 for (int j = 0; j < f->count; j++) {
1725 QString str = f->name;
1726 QString foundry = f->foundries[j]->name;
1727 if (!foundry.isEmpty()) {
1728 str += QLatin1String(" [");
1729 str += foundry;
1730 str += QLatin1Char(']');
1731 }
1732 flist.append(str);
1733 }
1734 }
1735 }
1736 return flist;
1737}
1738
1739/*!
1740 Returns a list of the styles available for the font family \a
1741 family. Some example styles: "Light", "Light Italic", "Bold",
1742 "Oblique", "Demi". The list may be empty.
1743
1744 \sa families()
1745*/
1746QStringList QFontDatabase::styles(const QString &family) const
1747{
1748 QString familyName, foundryName;
1749 parseFontName(family, foundryName, familyName);
1750
1751 QMutexLocker locker(fontDatabaseMutex());
1752
1753 QT_PREPEND_NAMESPACE(load)(familyName);
1754
1755 QStringList l;
1756 QtFontFamily *f = d->family(familyName);
1757 if (!f)
1758 return l;
1759
1760 QtFontFoundry allStyles(foundryName);
1761 for (int j = 0; j < f->count; j++) {
1762 QtFontFoundry *foundry = f->foundries[j];
1763 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1764 for (int k = 0; k < foundry->count; k++) {
1765 QtFontStyle::Key ke(foundry->styles[k]->key);
1766 ke.stretch = 0;
1767 allStyles.style(ke, true);
1768 }
1769 }
1770 }
1771
1772 for (int i = 0; i < allStyles.count; i++)
1773 l.append(styleStringHelper(allStyles.styles[i]->key.weight, (QFont::Style)allStyles.styles[i]->key.style));
1774 return l;
1775}
1776
1777/*!
1778 Returns true if the font that has family \a family and style \a
1779 style is fixed pitch; otherwise returns false.
1780*/
1781
1782bool QFontDatabase::isFixedPitch(const QString &family,
1783 const QString &style) const
1784{
1785 Q_UNUSED(style);
1786
1787 QString familyName, foundryName;
1788 parseFontName(family, foundryName, familyName);
1789
1790 QMutexLocker locker(fontDatabaseMutex());
1791
1792 QT_PREPEND_NAMESPACE(load)(familyName);
1793
1794 QtFontFamily *f = d->family(familyName);
1795#if !defined(QWS) && defined(Q_OS_MAC)
1796 qt_mac_get_fixed_pitch(f);
1797#endif
1798 return (f && f->fixedPitch);
1799}
1800
1801/*!
1802 Returns true if the font that has family \a family and style \a
1803 style is a scalable bitmap font; otherwise returns false. Scaling
1804 a bitmap font usually produces an unattractive hardly readable
1805 result, because the pixels of the font are scaled. If you need to
1806 scale a bitmap font it is better to scale it to one of the fixed
1807 sizes returned by smoothSizes().
1808
1809 \sa isScalable(), isSmoothlyScalable()
1810*/
1811bool QFontDatabase::isBitmapScalable(const QString &family,
1812 const QString &style) const
1813{
1814 bool bitmapScalable = false;
1815 QString familyName, foundryName;
1816 parseFontName(family, foundryName, familyName);
1817
1818 QMutexLocker locker(fontDatabaseMutex());
1819
1820 QT_PREPEND_NAMESPACE(load)(familyName);
1821
1822 QtFontStyle::Key styleKey(style);
1823
1824 QtFontFamily *f = d->family(familyName);
1825 if (!f) return bitmapScalable;
1826
1827 for (int j = 0; j < f->count; j++) {
1828 QtFontFoundry *foundry = f->foundries[j];
1829 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1830 for (int k = 0; k < foundry->count; k++)
1831 if ((style.isEmpty() || foundry->styles[k]->key == styleKey)
1832 && foundry->styles[k]->bitmapScalable && !foundry->styles[k]->smoothScalable) {
1833 bitmapScalable = true;
1834 goto end;
1835 }
1836 }
1837 }
1838 end:
1839 return bitmapScalable;
1840}
1841
1842
1843/*!
1844 Returns true if the font that has family \a family and style \a
1845 style is smoothly scalable; otherwise returns false. If this
1846 function returns true, it's safe to scale this font to any size,
1847 and the result will always look attractive.
1848
1849 \sa isScalable(), isBitmapScalable()
1850*/
1851bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &style) const
1852{
1853 bool smoothScalable = false;
1854 QString familyName, foundryName;
1855 parseFontName(family, foundryName, familyName);
1856
1857 QMutexLocker locker(fontDatabaseMutex());
1858
1859 QT_PREPEND_NAMESPACE(load)(familyName);
1860
1861 QtFontStyle::Key styleKey(style);
1862
1863 QtFontFamily *f = d->family(familyName);
1864 if (!f) return smoothScalable;
1865
1866 for (int j = 0; j < f->count; j++) {
1867 QtFontFoundry *foundry = f->foundries[j];
1868 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1869 for (int k = 0; k < foundry->count; k++)
1870 if ((style.isEmpty() || foundry->styles[k]->key == styleKey) && foundry->styles[k]->smoothScalable) {
1871 smoothScalable = true;
1872 goto end;
1873 }
1874 }
1875 }
1876 end:
1877 return smoothScalable;
1878}
1879
1880/*!
1881 Returns true if the font that has family \a family and style \a
1882 style is scalable; otherwise returns false.
1883
1884 \sa isBitmapScalable(), isSmoothlyScalable()
1885*/
1886bool QFontDatabase::isScalable(const QString &family,
1887 const QString &style) const
1888{
1889 QMutexLocker locker(fontDatabaseMutex());
1890 if (isSmoothlyScalable(family, style))
1891 return true;
1892 return isBitmapScalable(family, style);
1893}
1894
1895
1896/*!
1897 Returns a list of the point sizes available for the font that has
1898 family \a family and style \a style. The list may be empty.
1899
1900 \sa smoothSizes(), standardSizes()
1901*/
1902QList<int> QFontDatabase::pointSizes(const QString &family,
1903 const QString &style)
1904{
1905#if defined(Q_WS_WIN)
1906 // windows and macosx are always smoothly scalable
1907 Q_UNUSED(family);
1908 Q_UNUSED(style);
1909 return standardSizes();
1910#else
1911 bool smoothScalable = false;
1912 QString familyName, foundryName;
1913 parseFontName(family, foundryName, familyName);
1914
1915 QMutexLocker locker(fontDatabaseMutex());
1916
1917 QT_PREPEND_NAMESPACE(load)(familyName);
1918
1919 QtFontStyle::Key styleKey(style);
1920
1921 QList<int> sizes;
1922
1923 QtFontFamily *fam = d->family(familyName);
1924 if (!fam) return sizes;
1925
1926
1927#ifdef Q_WS_X11
1928 int dpi = QX11Info::appDpiY();
1929#else
1930 const int dpi = qt_defaultDpiY(); // embedded
1931#endif
1932
1933 for (int j = 0; j < fam->count; j++) {
1934 QtFontFoundry *foundry = fam->foundries[j];
1935 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1936 QtFontStyle *style = foundry->style(styleKey);
1937 if (!style) continue;
1938
1939 if (style->smoothScalable) {
1940 smoothScalable = true;
1941 goto end;
1942 }
1943 for (int l = 0; l < style->count; l++) {
1944 const QtFontSize *size = style->pixelSizes + l;
1945
1946 if (size->pixelSize != 0 && size->pixelSize != USHRT_MAX) {
1947 const uint pointSize = qRound(size->pixelSize * 72.0 / dpi);
1948 if (! sizes.contains(pointSize))
1949 sizes.append(pointSize);
1950 }
1951 }
1952 }
1953 }
1954 end:
1955 if (smoothScalable)
1956 return standardSizes();
1957
1958 qSort(sizes);
1959 return sizes;
1960#endif
1961}
1962
1963/*!
1964 Returns a QFont object that has family \a family, style \a style
1965 and point size \a pointSize. If no matching font could be created,
1966 a QFont object that uses the application's default font is
1967 returned.
1968*/
1969QFont QFontDatabase::font(const QString &family, const QString &style,
1970 int pointSize) const
1971{
1972 QString familyName, foundryName;
1973 parseFontName(family, foundryName, familyName);
1974
1975 QMutexLocker locker(fontDatabaseMutex());
1976
1977 QT_PREPEND_NAMESPACE(load)(familyName);
1978
1979 QtFontFoundry allStyles(foundryName);
1980 QtFontFamily *f = d->family(familyName);
1981 if (!f) return QApplication::font();
1982
1983 for (int j = 0; j < f->count; j++) {
1984 QtFontFoundry *foundry = f->foundries[j];
1985 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1986 for (int k = 0; k < foundry->count; k++)
1987 allStyles.style(foundry->styles[k]->key, true);
1988 }
1989 }
1990
1991 QtFontStyle::Key styleKey(style);
1992 QtFontStyle *s = bestStyle(&allStyles, styleKey);
1993
1994 if (!s) // no styles found?
1995 return QApplication::font();
1996 QFont fnt(family, pointSize, s->key.weight);
1997 fnt.setStyle((QFont::Style)s->key.style);
1998 return fnt;
1999}
2000
2001
2002/*!
2003 Returns the point sizes of a font that has family \a family and
2004 style \a style that will look attractive. The list may be empty.
2005 For non-scalable fonts and bitmap scalable fonts, this function
2006 is equivalent to pointSizes().
2007
2008 \sa pointSizes(), standardSizes()
2009*/
2010QList<int> QFontDatabase::smoothSizes(const QString &family,
2011 const QString &style)
2012{
2013#ifdef Q_WS_WIN
2014 Q_UNUSED(family);
2015 Q_UNUSED(style);
2016 return QFontDatabase::standardSizes();
2017#else
2018 bool smoothScalable = false;
2019 QString familyName, foundryName;
2020 parseFontName(family, foundryName, familyName);
2021
2022 QMutexLocker locker(fontDatabaseMutex());
2023
2024 QT_PREPEND_NAMESPACE(load)(familyName);
2025
2026 QtFontStyle::Key styleKey(style);
2027
2028 QList<int> sizes;
2029
2030 QtFontFamily *fam = d->family(familyName);
2031 if (!fam)
2032 return sizes;
2033
2034#ifdef Q_WS_X11
2035 int dpi = QX11Info::appDpiY();
2036#else
2037 const int dpi = qt_defaultDpiY(); // embedded
2038#endif
2039
2040 for (int j = 0; j < fam->count; j++) {
2041 QtFontFoundry *foundry = fam->foundries[j];
2042 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
2043 QtFontStyle *style = foundry->style(styleKey);
2044 if (!style) continue;
2045
2046 if (style->smoothScalable) {
2047 smoothScalable = true;
2048 goto end;
2049 }
2050 for (int l = 0; l < style->count; l++) {
2051 const QtFontSize *size = style->pixelSizes + l;
2052
2053 if (size->pixelSize != 0 && size->pixelSize != USHRT_MAX) {
2054 const uint pointSize = qRound(size->pixelSize * 72.0 / dpi);
2055 if (! sizes.contains(pointSize))
2056 sizes.append(pointSize);
2057 }
2058 }
2059 }
2060 }
2061 end:
2062 if (smoothScalable)
2063 return QFontDatabase::standardSizes();
2064
2065 qSort(sizes);
2066 return sizes;
2067#endif
2068}
2069
2070
2071/*!
2072 Returns a list of standard font sizes.
2073
2074 \sa smoothSizes(), pointSizes()
2075*/
2076QList<int> QFontDatabase::standardSizes()
2077{
2078 QList<int> ret;
2079 static const unsigned short standard[] =
2080 { 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72, 0 };
2081 const unsigned short *sizes = standard;
2082 while (*sizes) ret << *sizes++;
2083 return ret;
2084}
2085
2086
2087/*!
2088 Returns true if the font that has family \a family and style \a
2089 style is italic; otherwise returns false.
2090
2091 \sa weight(), bold()
2092*/
2093bool QFontDatabase::italic(const QString &family, const QString &style) const
2094{
2095 QString familyName, foundryName;
2096 parseFontName(family, foundryName, familyName);
2097
2098 QMutexLocker locker(fontDatabaseMutex());
2099
2100 QT_PREPEND_NAMESPACE(load)(familyName);
2101
2102 QtFontFoundry allStyles(foundryName);
2103 QtFontFamily *f = d->family(familyName);
2104 if (!f) return false;
2105
2106 for (int j = 0; j < f->count; j++) {
2107 QtFontFoundry *foundry = f->foundries[j];
2108 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
2109 for (int k = 0; k < foundry->count; k++)
2110 allStyles.style(foundry->styles[k]->key, true);
2111 }
2112 }
2113
2114 QtFontStyle::Key styleKey(style);
2115 QtFontStyle *s = allStyles.style(styleKey);
2116 return s && s->key.style == QFont::StyleItalic;
2117}
2118
2119
2120/*!
2121 Returns true if the font that has family \a family and style \a
2122 style is bold; otherwise returns false.
2123
2124 \sa italic(), weight()
2125*/
2126bool QFontDatabase::bold(const QString &family,
2127 const QString &style) const
2128{
2129 QString familyName, foundryName;
2130 parseFontName(family, foundryName, familyName);
2131
2132 QMutexLocker locker(fontDatabaseMutex());
2133
2134 QT_PREPEND_NAMESPACE(load)(familyName);
2135
2136 QtFontFoundry allStyles(foundryName);
2137 QtFontFamily *f = d->family(familyName);
2138 if (!f) return false;
2139
2140 for (int j = 0; j < f->count; j++) {
2141 QtFontFoundry *foundry = f->foundries[j];
2142 if (foundryName.isEmpty() ||
2143 foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
2144 for (int k = 0; k < foundry->count; k++)
2145 allStyles.style(foundry->styles[k]->key, true);
2146 }
2147 }
2148
2149 QtFontStyle::Key styleKey(style);
2150 QtFontStyle *s = allStyles.style(styleKey);
2151 return s && s->key.weight >= QFont::Bold;
2152}
2153
2154
2155/*!
2156 Returns the weight of the font that has family \a family and style
2157 \a style. If there is no such family and style combination,
2158 returns -1.
2159
2160 \sa italic(), bold()
2161*/
2162int QFontDatabase::weight(const QString &family,
2163 const QString &style) const
2164{
2165 QString familyName, foundryName;
2166 parseFontName(family, foundryName, familyName);
2167
2168 QMutexLocker locker(fontDatabaseMutex());
2169
2170 QT_PREPEND_NAMESPACE(load)(familyName);
2171
2172 QtFontFoundry allStyles(foundryName);
2173 QtFontFamily *f = d->family(familyName);
2174 if (!f) return -1;
2175
2176 for (int j = 0; j < f->count; j++) {
2177 QtFontFoundry *foundry = f->foundries[j];
2178 if (foundryName.isEmpty() ||
2179 foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
2180 for (int k = 0; k < foundry->count; k++)
2181 allStyles.style(foundry->styles[k]->key, true);
2182 }
2183 }
2184
2185 QtFontStyle::Key styleKey(style);
2186 QtFontStyle *s = allStyles.style(styleKey);
2187 return s ? s->key.weight : -1;
2188}
2189
2190
2191/*!
2192 Returns the names the \a writingSystem (e.g. for displaying to the
2193 user in a dialog).
2194*/
2195QString QFontDatabase::writingSystemName(WritingSystem writingSystem)
2196{
2197 const char *name = 0;
2198 switch (writingSystem) {
2199 case Any:
2200 name = QT_TRANSLATE_NOOP("QFontDatabase", "Any");
2201 break;
2202 case Latin:
2203 name = QT_TRANSLATE_NOOP("QFontDatabase", "Latin");
2204 break;
2205 case Greek:
2206 name = QT_TRANSLATE_NOOP("QFontDatabase", "Greek");
2207 break;
2208 case Cyrillic:
2209 name = QT_TRANSLATE_NOOP("QFontDatabase", "Cyrillic");
2210 break;
2211 case Armenian:
2212 name = QT_TRANSLATE_NOOP("QFontDatabase", "Armenian");
2213 break;
2214 case Hebrew:
2215 name = QT_TRANSLATE_NOOP("QFontDatabase", "Hebrew");
2216 break;
2217 case Arabic:
2218 name = QT_TRANSLATE_NOOP("QFontDatabase", "Arabic");
2219 break;
2220 case Syriac:
2221 name = QT_TRANSLATE_NOOP("QFontDatabase", "Syriac");
2222 break;
2223 case Thaana:
2224 name = QT_TRANSLATE_NOOP("QFontDatabase", "Thaana");
2225 break;
2226 case Devanagari:
2227 name = QT_TRANSLATE_NOOP("QFontDatabase", "Devanagari");
2228 break;
2229 case Bengali:
2230 name = QT_TRANSLATE_NOOP("QFontDatabase", "Bengali");
2231 break;
2232 case Gurmukhi:
2233 name = QT_TRANSLATE_NOOP("QFontDatabase", "Gurmukhi");
2234 break;
2235 case Gujarati:
2236 name = QT_TRANSLATE_NOOP("QFontDatabase", "Gujarati");
2237 break;
2238 case Oriya:
2239 name = QT_TRANSLATE_NOOP("QFontDatabase", "Oriya");
2240 break;
2241 case Tamil:
2242 name = QT_TRANSLATE_NOOP("QFontDatabase", "Tamil");
2243 break;
2244 case Telugu:
2245 name = QT_TRANSLATE_NOOP("QFontDatabase", "Telugu");
2246 break;
2247 case Kannada:
2248 name = QT_TRANSLATE_NOOP("QFontDatabase", "Kannada");
2249 break;
2250 case Malayalam:
2251 name = QT_TRANSLATE_NOOP("QFontDatabase", "Malayalam");
2252 break;
2253 case Sinhala:
2254 name = QT_TRANSLATE_NOOP("QFontDatabase", "Sinhala");
2255 break;
2256 case Thai:
2257 name = QT_TRANSLATE_NOOP("QFontDatabase", "Thai");
2258 break;
2259 case Lao:
2260 name = QT_TRANSLATE_NOOP("QFontDatabase", "Lao");
2261 break;
2262 case Tibetan:
2263 name = QT_TRANSLATE_NOOP("QFontDatabase", "Tibetan");
2264 break;
2265 case Myanmar:
2266 name = QT_TRANSLATE_NOOP("QFontDatabase", "Myanmar");
2267 break;
2268 case Georgian:
2269 name = QT_TRANSLATE_NOOP("QFontDatabase", "Georgian");
2270 break;
2271 case Khmer:
2272 name = QT_TRANSLATE_NOOP("QFontDatabase", "Khmer");
2273 break;
2274 case SimplifiedChinese:
2275 name = QT_TRANSLATE_NOOP("QFontDatabase", "Simplified Chinese");
2276 break;
2277 case TraditionalChinese:
2278 name = QT_TRANSLATE_NOOP("QFontDatabase", "Traditional Chinese");
2279 break;
2280 case Japanese:
2281 name = QT_TRANSLATE_NOOP("QFontDatabase", "Japanese");
2282 break;
2283 case Korean:
2284 name = QT_TRANSLATE_NOOP("QFontDatabase", "Korean");
2285 break;
2286 case Vietnamese:
2287 name = QT_TRANSLATE_NOOP("QFontDatabase", "Vietnamese");
2288 break;
2289 case Symbol:
2290 name = QT_TRANSLATE_NOOP("QFontDatabase", "Symbol");
2291 break;
2292 case Ogham:
2293 name = QT_TRANSLATE_NOOP("QFontDatabase", "Ogham");
2294 break;
2295 case Runic:
2296 name = QT_TRANSLATE_NOOP("QFontDatabase", "Runic");
2297 break;
2298 case Nko:
2299 name = QT_TRANSLATE_NOOP("QFontDatabase", "N'Ko");
2300 break;
2301 default:
2302 Q_ASSERT_X(false, "QFontDatabase::writingSystemName", "invalid 'writingSystem' parameter");
2303 break;
2304 }
2305 return QApplication::translate("QFontDatabase", name);
2306}
2307
2308
2309/*!
2310 Returns a string with sample characters from \a writingSystem.
2311*/
2312QString QFontDatabase::writingSystemSample(WritingSystem writingSystem)
2313{
2314 QString sample;
2315 switch (writingSystem) {
2316 case Any:
2317 case Symbol:
2318 // show only ascii characters
2319 sample += QLatin1String("AaBbzZ");
2320 break;
2321 case Latin:
2322 // This is cheating... we only show latin-1 characters so that we don't
2323 // end up loading lots of fonts - at least on X11...
2324 sample = QLatin1String("Aa");
2325 sample += QChar(0x00C3);
2326 sample += QChar(0x00E1);
2327 sample += QLatin1String("Zz");
2328 break;
2329 case Greek:
2330 sample += QChar(0x0393);
2331 sample += QChar(0x03B1);
2332 sample += QChar(0x03A9);
2333 sample += QChar(0x03C9);
2334 break;
2335 case Cyrillic:
2336 sample += QChar(0x0414);
2337 sample += QChar(0x0434);
2338 sample += QChar(0x0436);
2339 sample += QChar(0x044f);
2340 break;
2341 case Armenian:
2342 sample += QChar(0x053f);
2343 sample += QChar(0x054f);
2344 sample += QChar(0x056f);
2345 sample += QChar(0x057f);
2346 break;
2347 case Hebrew:
2348 sample += QChar(0x05D0);
2349 sample += QChar(0x05D1);
2350 sample += QChar(0x05D2);
2351 sample += QChar(0x05D3);
2352 break;
2353 case Arabic:
2354 sample += QChar(0x0628);
2355 sample += QChar(0x0629);
2356 sample += QChar(0x062A);
2357 sample += QChar(0x063A);
2358 break;
2359 case Syriac:
2360 sample += QChar(0x0715);
2361 sample += QChar(0x0725);
2362 sample += QChar(0x0716);
2363 sample += QChar(0x0726);
2364 break;
2365 case Thaana:
2366 sample += QChar(0x0784);
2367 sample += QChar(0x0794);
2368 sample += QChar(0x078c);
2369 sample += QChar(0x078d);
2370 break;
2371 case Devanagari:
2372 sample += QChar(0x0905);
2373 sample += QChar(0x0915);
2374 sample += QChar(0x0925);
2375 sample += QChar(0x0935);
2376 break;
2377 case Bengali:
2378 sample += QChar(0x0986);
2379 sample += QChar(0x0996);
2380 sample += QChar(0x09a6);
2381 sample += QChar(0x09b6);
2382 break;
2383 case Gurmukhi:
2384 sample += QChar(0x0a05);
2385 sample += QChar(0x0a15);
2386 sample += QChar(0x0a25);
2387 sample += QChar(0x0a35);
2388 break;
2389 case Gujarati:
2390 sample += QChar(0x0a85);
2391 sample += QChar(0x0a95);
2392 sample += QChar(0x0aa5);
2393 sample += QChar(0x0ab5);
2394 break;
2395 case Oriya:
2396 sample += QChar(0x0b06);
2397 sample += QChar(0x0b16);
2398 sample += QChar(0x0b2b);
2399 sample += QChar(0x0b36);
2400 break;
2401 case Tamil:
2402 sample += QChar(0x0b89);
2403 sample += QChar(0x0b99);
2404 sample += QChar(0x0ba9);
2405 sample += QChar(0x0bb9);
2406 break;
2407 case Telugu:
2408 sample += QChar(0x0c05);
2409 sample += QChar(0x0c15);
2410 sample += QChar(0x0c25);
2411 sample += QChar(0x0c35);
2412 break;
2413 case Kannada:
2414 sample += QChar(0x0c85);
2415 sample += QChar(0x0c95);
2416 sample += QChar(0x0ca5);
2417 sample += QChar(0x0cb5);
2418 break;
2419 case Malayalam:
2420 sample += QChar(0x0d05);
2421 sample += QChar(0x0d15);
2422 sample += QChar(0x0d25);
2423 sample += QChar(0x0d35);
2424 break;
2425 case Sinhala:
2426 sample += QChar(0x0d90);
2427 sample += QChar(0x0da0);
2428 sample += QChar(0x0db0);
2429 sample += QChar(0x0dc0);
2430 break;
2431 case Thai:
2432 sample += QChar(0x0e02);
2433 sample += QChar(0x0e12);
2434 sample += QChar(0x0e22);
2435 sample += QChar(0x0e32);
2436 break;
2437 case Lao:
2438 sample += QChar(0x0e8d);
2439 sample += QChar(0x0e9d);
2440 sample += QChar(0x0ead);
2441 sample += QChar(0x0ebd);
2442 break;
2443 case Tibetan:
2444 sample += QChar(0x0f00);
2445 sample += QChar(0x0f01);
2446 sample += QChar(0x0f02);
2447 sample += QChar(0x0f03);
2448 break;
2449 case Myanmar:
2450 sample += QChar(0x1000);
2451 sample += QChar(0x1001);
2452 sample += QChar(0x1002);
2453 sample += QChar(0x1003);
2454 break;
2455 case Georgian:
2456 sample += QChar(0x10a0);
2457 sample += QChar(0x10b0);
2458 sample += QChar(0x10c0);
2459 sample += QChar(0x10d0);
2460 break;
2461 case Khmer:
2462 sample += QChar(0x1780);
2463 sample += QChar(0x1790);
2464 sample += QChar(0x17b0);
2465 sample += QChar(0x17c0);
2466 break;
2467 case SimplifiedChinese:
2468 sample += QChar(0x4e2d);
2469 sample += QChar(0x6587);
2470 sample += QChar(0x8303);
2471 sample += QChar(0x4f8b);
2472 break;
2473 case TraditionalChinese:
2474 sample += QChar(0x4e2d);
2475 sample += QChar(0x6587);
2476 sample += QChar(0x7bc4);
2477 sample += QChar(0x4f8b);
2478 break;
2479 case Japanese:
2480 sample += QChar(0x3050);
2481 sample += QChar(0x3060);
2482 sample += QChar(0x30b0);
2483 sample += QChar(0x30c0);
2484 break;
2485 case Korean:
2486 sample += QChar(0xac00);
2487 sample += QChar(0xac11);
2488 sample += QChar(0xac1a);
2489 sample += QChar(0xac2f);
2490 break;
2491 case Vietnamese:
2492 {
2493 static const char vietnameseUtf8[] = {
2494 char(0xef), char(0xbb), char(0xbf), char(0xe1), char(0xbb), char(0x97),
2495 char(0xe1), char(0xbb), char(0x99),
2496 char(0xe1), char(0xbb), char(0x91),
2497 char(0xe1), char(0xbb), char(0x93),
2498 };
2499 sample += QString::fromUtf8(vietnameseUtf8, sizeof(vietnameseUtf8));
2500 break;
2501 }
2502 case Ogham:
2503 sample += QChar(0x1681);
2504 sample += QChar(0x1682);
2505 sample += QChar(0x1683);
2506 sample += QChar(0x1684);
2507 break;
2508 case Runic:
2509 sample += QChar(0x16a0);
2510 sample += QChar(0x16a1);
2511 sample += QChar(0x16a2);
2512 sample += QChar(0x16a3);
2513 break;
2514 case Nko:
2515 sample += QChar(0x7ca);
2516 sample += QChar(0x7cb);
2517 sample += QChar(0x7cc);
2518 sample += QChar(0x7cd);
2519 break;
2520 default:
2521 break;
2522 }
2523 return sample;
2524}
2525
2526
2527void QFontDatabase::parseFontName(const QString &name, QString &foundry, QString &family)
2528{
2529 QT_PREPEND_NAMESPACE(parseFontName)(name, foundry, family);
2530}
2531
2532void QFontDatabase::createDatabase()
2533{ initializeDb(); }
2534
2535// used from qfontengine_ft.cpp
2536QByteArray qt_fontdata_from_index(int index)
2537{
2538 QMutexLocker locker(fontDatabaseMutex());
2539 return privateDb()->applicationFonts.value(index).data;
2540}
2541
2542int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString &fileName)
2543{
2544 QFontDatabasePrivate::ApplicationFont font;
2545 font.data = fontData;
2546 font.fileName = fileName;
2547
2548 int i;
2549 for (i = 0; i < applicationFonts.count(); ++i)
2550 if (applicationFonts.at(i).families.isEmpty())
2551 break;
2552 if (i >= applicationFonts.count()) {
2553 applicationFonts.append(ApplicationFont());
2554 i = applicationFonts.count() - 1;
2555 }
2556
2557 if (font.fileName.isEmpty() && !fontData.isEmpty())
2558 font.fileName = QString::fromLatin1(":qmemoryfonts/") + QString::number(i);
2559
2560 registerFont(&font);
2561 if (font.families.isEmpty())
2562 return -1;
2563
2564 applicationFonts[i] = font;
2565
2566 invalidate();
2567 return i;
2568}
2569
2570bool QFontDatabasePrivate::isApplicationFont(const QString &fileName)
2571{
2572 for (int i = 0; i < applicationFonts.count(); ++i)
2573 if (applicationFonts.at(i).fileName == fileName)
2574 return true;
2575 return false;
2576}
2577
2578/*!
2579 \since 4.2
2580
2581 Loads the font from the file specified by \a fileName and makes it available to
2582 the application. An ID is returned that can be used to remove the font again
2583 with removeApplicationFont() or to retrieve the list of family names contained
2584 in the font.
2585
2586 The function returns -1 if the font could not be loaded.
2587
2588 Currently only TrueType fonts, TrueType font collections, and OpenType fonts are
2589 supported.
2590
2591 \note Adding application fonts on Unix/X11 platforms without fontconfig is
2592 currently not supported.
2593
2594 \sa addApplicationFontFromData(), applicationFontFamilies(), removeApplicationFont()
2595*/
2596int QFontDatabase::addApplicationFont(const QString &fileName)