util/src/gui/text/qfontdatabase_s60.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 ** 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 <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 
       
    59 QT_BEGIN_NAMESPACE
       
    60 
       
    61 QFileInfoList 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)
       
    95 class QFontDatabaseS60StoreImplementation : public QFontDatabaseS60Store
       
    96 {
       
    97 public:
       
    98     QFontDatabaseS60StoreImplementation();
       
    99     ~QFontDatabaseS60StoreImplementation();
       
   100 
       
   101     const QFontEngineS60Extensions *extension(const QString &typeface) const;
       
   102 
       
   103 private:
       
   104     RHeap* m_heap;
       
   105     CFontStore *m_store;
       
   106     COpenFontRasterizer *m_rasterizer;
       
   107     mutable QHash<QString, const QFontEngineS60Extensions *> m_extensions;
       
   108 };
       
   109 
       
   110 QFontDatabaseS60StoreImplementation::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 }
       
   130 QFontDatabaseS60StoreImplementation::~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 */
       
   149 COpenFont* 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 
       
   159 const 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
       
   179 class QFontEngineFTS60 : public QFontEngineFT
       
   180 {
       
   181 public:
       
   182     QFontEngineFTS60(const QFontDef &fd);
       
   183 };
       
   184 
       
   185 QFontEngineFTS60::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 */
       
   197 qreal 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 
       
   204 qreal 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 
       
   212 QFontEngineMultiS60::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 
       
   222 void 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 
       
   236 static 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 
       
   317 static inline void load(const QString &family = QString(), int script = -1)
       
   318 {
       
   319     Q_UNUSED(family)
       
   320     Q_UNUSED(script)
       
   321     initializeDb();
       
   322 }
       
   323 
       
   324 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
       
   325 {
       
   326     Q_UNUSED(fnt);
       
   327 }
       
   328 
       
   329 bool QFontDatabase::removeApplicationFont(int handle)
       
   330 {
       
   331     Q_UNUSED(handle);
       
   332     return false;
       
   333 }
       
   334 
       
   335 bool QFontDatabase::removeAllApplicationFonts()
       
   336 {
       
   337     return false;
       
   338 }
       
   339 
       
   340 bool QFontDatabase::supportsThreadedFontRendering()
       
   341 {
       
   342     return false;
       
   343 }
       
   344 
       
   345 static
       
   346 QFontDef cleanedFontDef(const QFontDef &req)
       
   347 {
       
   348     QFontDef result = req;
       
   349     if (result.pixelSize <= 0) {
       
   350         result.pixelSize = QFontEngineS60::pointsToPixels(qMax(qreal(1.0), result.pointSize));
       
   351         result.pointSize = 0;
       
   352     }
       
   353     return result;
       
   354 }
       
   355 
       
   356 QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *, const QFontDef &req)
       
   357 {
       
   358     const QFontCache::Key key(cleanedFontDef(req), script);
       
   359 
       
   360     if (!privateDb()->count)
       
   361         initializeDb();
       
   362 
       
   363     QFontEngine *fe = QFontCache::instance()->findEngine(key);
       
   364     if (!fe) {
       
   365         // Making sure that fe->fontDef.family will be an existing font.
       
   366         initializeDb();
       
   367         QFontDatabasePrivate *db = privateDb();
       
   368         QtFontDesc desc;
       
   369         QList<int> blacklistedFamilies;
       
   370         match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies);
       
   371         if (!desc.family) // falling back to application font
       
   372             desc.family = db->family(QApplication::font().defaultFamily());
       
   373         Q_ASSERT(desc.family);
       
   374 
       
   375         // Making sure that desc.family supports the requested script
       
   376         QtFontDesc mappedDesc;
       
   377         bool supportsScript = false;
       
   378         do {
       
   379             match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
       
   380             if (mappedDesc.family == desc.family) {
       
   381                 supportsScript = true;
       
   382                 break;
       
   383             }
       
   384             blacklistedFamilies.append(mappedDesc.familyIndex);
       
   385         } while (mappedDesc.family);
       
   386         if (!supportsScript) {
       
   387             blacklistedFamilies.clear();
       
   388             match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
       
   389             if (mappedDesc.family)
       
   390                 desc = mappedDesc;
       
   391         }
       
   392 
       
   393         const QString fontFamily = desc.family->name;
       
   394         QFontDef request = req;
       
   395         request.family = fontFamily;
       
   396 #if defined(QT_NO_FREETYPE)
       
   397         const QFontDatabaseS60StoreImplementation *store =
       
   398                 static_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store);
       
   399         const QFontEngineS60Extensions *extension = store->extension(fontFamily);
       
   400         fe = new QFontEngineS60(request, extension);
       
   401 #else
       
   402         QFontEngine::FaceId faceId;
       
   403         const QtFontFamily * const reqQtFontFamily = db->family(fontFamily);
       
   404         faceId.filename = reqQtFontFamily->fontFilename;
       
   405         faceId.index = reqQtFontFamily->fontFileIndex;
       
   406 
       
   407         QFontEngineFTS60 *fte = new QFontEngineFTS60(cleanedFontDef(request));
       
   408         if (fte->init(faceId, true, QFontEngineFT::Format_A8))
       
   409             fe = fte;
       
   410         else
       
   411             delete fte;
       
   412 #endif
       
   413 
       
   414         Q_ASSERT(fe);
       
   415         if (script == QUnicodeTables::Common
       
   416             && !(req.styleStrategy & QFont::NoFontMerging)
       
   417             && !fe->symbol) {
       
   418 
       
   419             QStringList commonFonts;
       
   420             for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
       
   421                 if (scriptForWritingSystem[ws] != script)
       
   422                     continue;
       
   423                 for (int i = 0; i < db->count; ++i) {
       
   424                     if (db->families[i]->writingSystems[ws] & QtFontFamily::Supported)
       
   425                         commonFonts.append(db->families[i]->name);
       
   426                 }
       
   427             }
       
   428 
       
   429             // Hack: Prioritize .ccc fonts
       
   430             const QString niceEastAsianFont(QLatin1String("Sans MT 936_S60"));
       
   431             if (commonFonts.removeAll(niceEastAsianFont) > 0)
       
   432                 commonFonts.prepend(niceEastAsianFont);
       
   433 
       
   434             fe = new QFontEngineMultiS60(fe, script, commonFonts);
       
   435         }
       
   436     }
       
   437     fe->ref.ref();
       
   438     QFontCache::instance()->insertEngine(key, fe);
       
   439     return fe;
       
   440 }
       
   441 
       
   442 void QFontDatabase::load(const QFontPrivate *d, int script)
       
   443 {
       
   444     QFontEngine *fe = 0;
       
   445     QFontDef req = d->request;
       
   446 
       
   447     if (!d->engineData) {
       
   448         const QFontCache::Key key(cleanedFontDef(req), script);
       
   449         getEngineData(d, key);
       
   450     }
       
   451 
       
   452     // the cached engineData could have already loaded the engine we want
       
   453     if (d->engineData->engines[script])
       
   454         fe = d->engineData->engines[script];
       
   455 
       
   456     if (!fe) {
       
   457         if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
       
   458             fe = new QTestFontEngine(req.pixelSize);
       
   459             fe->fontDef = req;
       
   460         } else {
       
   461             fe = findFont(script, d, req);
       
   462         }
       
   463         d->engineData->engines[script] = fe;
       
   464     }
       
   465 }
       
   466 
       
   467 QT_END_NAMESPACE