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

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

gui: Fixed: Hack to enable all scripts for the Workplace Sans font didn't work.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Date Revision Author Id
File size: 26.5 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 "qabstractfileengine.h"
45
46#include "qfontengine_pm_p.h"
47
48#include "qsettings.h"
49#include "qfileinfo.h"
50#include "qdatetime.h"
51#include "qhash.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
59QT_BEGIN_NAMESPACE
60
61struct FaceData
62{
63 int index;
64 QString familyName;
65 QtFontStyle::Key styleKey;
66 QList<QFontDatabase::WritingSystem> systems;
67 bool fixedPitch;
68 bool smoothScalable;
69 QList<unsigned short> pixelSizes;
70};
71
72static QDataStream &operator<<(QDataStream &data, const QFontDatabase::WritingSystem &ws)
73{
74 data << (int)ws;
75 return data;
76}
77
78static QDataStream &operator>>(QDataStream &data, QFontDatabase::WritingSystem &ws)
79{
80 data >> (int&)ws;
81 return data;
82}
83
84static QDataStream &operator<<(QDataStream &data, const FaceData &cached)
85{
86 data << cached.familyName;
87 data << cached.styleKey.style << cached.styleKey.weight
88 << cached.styleKey.stretch;
89 data << cached.systems;
90 data << cached.fixedPitch << cached.smoothScalable;
91 data << cached.pixelSizes;
92 return data;
93}
94
95static QDataStream &operator>>(QDataStream &data, FaceData &cached)
96{
97 data >> cached.familyName;
98 uint style;
99 int weight, stretch;
100 data >> style; cached.styleKey.style = style;
101 data >> weight; cached.styleKey.weight = weight;
102 data >> stretch; cached.styleKey.stretch = stretch;
103 data >> cached.systems;
104 data >> cached.fixedPitch >> cached.smoothScalable;
105 data >> cached.pixelSizes;
106 return data;
107}
108
109struct FileData
110{
111 FileData() : seen(false) {}
112 FileData(const QFileInfo &fi, bool s) : fileInfo(fi), seen(s) {}
113
114 QFileInfo fileInfo;
115 bool seen;
116};
117
118typedef QHash<QString, FileData> FontFileHash;
119static FontFileHash knownFontFiles;
120static bool knownFontFilesInitialized = false;
121
122static void populateDatabase(const QString& fam)
123{
124 QFontDatabasePrivate *db = privateDb();
125 if (!db)
126 return;
127
128 QtFontFamily *family = 0;
129 if(!fam.isEmpty()) {
130 family = db->family(fam);
131 if(family)
132 return;
133 } else if (db->count) {
134 return;
135 }
136
137 // we don't recognize foundries on OS/2, use an empty one
138 const QString foundryName;
139
140#ifdef QFONTDATABASE_DEBUG
141 QTime timer;
142 timer.start();
143#endif
144
145 QSettings fontCache(QSettings::UserScope, QLatin1String("Trolltech"));
146 fontCache.beginGroup(QLatin1String("Qt/Fonts/Cache 1.0"));
147
148 if (!knownFontFilesInitialized) {
149 // get the initial list of know font files from the cache (necessary to
150 // detect deleted font files)
151 knownFontFilesInitialized = true;
152 QStringList files = fontCache.childGroups();
153 foreach(QString file, files) {
154 file.replace("|", "/");
155 knownFontFiles.insert(file, FileData());
156 // note that QFileInfo is empty so the file will be considered as
157 // NEW which is necessary for the font to get into the database
158 }
159 } else {
160 // reset the 'seen' flag
161 for (FontFileHash::iterator it = knownFontFiles.begin();
162 it != knownFontFiles.end(); ++it)
163 it.value().seen = false;
164 }
165
166 QList<QFileInfo> fontFiles;
167
168 ULONG bufSize = 0;
169 BOOL ok = PrfQueryProfileSize(HINI_USERPROFILE, "PM_Fonts", 0, &bufSize);
170 Q_ASSERT(ok);
171 if (ok) {
172 char *buffer = new char[bufSize + 1 /*terminating NULL*/];
173 Q_ASSERT(buffer);
174 if (buffer) {
175 ULONG bufLen = PrfQueryProfileString(HINI_USERPROFILE, "PM_Fonts", 0, 0,
176 buffer, bufSize);
177 if (bufLen) {
178 char *key = buffer;
179 while (*key) {
180 ULONG keySize = 0;
181 ok = PrfQueryProfileSize(HINI_USERPROFILE, "PM_Fonts", key,
182 &keySize);
183 if (ok) {
184 QByteArray file(keySize, 0);
185 ULONG keyLen =
186 PrfQueryProfileString(HINI_USERPROFILE, "PM_Fonts", key, 0,
187 file.data(), file.size());
188 file.truncate(keyLen - 1 /*terminating NULL*/);
189 if (!file.isEmpty()) {
190 // FreeType doesn't understand .OFM but understands .PFB
191 if (file.toUpper().endsWith(".OFM")) {
192 file.chop(4);
193 file.append(".PFB");
194 }
195 QFileInfo fileInfo(QFile::decodeName(file));
196 QString fileName = fileInfo.canonicalFilePath().toLower();
197 if (!fileName.isEmpty()) { // file may have been deleted
198 fileInfo.setFile(fileName);
199 // check the in-process file name cache
200 FileData &cached = knownFontFiles[fileName];
201 if (cached.fileInfo.filePath().isEmpty() ||
202 cached.fileInfo.lastModified() != fileInfo.lastModified() ||
203 cached.fileInfo.size() != fileInfo.size()) {
204 // no cache entry or outdated, process it
205 cached.fileInfo = fileInfo;
206 cached.seen = true;
207 fontFiles << fileInfo;
208 FD_DEBUG("populateDatabase: NEW/UPDATED font file %s",
209 qPrintable(fileName));
210 } else {
211 // just set the 'seen' flag and skip this font
212 // (it's already in the database)
213 knownFontFiles[fileName].seen = true;
214 FD_DEBUG("populateDatabase: UNCHANGED font file %s",
215 qPrintable(fileName));
216 }
217 }
218 }
219 }
220 key += strlen(key) + 1;
221 }
222 }
223 delete buffer;
224 }
225 }
226
227 extern FT_Library qt_getFreetype(); // qfontengine_ft.cpp
228 FT_Library lib = qt_getFreetype();
229
230 // go through each font file and get available faces
231 foreach(const QFileInfo &fileInfo, fontFiles) {
232 QString fileKey = fileInfo.absoluteFilePath().toLower();
233 QByteArray file = QFile::encodeName(fileKey);
234
235 // QSettings uses / for splitting into groups, suppress it
236 fileKey.replace("/", "|");
237
238 QList<FaceData> cachedFaces;
239
240 // first, look up the cached data
241 fontCache.beginGroup(fileKey);
242
243 if (fontCache.value(QLatin1String("DateTime")).toDateTime() != fileInfo.lastModified() ||
244 fontCache.value(QLatin1String("Size")).toUInt() != fileInfo.size()) {
245 // the cache is outdated or doesn't exist, query the font file
246
247 FT_Long numFaces = 0;
248 FT_Face face;
249
250 FT_Error rc = FT_New_Face(lib, file, -1, &face);
251 if (rc == 0) {
252 numFaces = face->num_faces;
253 FT_Done_Face(face);
254 } else {
255 // invalid/unsupported font file, numFaces is left 0 so that
256 // only DateTime and Size will be cached indicating that this
257 // file is not recognized
258 }
259
260 FD_DEBUG("populateDatabase: Font file %s: FT error %d, has %ld faces",
261 file.constData(), (int) rc, numFaces);
262
263 // go throuhg each face
264 for (FT_Long idx = 0; idx < numFaces; ++idx) {
265 rc = FT_New_Face(lib, file, idx, &face);
266 if (rc != 0)
267 continue;
268
269 FaceData cached;
270
271 cached.index = idx;
272 cached.familyName = QString::fromLatin1(face->family_name);
273
274 // familyName may contain extra spaces (at least this is true for
275 // TNR.PFB that is reported as "Times New Roman ". Trim them.
276 cached.familyName = cached.familyName.trimmed();
277
278 cached.styleKey.style = face->style_flags & FT_STYLE_FLAG_ITALIC ?
279 QFont::StyleItalic : QFont::StyleNormal;
280
281 TT_OS2 *os2_table = 0;
282 if (face->face_flags & FT_FACE_FLAG_SFNT) {
283 os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
284 }
285 if (os2_table) {
286 // map weight and width values
287 if (os2_table->usWeightClass < 400)
288 cached.styleKey.weight = QFont::Light;
289 else if (os2_table->usWeightClass < 600)
290 cached.styleKey.weight = QFont::Normal;
291 else if (os2_table->usWeightClass < 700)
292 cached.styleKey.weight = QFont::DemiBold;
293 else if (os2_table->usWeightClass < 800)
294 cached.styleKey.weight = QFont::Bold;
295 else
296 cached.styleKey.weight = QFont::Black;
297
298 switch (os2_table->usWidthClass) {
299 case 1: cached.styleKey.stretch = QFont::UltraCondensed; break;
300 case 2: cached.styleKey.stretch = QFont::ExtraCondensed; break;
301 case 3: cached.styleKey.stretch = QFont::Condensed; break;
302 case 4: cached.styleKey.stretch = QFont::SemiCondensed; break;
303 case 5: cached.styleKey.stretch = QFont::Unstretched; break;
304 case 6: cached.styleKey.stretch = QFont::SemiExpanded; break;
305 case 7: cached.styleKey.stretch = QFont::Expanded; break;
306 case 8: cached.styleKey.stretch = QFont::ExtraExpanded; break;
307 case 9: cached.styleKey.stretch = QFont::UltraExpanded; break;
308 default: cached.styleKey.stretch = QFont::Unstretched; break;
309 }
310
311 quint32 unicodeRange[4] = {
312 os2_table->ulUnicodeRange1, os2_table->ulUnicodeRange2,
313 os2_table->ulUnicodeRange3, os2_table->ulUnicodeRange4
314 };
315 quint32 codePageRange[2] = {
316 os2_table->ulCodePageRange1, os2_table->ulCodePageRange2