author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Fri, 19 Feb 2010 23:40:16 +0200 | |
branch | RCL_3 |
changeset 4 | 3b1da2848fc7 |
parent 0 | 1918ee327afb |
child 30 | 5dc02b23752f |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 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 |
** No Commercial Usage |
|
11 |
** This file contains pre-release code and may not be distributed. |
|
12 |
** You may use this file in accordance with the terms and conditions |
|
13 |
** contained in the Technology Preview License Agreement accompanying |
|
14 |
** this package. |
|
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 |
** If you have questions regarding the use of this file, please contact |
|
29 |
** Nokia at qt-info@nokia.com. |
|
30 |
** |
|
31 |
** |
|
32 |
** |
|
33 |
** |
|
34 |
** |
|
35 |
** |
|
36 |
** |
|
37 |
** |
|
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 |
||
76 |
QT_BEGIN_NAMESPACE |
|
77 |
||
78 |
#ifndef QT_NO_LIBRARY |
|
79 |
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, |
|
80 |
(QFontEngineFactoryInterface_iid, QLatin1String("/fontengines"), Qt::CaseInsensitive)) |
|
81 |
#endif |
|
82 |
||
83 |
const quint8 DatabaseVersion = 4; |
|
84 |
||
85 |
// QFontDatabasePrivate::addFont() went into qfontdatabase.cpp |
|
86 |
||
87 |
#ifndef QT_NO_QWS_QPF2 |
|
88 |
void 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 |
||
149 |
static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt); |
|
150 |
||
151 |
extern QString qws_fontCacheDir(); |
|
152 |
||
153 |
#ifndef QT_FONTS_ARE_RESOURCES |
|
154 |
bool 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 |
||
241 |
static 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) |
|
261 |
class FriendlyResource : public QResource |
|
262 |
{ |
|
263 |
public: |
|
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 |
*/ |
|
272 |
static 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 |
|
504 |
void qt_qws_init_fontdb() |
|
505 |
{ |
|
506 |
initializeDb(); |
|
507 |
} |
|
508 |
||
509 |
#ifndef QT_NO_SETTINGS |
|
510 |
// called from qapplication_qws.cpp |
|
511 |
void 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 |
||
526 |
static 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 |
||
543 |
static |
|
544 |
QFontEngine *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 |
if (fte->init(faceId, style->antialiased, |
|
636 |
style->antialiased ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono)) { |
|
637 |
#ifdef QT_NO_QWS_QPF2 |
|
638 |
return fte.take(); |
|
639 |
#else |
|
640 |
// try to distinguish between bdf and ttf fonts we can pre-render |
|
641 |
// and don't try to share outline fonts |
|
642 |
shareFonts = shareFonts |
|
643 |
&& !fte->defaultGlyphs()->outline_drawing |
|
644 |
&& !fte->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd')).isEmpty(); |
|
645 |
engine.reset(fte.take()); |
|
646 |
#endif |
|
647 |
} |
|
648 |
#endif // QT_NO_FREETYPE |
|
649 |
} |
|
650 |
if (!engine.isNull()) { |
|
651 |
#if !defined(QT_NO_QWS_QPF2) && !defined(QT_FONTS_ARE_RESOURCES) |
|
652 |
if (shareFonts) { |
|
653 |
QScopedPointer<QFontEngineQPF> fe(new QFontEngineQPF(def, -1, engine.data())); |
|
654 |
engine.take(); |
|
655 |
if (fe->isValid()) |
|
656 |
return fe.take(); |
|
657 |
qWarning("Initializing QFontEngineQPF failed for %s", qPrintable(file)); |
|
658 |
engine.reset(fe->takeRenderingEngine()); |
|
659 |
} |
|
660 |
#endif |
|
661 |
return engine.take(); |
|
662 |
} |
|
663 |
} else |
|
664 |
{ |
|
665 |
#ifndef QT_NO_QWS_QPF |
|
666 |
QString fn = qwsFontPath(); |
|
667 |
fn += QLatin1Char('/'); |
|
668 |
fn += family->name.toLower() |
|
669 |
+ QLatin1Char('_') + QString::number(pixelSize*10) |
|
670 |
+ QLatin1Char('_') + QString::number(style->key.weight) |
|
671 |
+ (style->key.style == QFont::StyleItalic ? |
|
672 |
QLatin1String("i.qpf") : QLatin1String(".qpf")); |
|
673 |
//###rotation ### |
|
674 |
||
675 |
QFontEngine *fe = new QFontEngineQPF1(request, fn); |
|
676 |
return fe; |
|
677 |
#endif // QT_NO_QWS_QPF |
|
678 |
} |
|
679 |
return new QFontEngineBox(pixelSize); |
|
680 |
} |
|
681 |
||
682 |
static |
|
683 |
QFontEngine *loadEngine(int script, const QFontPrivate *fp, |
|
684 |
const QFontDef &request, |
|
685 |
QtFontFamily *family, QtFontFoundry *foundry, |
|
686 |
QtFontStyle *style, QtFontSize *size) |
|
687 |
{ |
|
688 |
QScopedPointer<QFontEngine> engine(loadSingleEngine(script, fp, request, family, foundry, |
|
689 |
style, size)); |
|
690 |
if (!engine.isNull() |
|
691 |
&& script == QUnicodeTables::Common |
|
692 |
&& !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) { |
|
693 |
||
694 |
QStringList fallbacks = privateDb()->fallbackFamilies; |
|
695 |
||
696 |
if (family && !family->fallbackFamilies.isEmpty()) |
|
697 |
fallbacks = family->fallbackFamilies; |
|
698 |
||
699 |
QFontEngine *fe = new QFontEngineMultiQWS(engine.data(), script, fallbacks); |
|
700 |
engine.take(); |
|
701 |
engine.reset(fe); |
|
702 |
} |
|
703 |
return engine.take(); |
|
704 |
} |
|
705 |
||
706 |
static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) |
|
707 |
{ |
|
708 |
QFontDatabasePrivate *db = privateDb(); |
|
709 |
#ifdef QT_NO_FREETYPE |
|
710 |
Q_UNUSED(fnt); |
|
711 |
#else |
|
712 |
fnt->families = db->addTTFile(QFile::encodeName(fnt->fileName), fnt->data); |
|
713 |
db->fallbackFamilies += fnt->families; |
|
714 |
#endif |
|
715 |
db->reregisterAppFonts = true; |
|
716 |
} |
|
717 |
||
718 |
bool QFontDatabase::removeApplicationFont(int handle) |
|
719 |
{ |
|
720 |
QMutexLocker locker(fontDatabaseMutex()); |
|
721 |
||
722 |
QFontDatabasePrivate *db = privateDb(); |
|
723 |
if (handle < 0 || handle >= db->applicationFonts.count()) |
|
724 |
return false; |
|
725 |
||
726 |
db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont(); |
|
727 |
||
728 |
db->reregisterAppFonts = true; |
|
729 |
db->invalidate(); |
|
730 |
return true; |
|
731 |
} |
|
732 |
||
733 |
bool QFontDatabase::removeAllApplicationFonts() |
|
734 |
{ |
|
735 |
QMutexLocker locker(fontDatabaseMutex()); |
|
736 |
||
737 |
QFontDatabasePrivate *db = privateDb(); |
|
738 |
if (db->applicationFonts.isEmpty()) |
|
739 |
return false; |
|
740 |
||
741 |
db->applicationFonts.clear(); |
|
742 |
db->invalidate(); |
|
743 |
return true; |
|
744 |
} |
|
745 |
||
746 |
bool QFontDatabase::supportsThreadedFontRendering() |
|
747 |
{ |
|
748 |
return true; |
|
749 |
} |
|
750 |
||
751 |
/*! |
|
752 |
\internal |
|
753 |
*/ |
|
754 |
QFontEngine * |
|
755 |
QFontDatabase::findFont(int script, const QFontPrivate *fp, |
|
756 |
const QFontDef &request) |
|
757 |
{ |
|
758 |
QMutexLocker locker(fontDatabaseMutex()); |
|
759 |
||
760 |
const int force_encoding_id = -1; |
|
761 |
||
762 |
if (!privateDb()->count) |
|
763 |
initializeDb(); |
|
764 |
||
765 |
QScopedPointer<QFontEngine> fe; |
|
766 |
if (fp) { |
|
767 |
if (fp->rawMode) { |
|
768 |
fe.reset(loadEngine(script, fp, request, 0, 0, 0, 0)); |
|
769 |
||
770 |
// if we fail to load the rawmode font, use a 12pixel box engine instead |
|
771 |
if (fe.isNull()) |
|
772 |
fe.reset(new QFontEngineBox(12)); |
|
773 |
return fe.take(); |
|
774 |
} |
|
775 |
||
776 |
QFontCache::Key key(request, script); |
|
777 |
fe.reset(QFontCache::instance()->findEngine(key)); |
|
778 |
if (! fe.isNull()) |
|
779 |
return fe.take(); |
|
780 |
} |
|
781 |
||
782 |
QString family_name, foundry_name; |
|
783 |
QtFontStyle::Key styleKey; |
|
784 |
styleKey.style = request.style; |
|
785 |
styleKey.weight = request.weight; |
|
786 |
styleKey.stretch = request.stretch; |
|
787 |
char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p'; |
|
788 |
||
789 |
parseFontName(request.family, foundry_name, family_name); |
|
790 |
||
791 |
FM_DEBUG("QFontDatabase::findFont\n" |
|
792 |
" request:\n" |
|
793 |
" family: %s [%s], script: %d\n" |
|
794 |
" weight: %d, style: %d\n" |
|
795 |
" stretch: %d\n" |
|
796 |
" pixelSize: %d\n" |
|
797 |
" pitch: %c", |
|
798 |
family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(), |
|
799 |
foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(), |
|
800 |
script, request.weight, request.style, request.stretch, request.pixelSize, pitch); |
|
801 |
||
802 |
if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) { |
|
803 |
fe.reset(new QTestFontEngine(request.pixelSize)); |
|
804 |
fe->fontDef = request; |
|
805 |
} |
|
806 |
||
807 |
if (fe.isNull()) |
|
808 |
{ |
|
809 |
QtFontDesc desc; |
|
810 |
match(script, request, family_name, foundry_name, force_encoding_id, &desc); |
|
811 |
||
812 |
if (desc.family != 0 && desc.foundry != 0 && desc.style != 0 |
|
813 |
) { |
|
814 |
FM_DEBUG(" BEST:\n" |
|
815 |
" family: %s [%s]\n" |
|
816 |
" weight: %d, style: %d\n" |
|
817 |
" stretch: %d\n" |
|
818 |
" pixelSize: %d\n" |
|
819 |
" pitch: %c\n" |
|
820 |
" encoding: %d\n", |
|
821 |
desc.family->name.toLatin1().constData(), |
|
822 |
desc.foundry->name.isEmpty() ? "-- none --" : desc.foundry->name.toLatin1().constData(), |
|
823 |
desc.style->key.weight, desc.style->key.style, |
|
824 |
desc.style->key.stretch, desc.size ? desc.size->pixelSize : 0xffff, |
|
825 |
'p', 0 |
|
826 |
); |
|
827 |
||
828 |
fe.reset(loadEngine(script, fp, request, desc.family, desc.foundry, desc.style, desc.size |
|
829 |
)); |
|
830 |
} else { |
|
831 |
FM_DEBUG(" NO MATCH FOUND\n"); |
|
832 |
} |
|
833 |
if (! fe.isNull()) |
|
834 |
initFontDef(desc, request, &fe->fontDef); |
|
835 |
} |
|
836 |
||
837 |
#ifndef QT_NO_FREETYPE |
|
838 |
if (! fe.isNull()) { |
|
839 |
if (scriptRequiresOpenType(script) && fe->type() == QFontEngine::Freetype) { |
|
840 |
HB_Face hbFace = static_cast<QFontEngineFT *>(fe.data())->harfbuzzFace(); |
|
841 |
if (!hbFace || !hbFace->supported_scripts[script]) { |
|
842 |
FM_DEBUG(" OpenType support missing for script\n"); |
|
843 |
fe.reset(0); |
|
844 |
} |
|
845 |
} |
|
846 |
} |
|
847 |
#endif |
|
848 |
||
849 |
if (! fe.isNull()) { |
|
850 |
if (fp) { |
|
851 |
QFontDef def = request; |
|
852 |
if (def.family.isEmpty()) { |
|
853 |
def.family = fp->request.family; |
|
854 |
def.family = def.family.left(def.family.indexOf(QLatin1Char(','))); |
|
855 |
} |
|
856 |
QFontCache::Key key(def, script); |
|
857 |
QFontCache::instance()->insertEngine(key, fe.data()); |
|
858 |
} |
|
859 |
} |
|
860 |
||
861 |
if (fe.isNull()) { |
|
862 |
if (!request.family.isEmpty()) |
|
863 |
return 0; |
|
864 |
||
865 |
FM_DEBUG("returning box engine"); |
|
866 |
||
867 |
fe.reset(new QFontEngineBox(request.pixelSize)); |
|
868 |
||
869 |
if (fp) { |
|
870 |
QFontCache::Key key(request, script); |
|
871 |
QFontCache::instance()->insertEngine(key, fe.data()); |
|
872 |
} |
|
873 |
} |
|
874 |
||
875 |
if (fp && fp->dpi > 0) { |
|
876 |
fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / fp->dpi)); |
|
877 |
} else { |
|
878 |
fe->fontDef.pointSize = request.pointSize; |
|
879 |
} |
|
880 |
||
881 |
return fe.take(); |
|
882 |
} |
|
883 |
||
884 |
void QFontDatabase::load(const QFontPrivate *d, int script) |
|
885 |
{ |
|
886 |
QFontDef req = d->request; |
|
887 |
||
888 |
if (req.pixelSize == -1) |
|
889 |
req.pixelSize = qRound(req.pointSize*d->dpi/72); |
|
890 |
if (req.pointSize < 0) |
|
891 |
req.pointSize = req.pixelSize*72.0/d->dpi; |
|
892 |
||
893 |
if (!d->engineData) { |
|
894 |
QFontCache::Key key(req, script); |
|
895 |
||
896 |
// look for the requested font in the engine data cache |
|
897 |
d->engineData = QFontCache::instance()->findEngineData(key); |
|
898 |
||
899 |
if (!d->engineData) { |
|
900 |
// create a new one |
|
901 |
d->engineData = new QFontEngineData; |
|
902 |
QT_TRY { |
|
903 |
QFontCache::instance()->insertEngineData(key, d->engineData); |
|
904 |
} QT_CATCH(...) { |
|
905 |
delete d->engineData; |
|
906 |
d->engineData = 0; |
|
907 |
QT_RETHROW; |
|
908 |
} |
|
909 |
} else { |
|
910 |
d->engineData->ref.ref(); |
|
911 |
} |
|
912 |
} |
|
913 |
||
914 |
// the cached engineData could have already loaded the engine we want |
|
915 |
if (d->engineData->engines[script]) return; |
|
916 |
||
917 |
// double scale = 1.0; // ### TODO: fix the scale calculations |
|
918 |
||
919 |
// list of families to try |
|
920 |
QStringList family_list; |
|
921 |
||
922 |
if (!req.family.isEmpty()) { |
|
923 |
family_list = req.family.split(QLatin1Char(',')); |
|
924 |
||
925 |
// append the substitute list for each family in family_list |
|
926 |
QStringList subs_list; |
|
927 |
QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd(); |
|
928 |
for (; it != end; ++it) |
|
929 |
subs_list += QFont::substitutes(*it); |
|
930 |
family_list += subs_list; |
|
931 |
||
932 |
// append the default fallback font for the specified script |
|
933 |
// family_list << ... ; ########### |
|
934 |
||
935 |
// add the default family |
|
936 |
QString defaultFamily = QApplication::font().family(); |
|
937 |
if (! family_list.contains(defaultFamily)) |
|
938 |
family_list << defaultFamily; |
|
939 |
||
940 |
// add QFont::defaultFamily() to the list, for compatibility with |
|
941 |
// previous versions |
|
942 |
family_list << QApplication::font().defaultFamily(); |
|
943 |
} |
|
944 |
||
945 |
// null family means find the first font matching the specified script |
|
946 |
family_list << QString(); |
|
947 |
||
948 |
// load the font |
|
949 |
QFontEngine *engine = 0; |
|
950 |
QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd(); |
|
951 |
for (; !engine && it != end; ++it) { |
|
952 |
req.family = *it; |
|
953 |
||
954 |
engine = QFontDatabase::findFont(script, d, req); |
|
955 |
if (engine && (engine->type()==QFontEngine::Box) && !req.family.isEmpty()) |
|
956 |
engine = 0; |
|
957 |
} |
|
958 |
||
959 |
engine->ref.ref(); |
|
960 |
d->engineData->engines[script] = engine; |
|
961 |
} |
|
962 |
||
963 |
||
964 |
QT_END_NAMESPACE |