src/gui/text/qfontdatabase_s60.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 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 /* :QTP:JKOO-7XPHCJ:resolve header split problem */
       
    44 #include "qglobal.h"
       
    45 #include "qdir.h"
       
    46 #include "qfont_p.h"
       
    47 #include "qfontengine_s60_p.h"
       
    48 #include "qabstractfileengine.h"
       
    49 #include "qdesktopservices.h"
       
    50 #include "qpixmap_s60_p.h"
       
    51 #include "qt_s60_p.h"
       
    52 #include "qendian.h"
       
    53 #include <private/qcore_symbian_p.h>
       
    54 #if defined(QT_NO_FREETYPE)
       
    55 #include <OPENFONT.H>
       
    56 #include <graphics/openfontrasterizer.h>
       
    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 const QFontEngineS60Extensions *QFontDatabaseS60StoreImplementation::extension(const QString &typeface) const
       
   143 {
       
   144     if (!m_extensions.contains(typeface)) {
       
   145         CFont* font = NULL;
       
   146         TFontSpec spec(qt_QString2TPtrC(typeface), 1);
       
   147         spec.iHeight = 1;
       
   148         const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, spec);
       
   149         Q_ASSERT(err == KErrNone && font);
       
   150         CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font);
       
   151         m_extensions.insert(typeface, new QFontEngineS60Extensions(font, bitmapFont->OpenFont()));
       
   152     }
       
   153     return m_extensions.value(typeface);
       
   154 }
       
   155 #else
       
   156 class QFontEngineFTS60 : public QFontEngineFT
       
   157 {
       
   158 public:
       
   159     QFontEngineFTS60(const QFontDef &fd);
       
   160 };
       
   161 
       
   162 QFontEngineFTS60::QFontEngineFTS60(const QFontDef &fd)
       
   163     : QFontEngineFT(fd)
       
   164 {
       
   165     default_hint_style = HintFull;
       
   166 }
       
   167 #endif // defined(QT_NO_FREETYPE)
       
   168 
       
   169 /*
       
   170  QFontEngineS60::pixelsToPoints, QFontEngineS60::pointsToPixels, QFontEngineMultiS60::QFontEngineMultiS60
       
   171  and QFontEngineMultiS60::QFontEngineMultiS60 should be in qfontengine_s60.cpp. But since also the
       
   172  Freetype based font rendering need them, they are here.
       
   173 */
       
   174 qreal QFontEngineS60::pixelsToPoints(qreal pixels, Qt::Orientation orientation)
       
   175 {
       
   176     return (orientation == Qt::Horizontal?
       
   177         S60->screenDevice()->HorizontalPixelsToTwips(pixels)
       
   178         :S60->screenDevice()->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint;
       
   179 }
       
   180 
       
   181 qreal QFontEngineS60::pointsToPixels(qreal points, Qt::Orientation orientation)
       
   182 {
       
   183     const int twips = points * KTwipsPerPoint;
       
   184     return orientation == Qt::Horizontal?
       
   185         S60->screenDevice()->HorizontalTwipsToPixels(twips)
       
   186         :S60->screenDevice()->VerticalTwipsToPixels(twips);
       
   187 }
       
   188 
       
   189 QFontEngineMultiS60::QFontEngineMultiS60(QFontEngine *first, int script, const QStringList &fallbackFamilies)
       
   190     : QFontEngineMulti(fallbackFamilies.size() + 1)
       
   191     , m_script(script)
       
   192     , m_fallbackFamilies(fallbackFamilies)
       
   193 {
       
   194     engines[0] = first;
       
   195     first->ref.ref();
       
   196     fontDef = engines[0]->fontDef;
       
   197 }
       
   198 
       
   199 void QFontEngineMultiS60::loadEngine(int at)
       
   200 {
       
   201     Q_ASSERT(at < engines.size());
       
   202     Q_ASSERT(engines.at(at) == 0);
       
   203 
       
   204     QFontDef request = fontDef;
       
   205     request.styleStrategy |= QFont::NoFontMerging;
       
   206     request.family = m_fallbackFamilies.at(at-1);
       
   207     engines[at] = QFontDatabase::findFont(m_script,
       
   208                                           /*fontprivate*/0,
       
   209                                           request);
       
   210     Q_ASSERT(engines[at]);
       
   211 }
       
   212 
       
   213 static void initializeDb()
       
   214 {
       
   215     QFontDatabasePrivate *db = privateDb();
       
   216     if(!db || db->count)
       
   217         return;
       
   218 
       
   219 #if defined(QT_NO_FREETYPE)
       
   220     if (!db->s60Store)
       
   221         db->s60Store = new QFontDatabaseS60StoreImplementation;
       
   222 
       
   223     QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
       
   224     
       
   225     const int numTypeFaces = QS60Data::screenDevice()->NumTypefaces();
       
   226     const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store);
       
   227     Q_ASSERT(store);
       
   228     bool fontAdded = false;
       
   229     for (int i = 0; i < numTypeFaces; i++) {
       
   230         TTypefaceSupport typefaceSupport;
       
   231         QS60Data::screenDevice()->TypefaceSupport(typefaceSupport, i);
       
   232         CFont *font; // We have to get a font instance in order to know all the details
       
   233         TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11);
       
   234         if (QS60Data::screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone)
       
   235             continue;
       
   236         if (font->TypeUid() == KCFbsFontUid) {
       
   237             TOpenFontFaceAttrib faceAttrib;
       
   238             const CFbsFont *cfbsFont = dynamic_cast<const CFbsFont *>(font);
       
   239             Q_ASSERT(cfbsFont);
       
   240             cfbsFont->GetFaceAttrib(faceAttrib);
       
   241 
       
   242             QtFontStyle::Key styleKey;
       
   243             styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal;
       
   244             styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal;
       
   245 
       
   246             QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
       
   247             QtFontFamily *family = db->family(familyName, true);
       
   248             family->fixedPitch = faceAttrib.IsMonoWidth();
       
   249             QtFontFoundry *foundry = family->foundry(QString(), true);
       
   250             QtFontStyle *style = foundry->style(styleKey, true);
       
   251             style->smoothScalable = typefaceSupport.iIsScalable;
       
   252             style->pixelSize(0, true);
       
   253 
       
   254             const QFontEngineS60Extensions *extension = store->extension(familyName);
       
   255             const QByteArray os2Table = extension->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
       
   256             const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData());
       
   257             const unsigned char* ulUnicodeRange = data + 42;
       
   258             quint32 unicodeRange[4] = {
       
   259                 qFromBigEndian<quint32>(ulUnicodeRange),
       
   260                 qFromBigEndian<quint32>(ulUnicodeRange + 4),
       
   261                 qFromBigEndian<quint32>(ulUnicodeRange + 8),
       
   262                 qFromBigEndian<quint32>(ulUnicodeRange + 12)
       
   263             };
       
   264             const unsigned char* ulCodePageRange = data + 78;
       
   265             quint32 codePageRange[2] = {
       
   266                 qFromBigEndian<quint32>(ulCodePageRange),
       
   267                 qFromBigEndian<quint32>(ulCodePageRange + 4)
       
   268             };
       
   269             const QList<QFontDatabase::WritingSystem> writingSystems =
       
   270                 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
       
   271             foreach (const QFontDatabase::WritingSystem system, writingSystems)
       
   272                 family->writingSystems[system] = QtFontFamily::Supported;
       
   273 
       
   274             fontAdded = true;
       
   275         }
       
   276         QS60Data::screenDevice()->ReleaseFont(font);
       
   277     }
       
   278 
       
   279     Q_ASSERT(fontAdded);
       
   280     
       
   281 	lock.relock();
       
   282 
       
   283 #else // defined(QT_NO_FREETYPE)
       
   284     QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation));
       
   285     dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
       
   286                        << QLatin1String("*.ttc") << QLatin1String("*.pfa")
       
   287                        << QLatin1String("*.pfb"));
       
   288     for (int i = 0; i < int(dir.count()); ++i) {
       
   289         const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
       
   290         db->addTTFile(file);
       
   291     }
       
   292 #endif // defined(QT_NO_FREETYPE)
       
   293 }
       
   294 
       
   295 static inline void load(const QString &family = QString(), int script = -1)
       
   296 {
       
   297     Q_UNUSED(family)
       
   298     Q_UNUSED(script)
       
   299     initializeDb();
       
   300 }
       
   301 
       
   302 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
       
   303 {
       
   304     Q_UNUSED(fnt);
       
   305 }
       
   306 
       
   307 bool QFontDatabase::removeApplicationFont(int handle)
       
   308 {
       
   309     Q_UNUSED(handle);
       
   310     return false;
       
   311 }
       
   312 
       
   313 bool QFontDatabase::supportsThreadedFontRendering()
       
   314 {
       
   315     return false;
       
   316 }
       
   317 
       
   318 static
       
   319 QFontDef cleanedFontDef(const QFontDef &req)
       
   320 {
       
   321     QFontDef result = req;
       
   322     if (result.pixelSize <= 0) {
       
   323         result.pixelSize = QFontEngineS60::pointsToPixels(qMax(qreal(1.0), result.pointSize));
       
   324         result.pointSize = 0;
       
   325     }
       
   326     return result;
       
   327 }
       
   328 
       
   329 QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *, const QFontDef &req)
       
   330 {
       
   331     const QFontCache::Key key(cleanedFontDef(req), script);
       
   332 
       
   333     if (!privateDb()->count)
       
   334         initializeDb();
       
   335 
       
   336     QFontEngine *fe = QFontCache::instance()->findEngine(key);
       
   337     if (!fe) {
       
   338         // Making sure that fe->fontDef.family will be an existing font.
       
   339         initializeDb();
       
   340         QFontDatabasePrivate *db = privateDb();
       
   341         QtFontDesc desc;
       
   342         QList<int> blacklistedFamilies;
       
   343         match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies);
       
   344         if (!desc.family) // falling back to application font
       
   345             desc.family = db->family(QApplication::font().defaultFamily());
       
   346         Q_ASSERT(desc.family);
       
   347 
       
   348         // Making sure that desc.family supports the requested script
       
   349         QtFontDesc mappedDesc;
       
   350         bool supportsScript = false;
       
   351         do {
       
   352             match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
       
   353             if (mappedDesc.family == desc.family) {
       
   354                 supportsScript = true;
       
   355                 break;
       
   356             }
       
   357             blacklistedFamilies.append(mappedDesc.familyIndex);
       
   358         } while (mappedDesc.family);
       
   359         if (!supportsScript) {
       
   360             blacklistedFamilies.clear();
       
   361             match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
       
   362             if (mappedDesc.family)
       
   363                 desc = mappedDesc;
       
   364         }
       
   365 
       
   366         const QString fontFamily = desc.family->name;
       
   367         QFontDef request = req;
       
   368         request.family = fontFamily;
       
   369 #if defined(QT_NO_FREETYPE)
       
   370         const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store);
       
   371         Q_ASSERT(store);
       
   372         const QFontEngineS60Extensions *extension = store->extension(fontFamily);
       
   373         fe = new QFontEngineS60(request, extension);
       
   374 #else
       
   375         QFontEngine::FaceId faceId;
       
   376         const QtFontFamily * const reqQtFontFamily = db->family(fontFamily);
       
   377         faceId.filename = reqQtFontFamily->fontFilename;
       
   378         faceId.index = reqQtFontFamily->fontFileIndex;
       
   379 
       
   380         QFontEngineFTS60 *fte = new QFontEngineFTS60(cleanedFontDef(request));
       
   381         if (fte->init(faceId, true, QFontEngineFT::Format_A8))
       
   382             fe = fte;
       
   383         else
       
   384             delete fte;
       
   385 #endif
       
   386 
       
   387         Q_ASSERT(fe);
       
   388         if (script == QUnicodeTables::Common
       
   389             && !(req.styleStrategy & QFont::NoFontMerging)
       
   390             && !fe->symbol) {
       
   391 
       
   392             QStringList commonFonts;
       
   393             for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
       
   394                 if (scriptForWritingSystem[ws] != script)
       
   395                     continue;
       
   396                 for (int i = 0; i < db->count; ++i) {
       
   397                     if (db->families[i]->writingSystems[ws] & QtFontFamily::Supported)
       
   398                         commonFonts.append(db->families[i]->name);
       
   399                 }
       
   400             }
       
   401 
       
   402             // Hack: Prioritize .ccc fonts
       
   403             const QString niceEastAsianFont(QLatin1String("Sans MT 936_S60"));
       
   404             if (commonFonts.removeAll(niceEastAsianFont) > 0)
       
   405                 commonFonts.prepend(niceEastAsianFont);
       
   406 
       
   407             fe = new QFontEngineMultiS60(fe, script, commonFonts);
       
   408         }
       
   409     }
       
   410     fe->ref.ref();
       
   411     QFontCache::instance()->insertEngine(key, fe);
       
   412     return fe;
       
   413 }
       
   414 
       
   415 void QFontDatabase::load(const QFontPrivate *d, int script)
       
   416 {
       
   417     QFontEngine *fe = 0;
       
   418     QFontDef req = d->request;
       
   419 
       
   420     if (!d->engineData) {
       
   421         const QFontCache::Key key(cleanedFontDef(req), script);
       
   422         getEngineData(d, key);
       
   423     }
       
   424 
       
   425     // the cached engineData could have already loaded the engine we want
       
   426     if (d->engineData->engines[script])
       
   427         fe = d->engineData->engines[script];
       
   428 
       
   429     if (!fe) {
       
   430         if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
       
   431             fe = new QTestFontEngine(req.pixelSize);
       
   432             fe->fontDef = req;
       
   433         } else {
       
   434             fe = findFont(script, d, req);
       
   435         }
       
   436         d->engineData->engines[script] = fe;
       
   437     }
       
   438 }
       
   439 
       
   440 QT_END_NAMESPACE