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

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

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

  • Property svn:eol-style set to native
File size: 32.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdir.h"
43#include "qscreen_qws.h" //so we can check for rotation
44#include "qwindowsystem_qws.h"
45#include "qlibraryinfo.h"
46#include "qabstractfileengine.h"
47#include <QtCore/qsettings.h>
48#if !defined(QT_NO_FREETYPE)
49#include "qfontengine_ft_p.h"
50
51#include <ft2build.h>
52#include FT_FREETYPE_H
53
54#endif
55#include "qfontengine_qpf_p.h"
56#include "private/qfactoryloader_p.h"
57#include "private/qcore_unix_p.h" // overrides QT_OPEN
58#include "qabstractfontengine_qws.h"
59#include "qabstractfontengine_p.h"
60#include <qdatetime.h>
61#include "qplatformdefs.h"
62
63// for mmap
64#include <stdlib.h>
65#include <unistd.h>
66#include <sys/types.h>
67#include <sys/stat.h>
68#include <sys/mman.h>
69#include <fcntl.h>
70#include <errno.h>
71
72#ifdef QT_FONTS_ARE_RESOURCES
73#include <qresource.h>
74#endif
75
76QT_BEGIN_NAMESPACE
77
78#ifndef QT_NO_LIBRARY
79Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
80 (QFontEngineFactoryInterface_iid, QLatin1String("/fontengines"), Qt::CaseInsensitive))
81#endif
82
83const quint8 DatabaseVersion = 4;
84
85// QFontDatabasePrivate::addFont() went into qfontdatabase.cpp
86
87#ifndef QT_NO_QWS_QPF2
88void QFontDatabasePrivate::addQPF2File(const QByteArray &file)
89{
90#ifndef QT_FONTS_ARE_RESOURCES
91 struct stat st;
92 if (stat(file.constData(), &st))
93 return;
94 int f = QT_OPEN(file, O_RDONLY, 0);
95 if (f < 0)
96 return;
97 const uchar *data = (const uchar *)mmap(0, st.st_size, PROT_READ, MAP_SHARED, f, 0);
98 const int dataSize = st.st_size;
99#else
100 QResource res(QLatin1String(file.constData()));
101 const uchar *data = res.data();
102 const int dataSize = res.size();
103 //qDebug() << "addQPF2File" << file << data;
104#endif
105 if (data && data != (const uchar *)MAP_FAILED) {
106 if (QFontEngineQPF::verifyHeader(data, dataSize)) {
107 QString fontName = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_FontName).toString();
108 int pixelSize = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_PixelSize).toInt();
109 QVariant weight = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_Weight);
110 QVariant style = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_Style);
111 QByteArray writingSystemBits = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_WritingSystems).toByteArray();
112
113 if (!fontName.isEmpty() && pixelSize) {
114 int fontWeight = 50;
115 if (weight.type() == QVariant::Int || weight.type() == QVariant::UInt)
116 fontWeight = weight.toInt();
117
118 bool italic = static_cast<QFont::Style>(style.toInt()) & QFont::StyleItalic;
119
120 QList<QFontDatabase::WritingSystem> writingSystems;
121 for (int i = 0; i < writingSystemBits.count(); ++i) {
122 uchar currentByte = writingSystemBits.at(i);
123 for (int j = 0; j < 8; ++j) {
124 if (currentByte & 1)
125 writingSystems << QFontDatabase::WritingSystem(i * 8 + j);
126 currentByte >>= 1;
127 }
128 }
129
130 addFont(fontName, /*foundry*/ "prerendered", fontWeight, italic,
131 pixelSize, file, /*fileIndex*/ 0,
132 /*antialiased*/ true, writingSystems);
133 }
134 } else {
135 qDebug() << "header verification of QPF2 font" << file << "failed. maybe it is corrupt?";
136 }
137#ifndef QT_FONTS_ARE_RESOURCES
138 munmap((void *)data, st.st_size);
139#endif
140 }
141#ifndef QT_FONTS_ARE_RESOURCES
142 QT_CLOSE(f);
143#endif
144}
145#endif // QT_NO_QWS_QPF2
146
147// QFontDatabasePrivate::addTTFile() went into qfontdatabase.cpp
148
149static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
150
151extern QString qws_fontCacheDir();
152
153#ifndef QT_FONTS_ARE_RESOURCES
154bool QFontDatabasePrivate::loadFromCache(const QString &fontPath)
155{
156 const bool weAreTheServer = QWSServer::instance();
157
158 QString fontDirFile = fontPath + QLatin1String("/fontdir");
159
160 QFile binaryDb(qws_fontCacheDir() + QLatin1String("/fontdb"));
161
162 if (weAreTheServer) {
163 QDateTime dbTimeStamp = QFileInfo(binaryDb.fileName()).lastModified();
164
165 QDateTime fontPathTimeStamp = QFileInfo(fontPath).lastModified();
166 if (dbTimeStamp < fontPathTimeStamp)
167 return false; // let the caller create the cache
168
169 if (QFile::exists(fontDirFile)) {
170 QDateTime fontDirTimeStamp = QFileInfo(fontDirFile).lastModified();
171 if (dbTimeStamp < fontDirTimeStamp)
172 return false;
173 }
174 }
175
176 if (!binaryDb.open(QIODevice::ReadOnly)) {
177 if (weAreTheServer)
178 return false; // let the caller create the cache
179 qFatal("QFontDatabase::loadFromCache: Could not open font database cache!");
180 }
181
182 QDataStream stream(&binaryDb);
183 quint8 version = 0;
184 quint8 dataStreamVersion = 0;
185 stream >> version >> dataStreamVersion;
186 if (version != DatabaseVersion || dataStreamVersion != stream.version()) {
187 if (weAreTheServer)
188 return false; // let the caller create the cache
189 qFatal("QFontDatabase::loadFromCache: Wrong version of the font database cache detected. Found %d/%d expected %d/%d",
190 version, dataStreamVersion, DatabaseVersion, stream.version());
191 }
192
193 QString originalFontPath;
194 stream >> originalFontPath;
195 if (originalFontPath != fontPath) {
196 if (weAreTheServer)
197 return false; // let the caller create the cache
198 qFatal("QFontDatabase::loadFromCache: Font path doesn't match. Found %s in database, expected %s", qPrintable(originalFontPath), qPrintable(fontPath));
199 }
200
201 QString familyname;
202 stream >> familyname;
203 //qDebug() << "populating database from" << binaryDb.fileName();
204 while (!familyname.isEmpty() && !stream.atEnd()) {
205 QString foundryname;
206 int weight;
207 quint8 italic;
208 int pixelSize;
209 QByteArray file;
210 int fileIndex;
211 quint8 antialiased;
212 quint8 writingSystemCount;
213
214 QList<QFontDatabase::WritingSystem> writingSystems;
215
216 stream >> foundryname >> weight >> italic >> pixelSize
217 >> file >> fileIndex >> antialiased >> writingSystemCount;
218
219 for (quint8 i = 0; i < writingSystemCount; ++i) {
220 quint8 ws;
221 stream >> ws;
222 writingSystems.append(QFontDatabase::WritingSystem(ws));
223 }
224
225 addFont(familyname, foundryname.toLatin1().constData(), weight, italic, pixelSize, file, fileIndex, antialiased,
226 writingSystems);
227
228 stream >> familyname;
229 }
230
231 stream >> fallbackFamilies;
232 //qDebug() << "fallback families from cache:" << fallbackFamilies;
233 return true;
234}
235#endif // QT_FONTS_ARE_RESOURCES
236
237/*!
238 \internal
239*/
240
241static QString qwsFontPath()
242{
243 QString fontpath = QString::fromLocal8Bit(qgetenv("QT_QWS_FONTDIR"));
244 if (fontpath.isEmpty()) {
245#ifdef QT_FONTS_ARE_RESOURCES
246 fontpath = QLatin1String(":/qt/fonts");
247#else
248#ifndef QT_NO_SETTINGS
249 fontpath = QLibraryInfo::location(QLibraryInfo::LibrariesPath);
250 fontpath += QLatin1String("/fonts");
251#else
252 fontpath = QLatin1String("/lib/fonts");
253#endif
254#endif //QT_FONTS_ARE_RESOURCES
255 }
256
257 return fontpath;
258}
259
260#if defined(QFONTDATABASE_DEBUG) && defined(QT_FONTS_ARE_RESOURCES)
261class FriendlyResource : public QResource
262{
263public:
264 bool isDir () const { return QResource::isDir(); }
265 bool isFile () const { return QResource::isFile(); }
266 QStringList children () const { return QResource::children(); }
267};
268#endif
269/*!
270 \internal
271*/
272static void initializeDb()
273{
274 QFontDatabasePrivate *db = privateDb();
275 if (!db || db->count)
276 return;
277
278 QString fontpath = qwsFontPath();
279#ifndef QT_FONTS_ARE_RESOURCES
280 QString fontDirFile = fontpath + QLatin1String("/fontdir");
281
282 if(!QFile::exists(fontpath)) {
283 qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
284 fontpath.toLocal8Bit().constData());
285 }
286
287 const bool loaded = db->loadFromCache(fontpath);
288
289 if (db->reregisterAppFonts) {
290 db->reregisterAppFonts = false;
291 for (int i = 0; i < db->applicationFonts.count(); ++i)
292 if (!db->applicationFonts.at(i).families.isEmpty()) {
293 registerFont(&db->applicationFonts[i]);
294 }
295 }
296
297 if (loaded)
298 return;
299
300 QString dbFileName = qws_fontCacheDir() + QLatin1String("/fontdb");
301
302 QFile binaryDb(dbFileName + QLatin1String(".tmp"));
303 binaryDb.open(QIODevice::WriteOnly | QIODevice::Truncate);
304 db->stream = new QDataStream(&binaryDb);
305 *db->stream << DatabaseVersion << quint8(db->stream->version()) << fontpath;
306// qDebug() << "creating binary database at" << binaryDb.fileName();
307
308 // Load in font definition file
309 FILE* fontdef=fopen(fontDirFile.toLocal8Bit().constData(),"r");
310 if (fontdef) {
311 char buf[200]="";
312 char name[200]="";
313 char render[200]="";
314 char file[200]="";
315 char isitalic[10]="";
316 char flags[10]="";
317 do {
318 fgets(buf,200,fontdef);
319 if (buf[0] != '#') {
320 int weight=50;
321 int size=0;
322 sscanf(buf,"%s %s %s %s %d %d %s",name,file,render,isitalic,&weight,&size,flags);
323 QString filename;
324 if (file[0] != '/')
325 filename.append(fontpath).append(QLatin1Char('/'));
326 filename += QLatin1String(file);
327 bool italic = isitalic[0] == 'y';
328 bool smooth = QByteArray(flags).contains('s');
329 if (file[0] && QFile::exists(filename))
330 db->addFont(QString::fromUtf8(name), /*foundry*/"", weight, italic, size/10, QFile::encodeName(filename), /*fileIndex*/ 0, smooth);
331 }
332 } while (!feof(fontdef));
333 fclose(fontdef);
334 }
335
336
337 QDir dir(fontpath, QLatin1String("*.qpf"));
338 for (int i=0; i<int(dir.count()); i++) {
339 int u0 = dir[i].indexOf(QLatin1Char('_'));
340 int u1 = dir[i].indexOf(QLatin1Char('_'), u0+1);
341 int u2 = dir[i].indexOf(QLatin1Char('_'), u1+1);
342 int u3 = dir[i].indexOf(QLatin1Char('.'), u1+1);
343 if (u2 < 0) u2 = u3;
344
345 QString familyname = dir[i].left(u0);
346 int pixelSize = dir[i].mid(u0+1,u1-u0-1).toInt()/10;
347 bool italic = dir[i].mid(u2-1,1) == QLatin1String("i");
348 int weight = dir[i].mid(u1+1,u2-u1-1-(italic?1:0)).toInt();
349
350 db->addFont(familyname, /*foundry*/ "qt", weight, italic, pixelSize, QFile::encodeName(dir.absoluteFilePath(dir[i])),
351 /*fileIndex*/ 0, /*antialiased*/ true);
352 }
353
354#ifndef QT_NO_FREETYPE
355 dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
356 << QLatin1String("*.ttc") << QLatin1String("*.pfa")
357 << QLatin1String("*.pfb"));
358 dir.refresh();
359 for (int i = 0; i < int(dir.count()); ++i) {
360 const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
361// qDebug() << "looking at" << file;
362 db->addTTFile(file);
363 }
364#endif
365
366#ifndef QT_NO_QWS_QPF2
367 dir.setNameFilters(QStringList() << QLatin1String("*.qpf2"));
368 dir.refresh();
369 for (int i = 0; i < int(dir.count()); ++i) {
370 const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
371// qDebug() << "looking at" << file;
372 db->addQPF2File(file);
373 }
374#endif
375
376#else //QT_FONTS_ARE_RESOURCES
377#ifdef QFONTDATABASE_DEBUG
378 {
379 QResource fontdir(fontpath);
380 FriendlyResource *fr = static_cast<FriendlyResource*>(&fontdir);
381 qDebug() << "fontdir" << fr->isValid() << fr->isDir() << fr->children();
382
383 }
384#endif
385 QDir dir(fontpath, QLatin1String("*.qpf2"));
386 for (int i = 0; i < int(dir.count()); ++i) {
387 const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
388 //qDebug() << "looking at" << file;
389 db->addQPF2File(file);
390 }
391#endif //QT_FONTS_ARE_RESOURCES
392
393
394#ifdef QFONTDATABASE_DEBUG
395 // print the database
396 for (int f = 0; f < db->count; f++) {
397 QtFontFamily *family = db->families[f];
398 FD_DEBUG("'%s' %s", qPrintable(family->name), (family->fixedPitch ? "fixed" : ""));
399#if 0
400 for (int i = 0; i < QFont::LastPrivateScript; ++i) {
401 FD_DEBUG("\t%s: %s", qPrintable(QFontDatabase::scriptName((QFont::Script) i)),
402 ((family->scripts[i] & QtFontFamily::Supported) ? "Supported" :
403 (family->scripts[i] & QtFontFamily::UnSupported) == QtFontFamily::UnSupported ?
404 "UnSupported" : "Unknown"));
405 }
406#endif
407
408 for (int fd = 0; fd < family->count; fd++) {
409 QtFontFoundry *foundry = family->foundries[fd];
410 FD_DEBUG("\t\t'%s'", qPrintable(foundry->name));
411 for (int s = 0; s < foundry->count; s++) {
412 QtFontStyle *style = foundry->styles[s];
413 FD_DEBUG("\t\t\tstyle: style=%d weight=%d\n"
414 "\t\t\tstretch=%d",
415 style->key.style, style->key.weight,
416 style->key.stretch);
417 if (style->smoothScalable)
418 FD_DEBUG("\t\t\t\tsmooth scalable");
419 else if (style->bitmapScalable)
420 FD_DEBUG("\t\t\t\tbitmap scalable");
421 if (style->pixelSizes) {
422 FD_DEBUG("\t\t\t\t%d pixel sizes", style->count);
423 for (int z = 0; z < style->count; ++z) {
424 QtFontSize *size = style->pixelSizes + z;
425 FD_DEBUG("\t\t\t\t size %5d",
426 size->pixelSize);
427 }
428 }
429 }
430 }
431 }
432#endif // QFONTDATABASE_DEBUG
433
434#ifndef QT_NO_LIBRARY
435 QStringList pluginFoundries = loader()->keys();
436// qDebug() << "plugin foundries:" << pluginFoundries;
437 for (int i = 0; i < pluginFoundries.count(); ++i) {
438 const QString foundry(pluginFoundries.at(i));
439
440 QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry));
441 if (!factory) {
442 qDebug() << "Could not load plugin for foundry" << foundry;
443 continue;
444 }
445
446 QList<QFontEngineInfo> fonts = factory->availableFontEngines();
447 for (int i = 0; i < fonts.count(); ++i) {
448 QFontEngineInfo info = fonts.at(i);
449
450 int weight = info.weight();
451 if (weight <= 0)
452 weight = QFont::Normal;
453
454 db->addFont(info.family(), foundry.toLatin1().constData(),
455 weight, info.style() != QFont::StyleNormal,
456 qRound(info.pixelSize()), /*file*/QByteArray(),
457 /*fileIndex*/0, /*antiAliased*/true,
458 info.writingSystems());
459 }
460 }
461#endif
462
463#ifndef QT_FONTS_ARE_RESOURCES
464 // the empty string/familyname signifies the end of the font list.
465 *db->stream << QString();
466#endif
467 {
468 bool coveredWritingSystems[QFontDatabase::WritingSystemsCount] = { 0 };
469
470 db->fallbackFamilies.clear();
471
472 for (int i = 0; i < db->count; ++i) {
473 QtFontFamily *family = db->families[i];
474 bool add = false;
475 if (family->count == 0)
476 continue;
477 if (family->bogusWritingSystems)
478 continue;
479 for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
480 if (coveredWritingSystems[ws])
481 continue;
482 if (family->writingSystems[ws] & QtFontFamily::Supported) {
483 coveredWritingSystems[ws] = true;
484 add = true;
485 }
486 }
487 if (add)
488 db->fallbackFamilies << family->name;
489 }
490 //qDebug() << "fallbacks on the server:" << db->fallbackFamilies;
491#ifndef QT_FONTS_ARE_RESOURCES
492 *db->stream << db->fallbackFamilies;
493#endif
494 }
495#ifndef QT_FONTS_ARE_RESOURCES
496 delete db->stream;
497 db->stream = 0;
498 QFile::remove(dbFileName);
499 binaryDb.rename(dbFileName);
500#endif
501}
502
503// called from qwindowsystem_qws.cpp
504void qt_qws_init_fontdb()
505{
506 initializeDb();
507}
508
509#ifndef QT_NO_SETTINGS
510// called from qapplication_qws.cpp
511void qt_applyFontDatabaseSettings(const QSettings &settings)
512{
513 initializeDb();
514 QFontDatabasePrivate *db = privateDb();
515 for (int i = 0; i < db->count; ++i) {
516 QtFontFamily *family = db->families[i];
517 if (settings.contains(family->name))
518 family->fallbackFamilies = settings.value(family->name).toStringList();
519 }
520
521 if (settings.contains(QLatin1String("Global Fallbacks")))
522 db->fallbackFamilies = settings.value(QLatin1String("Global Fallbacks")).toStringList();
523}
524#endif // QT_NO_SETTINGS
525
526static inline void load(const QString & = QString(), int = -1)
527{
528 initializeDb();
529}
530
531#ifndef QT_NO_FREETYPE
532
533#if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
534#define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
535#define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
536#else
537#define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
538#define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
539#endif
540
541#endif // QT_NO_FREETYPE
542
543static
544QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp,
545 const QFontDef &request,
546 QtFontFamily *family, QtFontFoundry *foundry,
547 QtFontStyle *style, QtFontSize *size)
548{
549 Q_UNUSED(script);
550 Q_UNUSED(fp);
551#ifdef QT_NO_FREETYPE
552 Q_UNUSED(foundry);
553#endif
554#ifdef QT_NO_QWS_QPF
555 Q_UNUSED(family);
556#endif
557 Q_ASSERT(size);
558
559 int pixelSize = size->pixelSize;
560 if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE))
561 pixelSize = request.pixelSize;
562
563#ifndef QT_NO_QWS_QPF2
564 if (foundry->name == QLatin1String("prerendered")) {
565#ifdef QT_FONTS_ARE_RESOURCES
566 QResource res(QLatin1String(size->fileName.constData()));
567 if (res.isValid()) {
568 QFontEngineQPF *fe = new QFontEngineQPF(request, res.data(), res.size());
569 if (fe->isValid())
570 return fe;
571 delete fe;
572 qDebug() << "fontengine is not valid! " << size->fileName;
573 } else {
574 qDebug() << "Resource not valid" << size->fileName;
575 }
576#else
577 int f = ::open(size->fileName, O_RDONLY, 0);
578 if (f >= 0) {
579 QFontEngineQPF *fe = new QFontEngineQPF(request, f);
580 if (fe->isValid())
581 return fe;
582 delete fe; // will close f
583 qDebug() << "fontengine is not valid!";
584 }
585#endif
586 } else
587#endif
588 if ( foundry->name != QLatin1String("qt") ) { ///#### is this the best way????
589 QString file = QFile::decodeName(size->fileName);
590
591 QFontDef def = request;
592 def.pixelSize = pixelSize;
593
594#ifdef QT_NO_QWS_SHARE_FONTS
595 bool shareFonts = false;
596#else
597 static bool dontShareFonts = !qgetenv("QWS_NO_SHARE_FONTS").isEmpty();
598 bool shareFonts = !dontShareFonts;
599#endif
600
601 QScopedPointer<QFontEngine> engine;
602
603#ifndef QT_NO_LIBRARY
604 QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry->name));
605 if (factory) {
606 QFontEngineInfo info;
607 info.setFamily(request.family);
608 info.setPixelSize(request.pixelSize);
609 info.setStyle(QFont::Style(request.style));
610 info.setWeight(request.weight);
611 // #### antialiased
612
613 QAbstractFontEngine *customEngine = factory->create(info);
614 if (customEngine) {
615 engine.reset(new QProxyFontEngine(customEngine, def));
616
617 if (shareFonts) {
618 QVariant hint = customEngine->fontProperty(QAbstractFontEngine::CacheGlyphsHint);
619 if (hint.isValid())
620 shareFonts = hint.toBool();
621 else
622 shareFonts = (pixelSize < 64);
623 }
624 }
625 }
626#endif // QT_NO_LIBRARY
627 if ((engine.isNull() && !file.isEmpty() && QFile::exists(file)) || privateDb()->isApplicationFont(file)) {
628 QFontEngine::FaceId faceId;
629 faceId.filename = file.toLocal8Bit();
630 faceId.index = size->fileIndex;
631
632#ifndef QT_NO_FREETYPE
633
634 QScopedPointer<QFontEngineFT> fte(new QFontEngineFT(def));
635 bool antialias = style->antialiased && !(request.styleStrategy & QFont::NoAntialias);
636 if (fte->init(faceId, antialias,
637 antialias ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono)) {
638#ifdef QT_NO_QWS_QPF2
639 return fte.take();
640#else
641 // try to distinguish between bdf and ttf fonts we can pre-render
642 // and don't try to share outline fonts
643 shareFonts = shareFonts
644 && !fte->defaultGlyphs()->outline_drawing
645 && !fte->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd')).isEmpty();
646 engine.reset(fte.take());
647#endif
648 }
649#endif // QT_NO_FREETYPE
650 }
651 if (!engine.isNull()) {
652#if !defined(QT_NO_QWS_QPF2) && !defined(QT_FONTS_ARE_RESOURCES)
653 if (shareFonts) {
654 QScopedPointer<QFontEngineQPF> fe(new QFontEngineQPF(def, -1, engine.data()));
655 engine.take();
656 if (fe->isValid())
657 return fe.take();
658 qWarning("Initializing QFontEngineQPF failed for %s", qPrintable(file));
659 engine.reset(fe->takeRenderingEngine());
660 }
661#endif
662 return engine.take();
663 }
664 } else
665 {
666#ifndef QT_NO_QWS_QPF
667 QString fn = qwsFontPath();
668 fn += QLatin1Char('/');
669 fn += family->name.toLower()
670 + QLatin1Char('_') + QString::number(pixelSize*10)
671 + QLatin1Char('_') + QString::number(style->key.weight)
672 + (style->key.style == QFont::StyleItalic ?
673 QLatin1String("i.qpf") : QLatin1String(".qpf"));
674 //###rotation ###
675
676 QFontEngine *fe = new QFontEngineQPF1(request, fn);
677 return fe;
678#endif // QT_NO_QWS_QPF
679 }
680 return new QFontEngineBox(pixelSize);
681}
682
683static
684QFontEngine *loadEngine(int script, const QFontPrivate *fp,
685 const QFontDef &request,
686 QtFontFamily *family, QtFontFoundry *foundry,
687 QtFontStyle *style, QtFontSize *size)
688{
689 QScopedPointer<QFontEngine> engine(loadSingleEngine(script, fp, request, family, foundry,
690 style, size));
691 if (!engine.isNull()
692 && script == QUnicodeTables::Common
693 && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
694
695 QStringList fallbacks = privateDb()->fallbackFamilies;
696
697 if (family && !family->fallbackFamilies.isEmpty())
698 fallbacks = family->fallbackFamilies;
699
700 QFontEngine *fe = new QFontEngineMultiQWS(engine.data(), script, fallbacks);
701 engine.take();
702 engine.reset(fe);
703 }
704 return engine.take();
705}
706
707static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
708{
709 QFontDatabasePrivate *db = privateDb();
710#ifdef QT_NO_FREETYPE
711 Q_UNUSED(fnt);
712#else
713 fnt->families = db->addTTFile(QFile::encodeName(fnt->fileName), fnt->data);
714 db->fallbackFamilies += fnt->families;
715#endif
716 db->reregisterAppFonts = true;
717}
718
719bool QFontDatabase::removeApplicationFont(int handle)
720{
721 QMutexLocker locker(fontDatabaseMutex());
722
723 QFontDatabasePrivate *db = privateDb();
724 if (handle < 0 || handle >= db->applicationFonts.count())
725 return false;
726
727 db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
728
729 db->reregisterAppFonts = true;
730 db->invalidate();
731 return true;
732}
733
734bool QFontDatabase::removeAllApplicationFonts()
735{
736 QMutexLocker locker(fontDatabaseMutex());
737
738 QFontDatabasePrivate *db = privateDb();
739 if (db->applicationFonts.isEmpty())
740 return false;
741
742 db->applicationFonts.clear();
743 db->invalidate();
744 return true;
745}
746
747bool QFontDatabase::supportsThreadedFontRendering()
748{
749 return true;
750}
751
752/*!
753 \internal
754*/
755QFontEngine *
756QFontDatabase::findFont(int script, const QFontPrivate *fp,
757 const QFontDef &request)
758{
759 QMutexLocker locker(fontDatabaseMutex());
760
761 const int force_encoding_id = -1;
762
763 if (!privateDb()->count)
764 initializeDb();
765
766 QScopedPointer<QFontEngine> fe;
767 if (fp) {
768 if (fp->rawMode) {
769 fe.reset(loadEngine(script, fp, request, 0, 0, 0, 0));
770
771 // if we fail to load the rawmode font, use a 12pixel box engine instead
772 if (fe.isNull())
773 fe.reset(new QFontEngineBox(12));
774 return fe.take();
775 }
776
777 QFontCache::Key key(request, script);
778 fe.reset(QFontCache::instance()->findEngine(key));
779 if (! fe.isNull())
780 return fe.take();
781 }
782
783 QString family_name, foundry_name;
784 QtFontStyle::Key styleKey;
785 styleKey.style = request.style;
786 styleKey.weight = request.weight;
787 styleKey.stretch = request.stretch;
788 char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
789
790 parseFontName(request.family, foundry_name, family_name);
791
792 FM_DEBUG("QFontDatabase::findFont\n"
793 " request:\n"
794 " family: %s [%s], script: %d\n"
795 " weight: %d, style: %d\n"
796 " stretch: %d\n"
797 " pixelSize: %g\n"
798 " pitch: %c",
799 family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
800 foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
801 script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
802
803 if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
804 fe.reset(new QTestFontEngine(request.pixelSize));
805 fe->fontDef = request;
806 }
807
808 if (fe.isNull())
809 {
810 QtFontDesc desc;
811 match(script, request, family_name, foundry_name, force_encoding_id, &desc);
812
813 if (desc.family != 0 && desc.foundry != 0 && desc.style != 0
814 ) {
815 FM_DEBUG(" BEST:\n"
816 " family: %s [%s]\n"
817 " weight: %d, style: %d\n"
818 " stretch: %d\n"
819 " pixelSize: %d\n"
820 " pitch: %c\n"
821 " encoding: %d\n",
822 desc.family->name.toLatin1().constData(),
823 desc.foundry->name.isEmpty() ? "-- none --" : desc.foundry->name.toLatin1().constData(),
824 desc.style->key.weight, desc.style->key.style,
825 desc.style->key.stretch, desc.size ? desc.size->pixelSize : 0xffff,
826 'p', 0
827 );
828
829 fe.reset(loadEngine(script, fp, request, desc.family, desc.foundry, desc.style, desc.size
830 ));
831 } else {
832 FM_DEBUG(" NO MATCH FOUND\n");
833 }
834 if (! fe.isNull())
835 initFontDef(desc, request, &fe->fontDef);
836 }
837
838#ifndef QT_NO_FREETYPE
839 if (! fe.isNull()) {
840 if (scriptRequiresOpenType(script) && fe->type() == QFontEngine::Freetype) {
841 HB_Face hbFace = static_cast<QFontEngineFT *>(fe.data())->harfbuzzFace();
842 if (!hbFace || !hbFace->supported_scripts[script]) {
843 FM_DEBUG(" OpenType support missing for script\n");
844 fe.reset(0);
845 }
846 }
847 }
848#endif
849
850 if (! fe.isNull()) {
851 if (fp) {
852 QFontDef def = request;
853 if (def.family.isEmpty()) {
854 def.family = fp->request.family;
855 def.family = def.family.left(def.family.indexOf(QLatin1Char(',')));
856 }
857 QFontCache::Key key(def, script);
858 QFontCache::instance()->insertEngine(key, fe.data());
859 }
860 }
861
862 if (fe.isNull()) {
863 if (!request.family.isEmpty())
864 return 0;
865
866 FM_DEBUG("returning box engine");
867
868 fe.reset(new QFontEngineBox(request.pixelSize));
869
870 if (fp) {
871 QFontCache::Key key(request, script);
872 QFontCache::instance()->insertEngine(key, fe.data());
873 }
874 }
875
876 if (fp && fp->dpi > 0) {
877 fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / fp->dpi));
878 } else {
879 fe->fontDef.pointSize = request.pointSize;
880 }
881
882 return fe.take();
883}
884
885void QFontDatabase::load(const QFontPrivate *d, int script)
886{
887 QFontDef req = d->request;
888
889 if (req.pixelSize == -1)
890 req.pixelSize = qRound(req.pointSize*d->dpi/72);
891 if (req.pointSize < 0)
892 req.pointSize = req.pixelSize*72.0/d->dpi;
893
894 if (!d->engineData) {
895 QFontCache::Key key(req, script);
896
897 // look for the requested font in the engine data cache
898 d->engineData = QFontCache::instance()->findEngineData(key);
899
900 if (!d->engineData) {
901 // create a new one
902 d->engineData = new QFontEngineData;
903 QT_TRY {
904 QFontCache::instance()->insertEngineData(key, d->engineData);
905 } QT_CATCH(...) {
906 delete d->engineData;
907 d->engineData = 0;
908 QT_RETHROW;
909 }
910 } else {
911 d->engineData->ref.ref();
912 }
913 }
914
915 // the cached engineData could have already loaded the engine we want
916 if (d->engineData->engines[script]) return;
917
918 // double scale = 1.0; // ### TODO: fix the scale calculations
919
920 // list of families to try
921 QStringList family_list;
922
923 if (!req.family.isEmpty()) {
924 family_list = req.family.split(QLatin1Char(','));
925
926 // append the substitute list for each family in family_list
927 QStringList subs_list;
928 QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
929 for (; it != end; ++it)
930 subs_list += QFont::substitutes(*it);
931 family_list += subs_list;
932
933 // append the default fallback font for the specified script
934 // family_list << ... ; ###########
935
936 // add the default family
937 QString defaultFamily = QApplication::font().family();
938 if (! family_list.contains(defaultFamily))
939 family_list << defaultFamily;
940
941 // add QFont::defaultFamily() to the list, for compatibility with
942 // previous versions
943 family_list << QApplication::font().defaultFamily();
944 }
945
946 // null family means find the first font matching the specified script
947 family_list << QString();
948
949 // load the font
950 QFontEngine *engine = 0;
951 QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
952 for (; !engine && it != end; ++it) {
953 req.family = *it;
954
955 engine = QFontDatabase::findFont(script, d, req);
956 if (engine && (engine->type()==QFontEngine::Box) && !req.family.isEmpty())
957 engine = 0;
958 }
959
960 engine->ref.ref();
961 d->engineData->engines[script] = engine;
962}
963
964
965QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.