source: trunk/src/gui/text/qfontdatabase_pm.cpp@ 439

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

general: Fixed a bunch of deprecated QString/QChar initializers.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Date Revision Author Id
File size: 32.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** Copyright (C) 2009 netlabs.org. OS/2 parts.
7**
8** This file is part of the QtGui module of the Qt Toolkit.
9**
10** $QT_BEGIN_LICENSE:LGPL$
11** Commercial Usage
12** Licensees holding valid Qt Commercial licenses may use this file in
13** accordance with the Qt Commercial License Agreement provided with the
14** Software or, alternatively, in accordance with the terms contained in
15** a written agreement between you and Nokia.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Nokia gives you certain
26** additional rights. These rights are described in the Nokia Qt LGPL
27** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28** package.
29**
30** GNU General Public License Usage
31** Alternatively, this file may be used under the terms of the GNU
32** General Public License version 3.0 as published by the Free Software
33** Foundation and appearing in the file LICENSE.GPL included in the
34** packaging of this file. Please review the following information to
35** ensure the GNU General Public License version 3.0 requirements will be
36** met: http://www.gnu.org/copyleft/gpl.html.
37**
38** If you are unsure which license is appropriate for your use, please
39** contact the sales department at [email protected].
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include "qfontengine_pm_p.h"
45
46#include "qabstractfileengine.h"
47#include "qsettings.h"
48#include "qfileinfo.h"
49#include "qdatetime.h"
50#include "qhash.h"
51#include "qtextcodec.h"
52
53#include <ft2build.h>
54#include FT_FREETYPE_H
55#include FT_TYPES_H
56#include FT_TRUETYPE_TABLES_H
57#include FT_LCD_FILTER_H
58#include FT_SFNT_NAMES_H
59#include FT_TRUETYPE_IDS_H
60
61QT_BEGIN_NAMESPACE
62
63struct FaceData
64{
65 int index;
66 QString familyName;
67 QtFontStyle::Key styleKey;
68 QList<QFontDatabase::WritingSystem> systems;
69 bool fixedPitch;
70 bool smoothScalable;
71 QList<unsigned short> pixelSizes;
72};
73
74static QDataStream &operator<<(QDataStream &data, const QFontDatabase::WritingSystem &ws)
75{
76 data << (int)ws;
77 return data;
78}
79
80static QDataStream &operator>>(QDataStream &data, QFontDatabase::WritingSystem &ws)
81{
82 data >> (int&)ws;
83 return data;
84}
85
86static QDataStream &operator<<(QDataStream &data, const FaceData &cached)
87{
88 data << cached.familyName;
89 data << cached.styleKey.style << cached.styleKey.weight
90 << cached.styleKey.stretch;
91 data << cached.systems;
92 data << cached.fixedPitch << cached.smoothScalable;
93 data << cached.pixelSizes;
94 return data;
95}
96
97static QDataStream &operator>>(QDataStream &data, FaceData &cached)
98{
99 data >> cached.familyName;
100 uint style;
101 int weight, stretch;
102 data >> style; cached.styleKey.style = style;
103 data >> weight; cached.styleKey.weight = weight;
104 data >> stretch; cached.styleKey.stretch = stretch;
105 data >> cached.systems;
106 data >> cached.fixedPitch >> cached.smoothScalable;
107 data >> cached.pixelSizes;
108 return data;
109}
110
111struct FileData
112{
113 FileData() : seen(false) {}
114 FileData(const QFileInfo &fi, bool s) : fileInfo(fi), seen(s) {}
115
116 QFileInfo fileInfo;
117 bool seen;
118};
119
120typedef QHash<QString, FileData> FontFileHash;
121static FontFileHash knownFontFiles;
122static bool knownFontFilesInitialized = false;
123
124static bool lookupFamilyName(FT_Face ftface, QString &familyName)
125{
126 FT_UInt nNameCount;
127 FT_UInt i;
128 FT_SfntName sfntName;
129 FT_UInt found, best;
130
131 nNameCount = FT_Get_Sfnt_Name_Count(ftface);
132
133 if (nNameCount == 0)
134 return false;
135
136#ifndef QT_NO_TEXTCODEC
137 QTextCodec *codec = QTextCodec::codecForName("UTF-16BE");
138
139 // find a unicode name at first
140 if (codec) {
141 found = (FT_UInt)-1;
142 best = (FT_UInt)-1;
143
144 // try to find the unicode name matching to the locale
145 for (i = 0; found == (FT_UInt)-1 && i < nNameCount; i++) {
146 FT_Get_Sfnt_Name(ftface, i, &sfntName);
147
148 if (sfntName.name_id == TT_NAME_ID_FONT_FAMILY &&
149 sfntName.platform_id == TT_PLATFORM_MICROSOFT &&
150 sfntName.encoding_id == TT_MS_ID_UNICODE_CS) {
151 if (best == (FT_UInt)-1 || sfntName.language_id == TT_MS_LANGID_ENGLISH_UNITED_STATES)
152 best = i;
153
154 QLocale sysLocale = QLocale::system();
155 switch (sfntName.language_id) {
156 case TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA :
157 if (sysLocale.language() == QLocale::Korean)
158 found = i;
159 break;
160
161 case TT_MS_LANGID_JAPANESE_JAPAN :
162 if (sysLocale.language() == QLocale::Japanese)
163 found = i;
164 break;
165
166 case TT_MS_LANGID_CHINESE_PRC :
167 if (sysLocale.country() == QLocale::China &&
168 sysLocale.language() == QLocale::Chinese)
169 found = i;
170 break;
171
172 case TT_MS_LANGID_CHINESE_TAIWAN :
173 if (sysLocale.country() == QLocale::Taiwan &&
174 sysLocale.language() == QLocale::Chinese)
175 found = i;
176 break;
177 }
178 }
179 }
180
181 if (found == (FT_UInt)-1)
182 found = best;
183
184 if (found != (FT_UInt)-1) {
185 FT_Get_Sfnt_Name(ftface, found, &sfntName);
186
187 familyName = codec->toUnicode((const char *)sfntName.string, sfntName.string_len);
188
189 return true;
190 }
191 }
192#endif
193
194 found = (FT_UInt)-1;
195 best = (FT_UInt)-1;
196
197 // unicode name is not available, try the NLS encoded name
198 for (i = 0; found == (FT_UInt)-1 && i < nNameCount; i++) {
199 FT_Get_Sfnt_Name(ftface, i, &sfntName);
200
201 if (sfntName.name_id == TT_NAME_ID_FONT_FAMILY &&
202 sfntName.platform_id == TT_PLATFORM_MICROSOFT) {
203 if (best == (FT_UInt)-1)
204 best = i;
205
206 QLocale sysLocale = QLocale::system();
207 switch (sfntName.encoding_id) {
208 case TT_MS_ID_WANSUNG :
209 if (sysLocale.language() == QLocale::Korean)
210 found = i;
211 break;
212
213 case TT_MS_ID_SJIS :
214 if (sysLocale.language() == QLocale::Japanese)
215 found = i;
216 break;
217
218 case TT_MS_ID_BIG_5 :
219 if (sysLocale.country() == QLocale::Taiwan &&
220 sysLocale.language() == QLocale::Chinese)
221 found = i;
222 break;
223
224 case TT_MS_ID_GB2312 :
225 if (sysLocale.country() == QLocale::China &&
226 sysLocale.language() == QLocale::Chinese)
227 found = i;
228 break;
229
230 case TT_MS_ID_SYMBOL_CS :
231 found = i;
232 break;
233 }
234 }
235 }
236
237 if (found == (FT_UInt)-1)
238 found = best;
239
240 if (found != (FT_UInt)-1)
241 {
242 char *name;
243 FT_UInt name_len = 0;
244
245 FT_Get_Sfnt_Name(ftface, found, &sfntName);
246
247 name = (char *)alloca(sfntName.string_len);
248
249 for (FT_UInt j = 0; j < sfntName.string_len; j++)
250 if (sfntName.string[j])
251 name[name_len++] = sfntName.string[j];
252
253#ifndef QT_NO_TEXTCODEC
254 switch (sfntName.encoding_id) {
255 case TT_MS_ID_WANSUNG :
256 codec = QTextCodec::codecForName("cp949");
257 break;
258
259 case TT_MS_ID_SJIS :
260 codec = QTextCodec::codecForName("SJIS");
261 break;
262
263 case TT_MS_ID_BIG_5 :
264 codec = QTextCodec::codecForName("Big5");
265 break;
266
267 case TT_MS_ID_GB2312 :
268 codec = QTextCodec::codecForName("GB2312");
269 break;
270
271 case TT_MS_ID_SYMBOL_CS :
272 default :
273 codec = NULL;
274 break;
275 }
276
277 if (codec)
278 familyName = codec->toUnicode(name, name_len);
279 else
280#endif
281 familyName = QString::fromLocal8Bit(name, name_len);
282
283 return true;
284 }
285
286 return false;
287}
288
289static void populateDatabase(const QString& fam)
290{
291 QFontDatabasePrivate *db = privateDb();
292 if (!db)
293 return;
294
295 QtFontFamily *family = 0;
296 if(!fam.isEmpty()) {
297 family = db->family(fam);
298 if(family)
299 return;
300 } else if (db->count) {
301 return;
302 }
303
304 // we don't recognize foundries on OS/2, use an empty one
305 const QString foundryName;
306
307#ifdef QFONTDATABASE_DEBUG
308 QTime timer;
309 timer.start();
310#endif
311
312 QSettings fontCache(QSettings::UserScope, QLatin1String("Trolltech"));
313 fontCache.beginGroup(QLatin1String("Qt/Fonts/Cache 1.0"));
314
315 if (!knownFontFilesInitialized) {
316 // get the initial list of know font files from the cache (necessary to
317 // detect deleted font files)
318 knownFontFilesInitialized = true;
319 QStringList files = fontCache.childGroups();
320 foreach(QString file, files) {
321 file.replace(QLatin1Char('|'), QLatin1Char('/'));
322 knownFontFiles.insert(file, FileData());
323 // note that QFileInfo is empty so the file will be considered as
324 // NEW which is necessary for the font to get into the database
325 }
326 } else {
327 // reset the 'seen' flag
328 for (FontFileHash::iterator it = knownFontFiles.begin();
329 it != knownFontFiles.end(); ++it)
330 it.value().seen = false;
331 }
332
333 QList<QFileInfo> fontFiles;
334
335 ULONG bufSize = 0;
336 BOOL ok = PrfQueryProfileSize(HINI_USERPROFILE, "PM_Fonts", 0, &bufSize);
337 Q_ASSERT(ok);
338 if (ok) {
339 char *buffer = new char[bufSize + 1 /*terminating NULL*/];
340 Q_ASSERT(buffer);
341 if (buffer) {
342 ULONG bufLen = PrfQueryProfileString(HINI_USERPROFILE, "PM_Fonts", 0, 0,
343 buffer, bufSize);
344 if (bufLen) {
345 char *key = buffer;
346 while (*key) {
347 ULONG keySize = 0;
348 ok = PrfQueryProfileSize(HINI_USERPROFILE, "PM_Fonts", key,
349 &keySize);
350 if (ok) {
351 QByteArray file(keySize, 0);
352 ULONG keyLen =
353 PrfQueryProfileString(HINI_USERPROFILE, "PM_Fonts", key, 0,
354 file.data(), file.size());
355 file.truncate(keyLen - 1 /*terminating NULL*/);
356 if (!file.isEmpty()) {
357 // FreeType doesn't understand .OFM but understands .PFB
358 if (file.toUpper().endsWith(".OFM")) {
359 file.chop(4);
360 file.append(".PFB");
361 }
362 QFileInfo fileInfo(QFile::decodeName(file));
363 QString fileName = fileInfo.canonicalFilePath().toLower();
364 if (!fileName.isEmpty()) { // file may have been deleted
365 fileInfo.setFile(fileName);
366 // check the in-process file name cache
367 FileData &cached = knownFontFiles[fileName];
368 if (cached.fileInfo.filePath().isEmpty() ||
369 cached.fileInfo.lastModified() != fileInfo.lastModified() ||
370 cached.fileInfo.size() != fileInfo.size()) {
371 // no cache entry or outdated, process it
372 cached.fileInfo = fileInfo;
373 cached.seen = true;
374 fontFiles << fileInfo;
375 FD_DEBUG("populateDatabase: NEW/UPDATED font file %s",
376 qPrintable(fileName));
377 } else {
378 // just set the 'seen' flag and skip this font
379 // (it's already in the database)
380 knownFontFiles[fileName].seen = true;
381 FD_DEBUG("populateDatabase: UNCHANGED font file %s",
382 qPrintable(fileName));
383 }
384 }
385 }
386 }
387 key += strlen(key) + 1;
388 }
389 }
390 delete buffer;
391 }
392 }
393
394 extern FT_Library qt_getFreetype(); // qfontengine_ft.cpp
395 FT_Library lib = qt_getFreetype();
396
397 // go through each font file and get available faces
398 foreach(const QFileInfo &fileInfo, fontFiles) {
399 QString fileKey = fileInfo.absoluteFilePath().toLower();
400 QByteArray file = QFile::encodeName(fileKey);
401
402 // QSettings uses / for splitting into groups, suppress it
403 fileKey.replace(QLatin1Char('/'), QLatin1Char('|'));
404
405 QList<FaceData> cachedFaces;
406
407 // first, look up the cached data
408 fontCache.beginGroup(fileKey);
409
410 if (fontCache.value(QLatin1String("DateTime")).toDateTime() != fileInfo.lastModified() ||
411 fontCache.value(QLatin1String("Size")).toUInt() != fileInfo.size()) {
412 // the cache is outdated or doesn't exist, query the font file
413
414 FT_Long numFaces = 0;
415 FT_Face face;
416
417 FT_Error rc = FT_New_Face(lib, file, -1, &face);
418 if (rc == 0) {
419 numFaces = face->num_faces;
420 FT_Done_Face(face);
421 } else {
422 // invalid/unsupported font file, numFaces is left 0 so that
423 // only DateTime and Size will be cached indicating that this
424 // file is not recognized
425 }
426
427 FD_DEBUG("populateDatabase: Font file %s: FT error %d, has %ld faces",
428 file.constData(), (int) rc, numFaces);
429
430 // go throuhg each face
431 for (FT_Long idx = 0; idx < numFaces; ++idx) {
432 rc = FT_New_Face(lib, file, idx, &face);
433 if (rc != 0)
434 continue;
435
436 FaceData cached;
437
438 cached.index = idx;
439
440 if (!lookupFamilyName(face, cached.familyName))
441 cached.familyName = QString::fromLocal8Bit(face->family_name);
442
443 // familyName may contain extra spaces (at least this is true for
444 // TNR.PFB that is reported as "Times New Roman ". Trim them.
445 cached.familyName = cached.familyName.trimmed();
446
447 cached.styleKey.style = face->style_flags & FT_STYLE_FLAG_ITALIC ?
448 QFont::StyleItalic : QFont::StyleNormal;
449
450 TT_OS2 *os2_table = 0;
451 if (face->face_flags & FT_FACE_FLAG_SFNT) {
452 os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
453 }
454 if (os2_table) {
455 // map weight and width values
456 if (os2_table->usWeightClass < 400)
457 cached.styleKey.weight = QFont::Light;
458 else if (os2_table->usWeightClass < 600)
459 cached.styleKey.weight = QFont::Normal;
460 else if (os2_table->usWeightClass < 700)
461 cached.styleKey.weight = QFont::DemiBold;
462 else if (os2_table->usWeightClass < 800)
463 cached.styleKey.weight = QFont::Bold;
464 else
465 cached.styleKey.weight = QFont::Black;
466
467 switch (os2_table->usWidthClass) {
468 case 1: cached.styleKey.stretch = QFont::UltraCondensed; break;
469 case 2: cached.styleKey.stretch = QFont::ExtraCondensed; break;
470 case 3: cached.styleKey.stretch = QFont::Condensed; break;
471 case 4: cached.styleKey.stretch = QFont::SemiCondensed; break;
472 case 5: cached.styleKey.stretch = QFont::Unstretched; break;
473 case 6: cached.styleKey.stretch = QFont::SemiExpanded; break;
474 case 7: cached.styleKey.stretch = QFont::Expanded; break;
475 case 8: cached.styleKey.stretch = QFont::ExtraExpanded; break;
476 case 9: cached.styleKey.stretch = QFont::UltraExpanded; break;
477 default: cached.styleKey.stretch = QFont::Unstretched; break;
478 }
479
480 quint32 unicodeRange[4] = {
481 os2_table->ulUnicodeRange1, os2_table->ulUnicodeRange2,
482 os2_table->ulUnicodeRange3, os2_table->ulUnicodeRange4
483 };
484 quint32 codePageRange[2] = {
485 os2_table->ulCodePageRange1, os2_table->ulCodePageRange2
486 };
487 cached.systems =
488 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
489 } else {
490 // we've only got simple weight information and no stretch
491 cached.styleKey.weight = face->style_flags & FT_STYLE_FLAG_BOLD ?
492 QFont::Bold : QFont::Normal;
493 cached.styleKey.stretch = QFont::Unstretched;
494 }
495
496 cached.fixedPitch = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH;
497
498 cached.smoothScalable = face->face_flags & FT_FACE_FLAG_SCALABLE;
499
500 // the font may both be scalable and contain fixed size bitmaps
501 if (face->face_flags & FT_FACE_FLAG_FIXED_SIZES) {
502 for (FT_Int i = 0; i < face->num_fixed_sizes; ++i) {
503 cached.pixelSizes << face->available_sizes[i].height;
504 }
505 }
506
507 cachedFaces << cached;
508
509 FT_Done_Face(face);
510 }
511
512 // store the data into the cache
513 fontCache.setValue(QLatin1String("DateTime"), fileInfo.lastModified());
514 fontCache.setValue(QLatin1String("Size"), fileInfo.size());
515 foreach(FaceData cached, cachedFaces) {
516 QByteArray rawData;
517 QDataStream data(&rawData, QIODevice::WriteOnly);
518 data << cached;
519
520 QString face = QString::number(cached.index);
521 fontCache.beginGroup(face);
522 fontCache.setValue(QLatin1String("Info"), rawData);
523 fontCache.endGroup();
524 }
525 } else {
526 // take the face data from the cache
527
528 QStringList faces = fontCache.childGroups();
529
530 FD_DEBUG("populateDatabase: Font file %s: IN CACHE, has %d faces",
531 file.constData(), faces.count());
532
533 foreach(QString face, faces) {
534 bool ok = false;
535 FaceData cached;
536 cached.index = face.toInt(&ok);
537 if (!ok || cached.index < 0) // not a valid index
538 continue;
539
540 fontCache.beginGroup(face);
541 QByteArray rawData =
542 fontCache.value(QLatin1String("Info")).toByteArray();
543 QDataStream data(rawData);
544 data >> cached;
545 fontCache.endGroup();
546
547 cachedFaces << cached;
548 }
549 }
550
551 fontCache.endGroup();
552
553 // go throuhg each cached face and add it to the database
554 foreach(FaceData cached, cachedFaces) {
555
556 QtFontFamily *family = privateDb()->family(cached.familyName, true);
557
558 // @todo is it possible that the same family is both fixed and not?
559 Q_ASSERT(!family->fixedPitch || cached.fixedPitch);
560 family->fixedPitch = cached.fixedPitch;
561
562 if (cached.systems.isEmpty()) {
563 // it was hard or impossible to determine the actual writing system
564 // of the font (as in case of OS/2 bitmap and PFB fonts for which it is
565 // usually simply reported that they support standard/system codepages).
566 // Pretend that we support all writing systems to not miss the one.
567 //
568 // @todo find a proper way to detect actual supported scripts to make
569 // sure these fonts are not matched for scripts they don't support.
570 for (int ws = 0; ws < QFontDatabase::WritingSystemsCount; ++ws)
571 family->writingSystems[ws] = QtFontFamily::Supported;
572 } else {
573 for (int i = 0; i < cached.systems.count(); ++i)
574 family->writingSystems[cached.systems.at(i)] = QtFontFamily::Supported;
575 }
576
577 QtFontFoundry *foundry = family->foundry(foundryName, true);
578 QtFontStyle *style = foundry->style(cached.styleKey, true);
579
580 // so far, all recognized fonts are antialiased
581 style->antialiased = true;
582
583 if (cached.smoothScalable && !style->smoothScalable) {
584 // add new scalable style only if it hasn't been already added --
585 // the first one of two duplicate (in Qt terms) non-bitmap font
586 // styles wins.
587 style->smoothScalable = true;
588 QtFontSize *size =
589 style->pixelSize(SMOOTH_SCALABLE, true);
590 size->fileName = file;
591 size->fileIndex = cached.index;
592 size->systems = cached.systems;
593 }
594
595 foreach(unsigned short pixelSize, cached.pixelSizes) {
596 QtFontSize *size = style->pixelSize(pixelSize, true);
597 // the first bitmap style with a given pixel and point size wins
598 if (!size->fileName.isEmpty())
599 continue;
600 size->fileName = file;
601 size->fileIndex = cached.index;
602 size->systems = cached.systems;
603 }
604 }
605 }
606
607 // go through the known file list to detect what files have been removed
608 for (FontFileHash::iterator it = knownFontFiles.begin();
609 it != knownFontFiles.end();) {
610 if (!it.value().seen) {
611 FD_DEBUG("populateDatabase: DELETED font file %s",
612 qPrintable(it.key()));
613 // remove from the both caches
614 QString fileKey = it.key();
615 fileKey.replace(QLatin1Char('/'), QLatin1Char('|'));
616 fontCache.remove(fileKey);
617 it = knownFontFiles.erase(it);
618 // @todo should we remove all references to this file from the
619 // font database? My concern is that this font may be in use by Qt
620 // and its glyphs may be still cached when file deletion happens
621 } else {
622 ++it;
623 }
624 }
625
626#ifdef QFONTDATABASE_DEBUG
627 FD_DEBUG("populateDatabase: took %d ms", timer.elapsed());
628#endif
629}
630
631static void initializeDb()
632{
633 QFontDatabasePrivate *db = privateDb();
634 if (!db || db->count)
635 return;
636
637 populateDatabase(QString());
638
639#ifdef QFONTDATABASE_DEBUG
640 // print the database
641 qDebug("initializeDb:");
642 for (int f = 0; f < db->count; f++) {
643 QtFontFamily *family = db->families[f];
644 qDebug(" %s: %p", qPrintable(family->name), family);
645 populateDatabase(family->name);
646#if 1
647 qDebug(" writing systems supported:");
648 QStringList systems;
649 for (int ws = 0; ws < QFontDatabase::WritingSystemsCount; ++ws)
650 if (family->writingSystems[ws] & QtFontFamily::Supported)
651 systems << QFontDatabase::writingSystemName((QFontDatabase::WritingSystem)ws);
652 qDebug() << " " << systems;
653 for (int fd = 0; fd < family->count; fd++) {
654 QtFontFoundry *foundry = family->foundries[fd];
655 qDebug(" %s", foundry->name.isEmpty() ? "(empty foundry)" :
656 qPrintable(foundry->name));
657 for (int s = 0; s < foundry->count; s++) {
658 QtFontStyle *style = foundry->styles[s];
659 qDebug(" style: style=%d weight=%d smooth=%d", style->key.style,
660 style->key.weight, style->smoothScalable);
661 for(int i = 0; i < style->count; ++i) {
662 if (style->pixelSizes[i].pixelSize == SMOOTH_SCALABLE)
663 qDebug(" smooth %s:%d",
664 style->pixelSizes[i].fileName.constData(),
665 style->pixelSizes[i].fileIndex);
666 else
667 qDebug(" %d px %s:%d", style->pixelSizes[i].pixelSize,
668 style->pixelSizes[i].fileName.constData(),
669 style->pixelSizes[i].fileIndex);
670 }
671 }
672 }
673#endif
674 }
675#endif // QFONTDATABASE_DEBUG
676}
677
678static inline void load(const QString &family = QString(), int = -1)
679{
680 populateDatabase(family);
681}
682
683static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
684{
685 // @todo implement
686}
687
688static QFontDef fontDescToFontDef(const QFontDef &req, const QtFontDesc &desc)
689{
690 static LONG dpi = -1;
691 if (dpi == -1) {
692 // PM cannot change resolutions on the fly so cache it
693 int hps = qt_display_ps();
694 DevQueryCaps(GpiQueryDevice(hps), CAPS_HORIZONTAL_FONT_RES, 1, &dpi);
695 }
696
697 QFontDef fontDef;
698
699 fontDef.family = desc.family->name;
700
701 if (desc.size->pixelSize == SMOOTH_SCALABLE) {
702 // scalable font matched, calculate the missing size (points or pixels)
703 fontDef.pointSize = req.pointSize;
704 fontDef.pixelSize = req.pixelSize;
705 if (req.pointSize < 0) {
706 fontDef.pointSize = req.pixelSize * 72. / dpi;
707 } else if (req.pixelSize == -1) {
708 fontDef.pixelSize = qRound(req.pointSize * dpi / 72.);
709 }
710 } else {
711 // non-scalable font matched, calculate both point and pixel size
712 fontDef.pixelSize = desc.size->pixelSize;
713 fontDef.pointSize = desc.size->pixelSize * 72. / dpi;
714 }
715
716 fontDef.styleStrategy = req.styleStrategy;
717 fontDef.styleHint = req.styleHint;
718
719 fontDef.weight = desc.style->key.weight;
720 fontDef.fixedPitch = desc.family->fixedPitch;
721 fontDef.style = desc.style->key.style;
722 fontDef.stretch = desc.style->key.stretch;
723
724 return fontDef;
725}
726
727static QFontEngine *loadEngine(const QFontDef &req, const QtFontDesc &desc)
728{
729 // @todo all these fixed so far; make configurable through the Registry
730 // on per-family basis
731 QFontEnginePMFT::HintStyle hintStyle = QFontEnginePMFT::HintFull;
732 bool autoHint = true;
733 QFontEngineFT::SubpixelAntialiasingType subPixel = QFontEngineFT::Subpixel_None;
734 int lcdFilter = FT_LCD_FILTER_DEFAULT;
735 bool useEmbeddedBitmap = true;
736
737 QFontEngine::FaceId faceId;
738 faceId.filename = desc.size->fileName;
739 faceId.index = desc.size->fileIndex;
740
741 QFontEngineFT *fe = new QFontEnginePMFT(fontDescToFontDef(req, desc), faceId,
742 desc.style->antialiased, hintStyle,
743 autoHint, subPixel, lcdFilter,
744 useEmbeddedBitmap);
745 Q_ASSERT(fe);
746 if (fe && fe->invalid()) {
747 FM_DEBUG(" --> invalid!\n");
748 delete fe;
749 fe = 0;
750 }
751 return fe;
752}
753
754static QString getAssociateFont()
755{
756 static char szFontName[FACESIZE + 1] = {0,};
757
758 // already queried ?
759 if (szFontName[0] == '\0') {
760 // query the associated font
761 if (PrfQueryProfileString(HINI_USERPROFILE,
762 "PM_SystemFonts", "PM_AssociateFont", 0,
763 szFontName, sizeof(szFontName))) {
764 szFontName[FACESIZE] = '\0';
765
766 // the format of the associated font is face_name;point_size
767 // so remove ';' and later
768 for (PSZ pch = szFontName; *pch; pch++)
769 if (*pch == ';') {
770 *pch = '\0';
771 break;
772 }
773 }
774
775 if (szFontName[0] == '\0')
776 szFontName[0] = ';';
777 }
778
779 if (szFontName[0] != ';')
780 return QString::fromLocal8Bit(szFontName);
781
782 return QString::null;
783}
784
785static QFontEngine *loadPM(const QFontPrivate *d, int script, const QFontDef &req)
786{
787 // list of families to try
788 QStringList families = familyList(req);
789
790 const char *styleHint = qt_fontFamilyFromStyleHint(d->request);
791 if (styleHint)
792 families << QLatin1String(styleHint);
793
794 // add the default family
795 QString defaultFamily = QApplication::font().family();
796 if (!families.contains(defaultFamily))
797 families << defaultFamily;
798
799 // add QFont::defaultFamily() to the list, for compatibility with
800 // previous versions
801 families << QApplication::font().defaultFamily();
802
803 // add PM_AssociateFont to the list (used on DBCS systems to take the
804 // missing glyphs from)
805 QString associateFont = getAssociateFont();
806 if (!associateFont.isEmpty() && !families.contains(associateFont))
807 families << associateFont;
808
809 // null family means find the first font matching the specified script
810 families << QString();
811
812 QtFontDesc desc;
813 QFontEngine *fe = 0;
814 QList<int> blacklistedFamilies;
815
816 while (!fe) {
817 for (int i = 0; i < families.size(); ++i) {
818 QString family, foundry;
819 parseFontName(families.at(i), foundry, family);
820 FM_DEBUG("loadPM: >>>>>>>>>>>>>> trying to match '%s'", qPrintable(family));
821 QT_PREPEND_NAMESPACE(match)(script, req, family, foundry, -1, &desc, blacklistedFamilies);
822 if (desc.family)
823 break;
824 }
825 if (!desc.family)
826 break;
827 FM_DEBUG("loadPM: ============== matched '%s'", qPrintable(desc.family->name));
828 fe = loadEngine(req, desc);
829 if (!fe)
830 blacklistedFamilies.append(desc.familyIndex);
831 }
832 return fe;
833}
834
835void QFontDatabase::load(const QFontPrivate *d, int script)
836{
837 Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
838
839 // normalize the request to get better caching
840 QFontDef req = d->request;
841 if (req.pixelSize <= 0)
842 req.pixelSize = qMax(1, qRound(req.pointSize * d->dpi / 72.));
843 req.pointSize = 0;
844 if (req.weight == 0)
845 req.weight = QFont::Normal;
846 if (req.stretch == 0)
847 req.stretch = 100;
848
849 // @todo a hack to substitute "WarpSans" with "Workplace Sans". Remove this
850 // when we start supporting OS/2 bitmap fonts.
851 if (req.family == QLatin1String("WarpSans"))
852 req.family = QLatin1String("Workplace Sans");
853
854 QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
855 if (!d->engineData)
856 getEngineData(d, key);
857
858 // the cached engineData could have already loaded the engine we want
859 if (d->engineData->engines[script])
860 return;
861
862 // set it to the actual pointsize, so QFontInfo will do the right thing
863 req.pointSize = req.pixelSize * 72. / d->dpi;
864
865 QFontEngine *fe = QFontCache::instance()->findEngine(key);
866
867 if (!fe) {
868 if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
869 fe = new QTestFontEngine(req.pixelSize);
870 fe->fontDef = req;
871 } else {
872 QMutexLocker locker(fontDatabaseMutex());
873 if (!privateDb()->count)
874 initializeDb();
875 fe = loadPM(d, script, req);
876 }
877 if (!fe) {
878 fe = new QFontEngineBox(req.pixelSize);
879 fe->fontDef = QFontDef();
880 }
881 }
882 if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
883 for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
884 if (!d->engineData->engines[i]) {
885 d->engineData->engines[i] = fe;
886 fe->ref.ref();
887 }
888 }
889 } else {
890 d->engineData->engines[script] = fe;
891 fe->ref.ref();
892 }
893 QFontCache::instance()->insertEngine(key, fe);
894}
895
896bool QFontDatabase::removeApplicationFont(int handle)
897{
898 // @todo implement
899 return false;
900}
901
902bool QFontDatabase::removeAllApplicationFonts()
903{
904 // @todo implement
905 return false;
906}
907
908bool QFontDatabase::supportsThreadedFontRendering()
909{
910 // @todo implement
911 return false;
912}
913
914QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.