source: trunk/src/gui/text/qfontdatabase_s60.cpp@ 561

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

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 17.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <private/qapplication_p.h>
43#include "qdir.h"
44#include "qfont_p.h"
45#include "qfontengine_s60_p.h"
46#include "qabstractfileengine.h"
47#include "qdesktopservices.h"
48#include "qpixmap_s60_p.h"
49#include "qt_s60_p.h"
50#include "qendian.h"
51#include <private/qcore_symbian_p.h>
52#if defined(QT_NO_FREETYPE)
53#include <OPENFONT.H>
54#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
55#include <graphics/openfontrasterizer.h> // COpenFontRasterizer has moved to a new header file
56#endif // SYMBIAN_ENABLE_SPLIT_HEADERS
57#endif
58
59QT_BEGIN_NAMESPACE
60
61QFileInfoList alternativeFilePaths(const QString &path, const QStringList &nameFilters,
62 QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort,
63 bool uniqueFileNames = true)
64{
65 QFileInfoList result;
66
67 // Prepare a 'soft to hard' drive list: W:, X: ... A:, Z:
68 QStringList driveStrings;
69 foreach (const QFileInfo &drive, QDir::drives())
70 driveStrings.append(drive.absolutePath());
71 driveStrings.sort();
72 const QString zDriveString(QLatin1String("Z:/"));
73 driveStrings.removeAll(zDriveString);
74 driveStrings.prepend(zDriveString);
75
76 QStringList uniqueFileNameList;
77 for (int i = driveStrings.count() - 1; i >= 0; --i) {
78 const QDir dirOnDrive(driveStrings.at(i) + path);
79 const QFileInfoList entriesOnDrive = dirOnDrive.entryInfoList(nameFilters, filters, sort);
80 if (uniqueFileNames) {
81 foreach(const QFileInfo &entry, entriesOnDrive) {
82 if (!uniqueFileNameList.contains(entry.fileName())) {
83 uniqueFileNameList.append(entry.fileName());
84 result.append(entry);
85 }
86 }
87 } else {
88 result.append(entriesOnDrive);
89 }
90 }
91 return result;
92}
93
94#if defined(QT_NO_FREETYPE)
95class QFontDatabaseS60StoreImplementation : public QFontDatabaseS60Store
96{
97public:
98 QFontDatabaseS60StoreImplementation();
99 ~QFontDatabaseS60StoreImplementation();
100
101 const QFontEngineS60Extensions *extension(const QString &typeface) const;
102
103private:
104 RHeap* m_heap;
105 CFontStore *m_store;
106 COpenFontRasterizer *m_rasterizer;
107 mutable QHash<QString, const QFontEngineS60Extensions *> m_extensions;
108};
109
110QFontDatabaseS60StoreImplementation::QFontDatabaseS60StoreImplementation()
111{
112 m_heap = User::ChunkHeap(NULL, 0x1000, 0x100000);
113 QT_TRAP_THROWING(
114 m_store = CFontStore::NewL(m_heap);
115 m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E));
116 CleanupStack::PushL(m_rasterizer);
117 m_store->InstallRasterizerL(m_rasterizer);
118 CleanupStack::Pop(m_rasterizer););
119
120 QStringList filters;
121 filters.append(QString::fromLatin1("*.ttf"));
122 filters.append(QString::fromLatin1("*.ccc"));
123 const QFileInfoList fontFiles = alternativeFilePaths(QString::fromLatin1("resource\\Fonts"), filters);
124 foreach (const QFileInfo &fontFileInfo, fontFiles) {
125 const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath());
126 TPtrC fontFilePtr(qt_QString2TPtrC(fontFile));
127 QT_TRAP_THROWING(m_store->AddFileL(fontFilePtr));
128 }
129}
130QFontDatabaseS60StoreImplementation::~QFontDatabaseS60StoreImplementation()
131{
132 typedef QHash<QString, const QFontEngineS60Extensions *>::iterator iterator;
133 for (iterator p = m_extensions.begin(); p != m_extensions.end(); ++p) {
134 m_store->ReleaseFont((*p)->fontOwner());
135 delete *p;
136 }
137
138 delete m_store;
139 m_heap->Close();
140}
141
142#ifndef FNTSTORE_H_INLINES_SUPPORT_FMM
143/*
144 Workaround: fntstore.h has an inlined function 'COpenFont* CBitmapFont::OpenFont()'
145 that returns a private data member. The header will change between SDKs. But Qt has
146 to build on any SDK version and run on other versions of Symbian OS.
147 This function performs the needed pointer arithmetic to get the right COpenFont*
148*/
149COpenFont* OpenFontFromBitmapFont(const CBitmapFont* aBitmapFont)
150{
151 const TInt offsetIOpenFont = 92; // '_FOFF(CBitmapFont, iOpenFont)' ..if iOpenFont weren't private
152 const TUint valueIOpenFont = *(TUint*)PtrAdd(aBitmapFont, offsetIOpenFont);
153 return (valueIOpenFont & 1) ?
154 (COpenFont*)PtrAdd(aBitmapFont, valueIOpenFont & ~1) : // New behavior: iOpenFont is offset
155 (COpenFont*)valueIOpenFont; // Old behavior: iOpenFont is pointer
156}
157#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
158
159const QFontEngineS60Extensions *QFontDatabaseS60StoreImplementation::extension(const QString &typeface) const
160{
161 if (!m_extensions.contains(typeface)) {
162 CFont* font = NULL;
163 TFontSpec spec(qt_QString2TPtrC(typeface), 1);
164 spec.iHeight = 1;
165 const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, spec);
166 Q_ASSERT(err == KErrNone && font);
167 const CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font);
168 COpenFont *openFont =
169#ifdef FNTSTORE_H_INLINES_SUPPORT_FMM
170 bitmapFont->openFont();
171#else
172 OpenFontFromBitmapFont(bitmapFont);
173#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
174 m_extensions.insert(typeface, new QFontEngineS60Extensions(font, openFont));
175 }
176 return m_extensions.value(typeface);
177}
178#else
179class QFontEngineFTS60 : public QFontEngineFT
180{
181public:
182 QFontEngineFTS60(const QFontDef &fd);
183};
184
185QFontEngineFTS60::QFontEngineFTS60(const QFontDef &fd)
186 : QFontEngineFT(fd)
187{
188 default_hint_style = HintFull;
189}
190#endif // defined(QT_NO_FREETYPE)
191
192/*
193 QFontEngineS60::pixelsToPoints, QFontEngineS60::pointsToPixels, QFontEngineMultiS60::QFontEngineMultiS60
194 and QFontEngineMultiS60::QFontEngineMultiS60 should be in qfontengine_s60.cpp. But since also the
195 Freetype based font rendering need them, they are here.
196*/
197qreal QFontEngineS60::pixelsToPoints(qreal pixels, Qt::Orientation orientation)
198{
199 return (orientation == Qt::Horizontal?
200 S60->screenDevice()->HorizontalPixelsToTwips(pixels)
201 :S60->screenDevice()->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint;
202}
203
204qreal QFontEngineS60::pointsToPixels(qreal points, Qt::Orientation orientation)
205{
206 const int twips = points * KTwipsPerPoint;
207 return orientation == Qt::Horizontal?
208 S60->screenDevice()->HorizontalTwipsToPixels(twips)
209 :S60->screenDevice()->VerticalTwipsToPixels(twips);
210}
211
212QFontEngineMultiS60::QFontEngineMultiS60(QFontEngine *first, int script, const QStringList &fallbackFamilies)
213 : QFontEngineMulti(fallbackFamilies.size() + 1)
214 , m_script(script)
215 , m_fallbackFamilies(fallbackFamilies)
216{
217 engines[0] = first;
218 first->ref.ref();
219 fontDef = engines[0]->fontDef;
220}
221
222void QFontEngineMultiS60::loadEngine(int at)
223{
224 Q_ASSERT(at < engines.size());
225 Q_ASSERT(engines.at(at) == 0);
226
227 QFontDef request = fontDef;
228 request.styleStrategy |= QFont::NoFontMerging;
229 request.family = m_fallbackFamilies.at(at-1);
230 engines[at] = QFontDatabase::findFont(m_script,
231 /*fontprivate*/0,
232 request);
233 Q_ASSERT(engines[at]);
234}
235
236static void initializeDb()
237{
238 QFontDatabasePrivate *db = privateDb();
239 if(!db || db->count)
240 return;
241
242#if defined(QT_NO_FREETYPE)
243 if (!db->s60Store)
244 db->s60Store = new QFontDatabaseS60StoreImplementation;
245
246 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
247
248 const int numTypeFaces = QS60Data::screenDevice()->NumTypefaces();
249 const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store);
250 Q_ASSERT(store);
251 bool fontAdded = false;
252 for (int i = 0; i < numTypeFaces; i++) {
253 TTypefaceSupport typefaceSupport;
254 QS60Data::screenDevice()->TypefaceSupport(typefaceSupport, i);
255 CFont *font; // We have to get a font instance in order to know all the details
256 TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11);
257 if (QS60Data::screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone)
258 continue;
259 if (font->TypeUid() == KCFbsFontUid) {
260 TOpenFontFaceAttrib faceAttrib;
261 const CFbsFont *cfbsFont = dynamic_cast<const CFbsFont *>(font);
262 Q_ASSERT(cfbsFont);
263 cfbsFont->GetFaceAttrib(faceAttrib);
264
265 QtFontStyle::Key styleKey;
266 styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal;
267 styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal;
268
269 QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
270 QtFontFamily *family = db->family(familyName, true);
271 family->fixedPitch = faceAttrib.IsMonoWidth();
272 QtFontFoundry *foundry = family->foundry(QString(), true);
273 QtFontStyle *style = foundry->style(styleKey, true);
274 style->smoothScalable = typefaceSupport.iIsScalable;
275 style->pixelSize(0, true);
276
277 const QFontEngineS60Extensions *extension = store->extension(familyName);
278 const QByteArray os2Table = extension->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
279 const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData());
280 const unsigned char* ulUnicodeRange = data + 42;
281 quint32 unicodeRange[4] = {
282 qFromBigEndian<quint32>(ulUnicodeRange),
283 qFromBigEndian<quint32>(ulUnicodeRange + 4),
284 qFromBigEndian<quint32>(ulUnicodeRange + 8),
285 qFromBigEndian<quint32>(ulUnicodeRange + 12)
286 };
287 const unsigned char* ulCodePageRange = data + 78;
288 quint32 codePageRange[2] = {
289 qFromBigEndian<quint32>(ulCodePageRange),
290 qFromBigEndian<quint32>(ulCodePageRange + 4)
291 };
292 const QList<QFontDatabase::WritingSystem> writingSystems =
293 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
294 foreach (const QFontDatabase::WritingSystem system, writingSystems)
295 family->writingSystems[system] = QtFontFamily::Supported;
296
297 fontAdded = true;
298 }
299 QS60Data::screenDevice()->ReleaseFont(font);
300 }
301
302 Q_ASSERT(fontAdded);
303
304 lock.relock();
305
306#else // defined(QT_NO_FREETYPE)
307 QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation));
308 dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
309 << QLatin1String("*.ttc") << QLatin1String("*.pfa")
310 << QLatin1String("*.pfb"));
311 for (int i = 0; i < int(dir.count()); ++i) {
312 const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
313 db->addTTFile(file);
314 }
315#endif // defined(QT_NO_FREETYPE)
316}
317
318static inline void load(const QString &family = QString(), int script = -1)
319{
320 Q_UNUSED(family)
321 Q_UNUSED(script)
322 initializeDb();
323}
324
325static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
326{
327 Q_UNUSED(fnt);
328}
329
330bool QFontDatabase::removeApplicationFont(int handle)
331{
332 Q_UNUSED(handle);
333 return false;
334}
335
336bool QFontDatabase::supportsThreadedFontRendering()
337{
338 return false;
339}
340
341static
342QFontDef cleanedFontDef(const QFontDef &req)
343{
344 QFontDef result = req;
345 if (result.pixelSize <= 0) {
346 result.pixelSize = QFontEngineS60::pointsToPixels(qMax(qreal(1.0), result.pointSize));
347 result.pointSize = 0;
348 }
349 return result;
350}
351
352QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *, const QFontDef &req)
353{
354 const QFontCache::Key key(cleanedFontDef(req), script);
355
356 if (!privateDb()->count)
357 initializeDb();
358
359 QFontEngine *fe = QFontCache::instance()->findEngine(key);
360 if (!fe) {
361 // Making sure that fe->fontDef.family will be an existing font.
362 initializeDb();
363 QFontDatabasePrivate *db = privateDb();
364 QtFontDesc desc;
365 QList<int> blacklistedFamilies;
366 match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies);
367 if (!desc.family) // falling back to application font
368 desc.family = db->family(QApplication::font().defaultFamily());
369 Q_ASSERT(desc.family);
370
371 // Making sure that desc.family supports the requested script
372 QtFontDesc mappedDesc;
373 bool supportsScript = false;
374 do {
375 match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
376 if (mappedDesc.family == desc.family) {
377 supportsScript = true;
378 break;
379 }
380 blacklistedFamilies.append(mappedDesc.familyIndex);
381 } while (mappedDesc.family);
382 if (!supportsScript) {
383 blacklistedFamilies.clear();
384 match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
385 if (mappedDesc.family)
386 desc = mappedDesc;
387 }
388
389 const QString fontFamily = desc.family->name;
390 QFontDef request = req;
391 request.family = fontFamily;
392#if defined(QT_NO_FREETYPE)
393 const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store);
394 Q_ASSERT(store);
395 const QFontEngineS60Extensions *extension = store->extension(fontFamily);
396 fe = new QFontEngineS60(request, extension);
397#else
398 QFontEngine::FaceId faceId;
399 const QtFontFamily * const reqQtFontFamily = db->family(fontFamily);
400 faceId.filename = reqQtFontFamily->fontFilename;
401 faceId.index = reqQtFontFamily->fontFileIndex;
402
403 QFontEngineFTS60 *fte = new QFontEngineFTS60(cleanedFontDef(request));
404 if (fte->init(faceId, true, QFontEngineFT::Format_A8))
405 fe = fte;
406 else
407 delete fte;
408#endif
409
410 Q_ASSERT(fe);
411 if (script == QUnicodeTables::Common
412 && !(req.styleStrategy & QFont::NoFontMerging)
413 && !fe->symbol) {
414
415 QStringList commonFonts;
416 for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
417 if (scriptForWritingSystem[ws] != script)
418 continue;
419 for (int i = 0; i < db->count; ++i) {
420 if (db->families[i]->writingSystems[ws] & QtFontFamily::Supported)
421 commonFonts.append(db->families[i]->name);
422 }
423 }
424
425 // Hack: Prioritize .ccc fonts
426 const QString niceEastAsianFont(QLatin1String("Sans MT 936_S60"));
427 if (commonFonts.removeAll(niceEastAsianFont) > 0)
428 commonFonts.prepend(niceEastAsianFont);
429
430 fe = new QFontEngineMultiS60(fe, script, commonFonts);
431 }
432 }
433 fe->ref.ref();
434 QFontCache::instance()->insertEngine(key, fe);
435 return fe;
436}
437
438void QFontDatabase::load(const QFontPrivate *d, int script)
439{
440 QFontEngine *fe = 0;
441 QFontDef req = d->request;
442
443 if (!d->engineData) {
444 const QFontCache::Key key(cleanedFontDef(req), script);
445 getEngineData(d, key);
446 }
447
448 // the cached engineData could have already loaded the engine we want
449 if (d->engineData->engines[script])
450 fe = d->engineData->engines[script];
451
452 if (!fe) {
453 if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
454 fe = new QTestFontEngine(req.pixelSize);
455 fe->fontDef = req;
456 } else {
457 fe = findFont(script, d, req);
458 }
459 d->engineData->engines[script] = fe;
460 }
461}
462
463QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.