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

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

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 17.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 =
250 static_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store);
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 = static_cast<const CFbsFont *>(font);
262 cfbsFont->GetFaceAttrib(faceAttrib);
263
264 QtFontStyle::Key styleKey;
265 styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal;
266 styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal;
267
268 QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
269 QtFontFamily *family = db->family(familyName, true);
270 family->fixedPitch = faceAttrib.IsMonoWidth();
271 QtFontFoundry *foundry = family->foundry(QString(), true);
272 QtFontStyle *style = foundry->style(styleKey, true);
273 style->smoothScalable = typefaceSupport.iIsScalable;
274 style->pixelSize(0, true);
275
276 const QFontEngineS60Extensions *extension = store->extension(familyName);
277 const QByteArray os2Table = extension->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
278 const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData());
279 const unsigned char* ulUnicodeRange = data + 42;
280 quint32 unicodeRange[4] = {
281 qFromBigEndian<quint32>(ulUnicodeRange),
282 qFromBigEndian<quint32>(ulUnicodeRange + 4),
283 qFromBigEndian<quint32>(ulUnicodeRange + 8),
284 qFromBigEndian<quint32>(ulUnicodeRange + 12)
285 };
286 const unsigned char* ulCodePageRange = data + 78;
287 quint32 codePageRange[2] = {
288 qFromBigEndian<quint32>(ulCodePageRange),
289 qFromBigEndian<quint32>(ulCodePageRange + 4)
290 };
291 const QList<QFontDatabase::WritingSystem> writingSystems =
292 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
293 foreach (const QFontDatabase::WritingSystem system, writingSystems)
294 family->writingSystems[system] = QtFontFamily::Supported;
295
296 fontAdded = true;
297 }
298 QS60Data::screenDevice()->ReleaseFont(font);
299 }
300
301 Q_ASSERT(fontAdded);
302
303 lock.relock();
304
305#else // defined(QT_NO_FREETYPE)
306 QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation));
307 dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
308 << QLatin1String("*.ttc") << QLatin1String("*.pfa")
309 << QLatin1String("*.pfb"));
310 for (int i = 0; i < int(dir.count()); ++i) {
311 const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
312 db->addTTFile(file);
313 }
314#endif // defined(QT_NO_FREETYPE)
315}
316
317static inline void load(const QString &family = QString(), int script = -1)
318{
319 Q_UNUSED(family)
320 Q_UNUSED(script)
321 initializeDb();
322}
323
324static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
325{
326 Q_UNUSED(fnt);
327}
328
329bool QFontDatabase::removeApplicationFont(int handle)
330{
331 Q_UNUSED(handle);
332 return false;
333}
334
335bool QFontDatabase::supportsThreadedFontRendering()
336{
337 return false;
338}
339
340static
341QFontDef cleanedFontDef(const QFontDef &req)
342{
343 QFontDef result = req;
344 if (result.pixelSize <= 0) {
345 result.pixelSize = QFontEngineS60::pointsToPixels(qMax(qreal(1.0), result.pointSize));
346 result.pointSize = 0;
347 }
348 return result;
349}
350
351QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *, const QFontDef &req)
352{
353 const QFontCache::Key key(cleanedFontDef(req), script);
354
355 if (!privateDb()->count)
356 initializeDb();
357
358 QFontEngine *fe = QFontCache::instance()->findEngine(key);
359 if (!fe) {
360 // Making sure that fe->fontDef.family will be an existing font.
361 initializeDb();
362 QFontDatabasePrivate *db = privateDb();
363 QtFontDesc desc;
364 QList<int> blacklistedFamilies;
365 match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies);
366 if (!desc.family) // falling back to application font
367 desc.family = db->family(QApplication::font().defaultFamily());
368 Q_ASSERT(desc.family);
369
370 // Making sure that desc.family supports the requested script
371 QtFontDesc mappedDesc;
372 bool supportsScript = false;
373 do {
374 match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
375 if (mappedDesc.family == desc.family) {
376 supportsScript = true;
377 break;
378 }
379 blacklistedFamilies.append(mappedDesc.familyIndex);
380 } while (mappedDesc.family);
381 if (!supportsScript) {
382 blacklistedFamilies.clear();
383 match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
384 if (mappedDesc.family)
385 desc = mappedDesc;
386 }
387
388 const QString fontFamily = desc.family->name;
389 QFontDef request = req;
390 request.family = fontFamily;
391#if defined(QT_NO_FREETYPE)
392 const QFontDatabaseS60StoreImplementation *store =
393 static_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store);
394 const QFontEngineS60Extensions *extension = store->extension(fontFamily);
395 fe = new QFontEngineS60(request, extension);
396#else
397 QFontEngine::FaceId faceId;
398 const QtFontFamily * const reqQtFontFamily = db->family(fontFamily);
399 faceId.filename = reqQtFontFamily->fontFilename;
400 faceId.index = reqQtFontFamily->fontFileIndex;
401
402 QFontEngineFTS60 *fte = new QFontEngineFTS60(cleanedFontDef(request));
403 if (fte->init(faceId, true, QFontEngineFT::Format_A8))
404 fe = fte;
405 else
406 delete fte;
407#endif
408
409 Q_ASSERT(fe);
410 if (script == QUnicodeTables::Common
411 && !(req.styleStrategy & QFont::NoFontMerging)
412 && !fe->symbol) {
413
414 QStringList commonFonts;
415 for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
416 if (scriptForWritingSystem[ws] != script)
417 continue;
418 for (int i = 0; i < db->count; ++i) {
419 if (db->families[i]->writingSystems[ws] & QtFontFamily::Supported)
420 commonFonts.append(db->families[i]->name);
421 }
422 }
423
424 // Hack: Prioritize .ccc fonts
425 const QString niceEastAsianFont(QLatin1String("Sans MT 936_S60"));
426 if (commonFonts.removeAll(niceEastAsianFont) > 0)
427 commonFonts.prepend(niceEastAsianFont);
428
429 fe = new QFontEngineMultiS60(fe, script, commonFonts);
430 }
431 }
432 fe->ref.ref();
433 QFontCache::instance()->insertEngine(key, fe);
434 return fe;
435}
436
437void QFontDatabase::load(const QFontPrivate *d, int script)
438{
439 QFontEngine *fe = 0;
440 QFontDef req = d->request;
441
442 if (!d->engineData) {
443 const QFontCache::Key key(cleanedFontDef(req), script);
444 getEngineData(d, key);
445 }
446
447 // the cached engineData could have already loaded the engine we want
448 if (d->engineData->engines[script])
449 fe = d->engineData->engines[script];
450
451 if (!fe) {
452 if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
453 fe = new QTestFontEngine(req.pixelSize);
454 fe->fontDef = req;
455 } else {
456 fe = findFont(script, d, req);
457 }
458 d->engineData->engines[script] = fe;
459 }
460}
461
462QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.