Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/gui/text/qfontdatabase_s60.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4646#include "qabstractfileengine.h"
    4747#include "qdesktopservices.h"
    48 #include "qpixmap_s60_p.h"
    49 #include "qt_s60_p.h"
     48#include "qtemporaryfile.h"
     49#include "qtextcodec.h"
     50#include <private/qpixmap_s60_p.h>
     51#include <private/qt_s60_p.h>
    5052#include "qendian.h"
    5153#include <private/qcore_symbian_p.h>
    52 #if defined(QT_NO_FREETYPE)
     54#ifdef QT_NO_FREETYPE
    5355#include <openfont.h>
    5456#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
    5557#include <graphics/openfontrasterizer.h> // COpenFontRasterizer has moved to a new header file
    5658#endif // SYMBIAN_ENABLE_SPLIT_HEADERS
    57 #endif
     59#endif // QT_NO_FREETYPE
    5860
    5961QT_BEGIN_NAMESPACE
     62
     63QStringList qt_symbian_fontFamiliesOnFontServer() // Also used in qfont_s60.cpp
     64{
     65    QStringList result;
     66    QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
     67    const int numTypeFaces = S60->screenDevice()->NumTypefaces();
     68    for (int i = 0; i < numTypeFaces; i++) {
     69        TTypefaceSupport typefaceSupport;
     70        S60->screenDevice()->TypefaceSupport(typefaceSupport, i);
     71        const QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
     72        result.append(familyName);
     73    }
     74    lock.relock();
     75    return result;
     76}
    6077
    6178QFileInfoList alternativeFilePaths(const QString &path, const QStringList &nameFilters,
     
    92109}
    93110
    94 #if defined(QT_NO_FREETYPE)
     111#ifdef QT_NO_FREETYPE
    95112class QSymbianFontDatabaseExtrasImplementation : public QSymbianFontDatabaseExtras
    96113{
     
    100117
    101118    const QSymbianTypeFaceExtras *extras(const QString &typeface, bool bold, bool italic) const;
    102 
    103 private:
     119    void removeAppFontData(QFontDatabasePrivate::ApplicationFont *fnt);
     120    static inline bool appFontLimitReached();
     121    TUid addFontFileToFontStore(const QFileInfo &fontFileInfo);
     122    static void clear();
     123
     124    static inline QString tempAppFontFolder();
     125    static const QString appFontMarkerPrefix;
     126    static QString appFontMarker(); // 'qaf<shortUid[+shortPid]>'
     127
     128    struct CFontFromFontStoreReleaser {
     129        static inline void cleanup(CFont *font)
     130        {
     131            if (!font)
     132                return;
     133            const QSymbianFontDatabaseExtrasImplementation *dbExtras =
     134                    static_cast<const QSymbianFontDatabaseExtrasImplementation*>(privateDb()->symbianExtras);
     135            dbExtras->m_store->ReleaseFont(font);
     136        }
     137    };
     138
     139    struct CFontFromScreenDeviceReleaser {
     140        static inline void cleanup(CFont *font)
     141        {
     142            if (!font)
     143                return;
     144            S60->screenDevice()->ReleaseFont(font);
     145        }
     146    };
     147
     148// m_heap, m_store, m_rasterizer and m_extras are used if Symbian
     149// does not provide the Font Table API
    104150    RHeap* m_heap;
    105151    CFontStore *m_store;
    106152    COpenFontRasterizer *m_rasterizer;
    107153    mutable QList<const QSymbianTypeFaceExtras *> m_extras;
     154
    108155    mutable QHash<QString, const QSymbianTypeFaceExtras *> m_extrasHash;
     156    mutable QSet<QString> m_applicationFontFamilies;
    109157};
    110158
     159const QString QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix =
     160        QLatin1String("Q");
     161
     162inline QString QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
     163{
     164    return QDir::toNativeSeparators(QDir::tempPath()) + QLatin1Char('\\');
     165}
     166
     167QString QSymbianFontDatabaseExtrasImplementation::appFontMarker()
     168{
     169    static QString result;
     170    if (result.isEmpty()) {
     171        quint16 id = 0;
     172        if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     173            // We are allowed to load app fonts even from previous, crashed runs
     174            // of this application, since we can access the font tables.
     175            const quint32 uid = RProcess().Type().MostDerived().iUid;
     176            id = static_cast<quint16>(uid + (uid >> 16));
     177        } else {
     178            // If no font table Api is available, we must not even load a font
     179            // from a previous (crashed) run of this application. Reason: we
     180            // won't get the font tables, they are not in the CFontStore.
     181            // So, we use the pid, for more uniqueness.
     182            id = static_cast<quint16>(RProcess().Id().Id());
     183        }
     184        result = appFontMarkerPrefix + QString::fromLatin1("%1").arg(id & 0x7fff, 3, 32, QLatin1Char('0'));
     185        Q_ASSERT(appFontMarkerPrefix.length() == 1 && result.length() == 4);
     186    }
     187    return result;
     188}
     189
     190static inline bool qt_symbian_fontNameHasAppFontMarker(const QString &fontName)
     191{
     192    const int idLength = 3; // Keep in sync with id length in appFontMarker().
     193    const QString &prefix = QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix;
     194    if (fontName.length() < prefix.length() + idLength
     195            || fontName.mid(fontName.length() - idLength - prefix.length(), prefix.length()) != prefix)
     196        return false;
     197    // Testing if the the id is base32 data
     198    for (int i = fontName.length() - idLength; i < fontName.length(); ++i) {
     199        const QChar &c = fontName.at(i);
     200        if (!(c >= QLatin1Char('0') && c <= QLatin1Char('9')
     201              || c >= QLatin1Char('a') && c <= QLatin1Char('v')))
     202            return false;
     203    }
     204    return true;
     205}
     206
     207// If fontName is an application font of this app, prepend the app font marker
     208QString qt_symbian_fontNameWithAppFontMarker(const QString &fontName)
     209{
     210    QFontDatabasePrivate *db = privateDb();
     211    Q_ASSERT(db);
     212    const QSymbianFontDatabaseExtrasImplementation *dbExtras =
     213            static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
     214    return dbExtras->m_applicationFontFamilies.contains(fontName) ?
     215                fontName + QSymbianFontDatabaseExtrasImplementation::appFontMarker()
     216              : fontName;
     217}
     218
     219static inline QString qt_symbian_appFontNameWithoutMarker(const QString &markedFontName)
     220{
     221    return markedFontName.left(markedFontName.length()
     222                               - QSymbianFontDatabaseExtrasImplementation::appFontMarker().length());
     223}
     224
    111225QSymbianFontDatabaseExtrasImplementation::QSymbianFontDatabaseExtrasImplementation()
    112226{
    113     QStringList filters;
    114     filters.append(QLatin1String("*.ttf"));
    115     filters.append(QLatin1String("*.ccc"));
    116     filters.append(QLatin1String("*.ltt"));
    117     const QFileInfoList fontFiles = alternativeFilePaths(QLatin1String("resource\\Fonts"), filters);
    118 
    119     const TInt heapMinLength = 0x1000;
    120     const TInt heapMaxLength = qMax(0x20000 * fontFiles.count(), heapMinLength);
    121     m_heap = User::ChunkHeap(NULL, heapMinLength, heapMaxLength);
    122     QT_TRAP_THROWING(
    123         m_store = CFontStore::NewL(m_heap);
    124         m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E));
    125         CleanupStack::PushL(m_rasterizer);
    126         m_store->InstallRasterizerL(m_rasterizer);
    127         CleanupStack::Pop(m_rasterizer););
    128 
    129     foreach (const QFileInfo &fontFileInfo, fontFiles) {
    130         const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath());
    131         TPtrC fontFilePtr(qt_QString2TPtrC(fontFile));
    132         QT_TRAP_THROWING(m_store->AddFileL(fontFilePtr));
     227    if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     228        QStringList filters;
     229        filters.append(QLatin1String("*.ttf"));
     230        filters.append(QLatin1String("*.ccc"));
     231        filters.append(QLatin1String("*.ltt"));
     232        const QFileInfoList fontFiles = alternativeFilePaths(QLatin1String("resource\\Fonts"), filters);
     233
     234        const TInt heapMinLength = 0x1000;
     235        const TInt heapMaxLength = qMax(0x20000 * fontFiles.count(), heapMinLength);
     236        m_heap = User::ChunkHeap(NULL, heapMinLength, heapMaxLength);
     237        QT_TRAP_THROWING(
     238            m_store = CFontStore::NewL(m_heap);
     239            m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E));
     240            CleanupStack::PushL(m_rasterizer);
     241            m_store->InstallRasterizerL(m_rasterizer);
     242            CleanupStack::Pop(m_rasterizer););
     243
     244        foreach (const QFileInfo &fontFileInfo, fontFiles)
     245            addFontFileToFontStore(fontFileInfo);
     246    }
     247}
     248
     249void QSymbianFontDatabaseExtrasImplementation::clear()
     250{
     251    QFontDatabasePrivate *db = privateDb();
     252    if (!db)
     253        return;
     254    const QSymbianFontDatabaseExtrasImplementation *dbExtras =
     255            static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
     256    if (!dbExtras)
     257        return; // initializeDb() has never been called
     258    if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     259        qDeleteAll(dbExtras->m_extrasHash);
     260    } else {
     261        typedef QList<const QSymbianTypeFaceExtras *>::iterator iterator;
     262        for (iterator p = dbExtras->m_extras.begin(); p != dbExtras->m_extras.end(); ++p) {
     263            dbExtras->m_store->ReleaseFont((*p)->fontOwner());
     264            delete *p;
     265        }
     266        dbExtras->m_extras.clear();
     267    }
     268    dbExtras->m_extrasHash.clear();
     269}
     270
     271void qt_cleanup_symbianFontDatabase()
     272{
     273    QFontDatabasePrivate *db = privateDb();
     274    if (!db)
     275        return;
     276
     277    QSymbianFontDatabaseExtrasImplementation::clear();
     278
     279    if (!db->applicationFonts.isEmpty()) {
     280        QFontDatabase::removeAllApplicationFonts();
     281        // We remove the left over temporary font files of Qt application.
     282        // Active fonts are undeletable since the font server holds a handle
     283        // on them, so we do not need to worry to delete other running
     284        // applications' fonts.
     285        const QDir dir(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder());
     286        const QStringList filter(
     287                QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix + QLatin1String("*.ttf"));
     288        foreach (const QFileInfo &ttfFile, dir.entryInfoList(filter))
     289            QFile(ttfFile.absoluteFilePath()).remove();
     290        db->applicationFonts.clear();
    133291    }
    134292}
     
    136294QSymbianFontDatabaseExtrasImplementation::~QSymbianFontDatabaseExtrasImplementation()
    137295{
    138     typedef QList<const QSymbianTypeFaceExtras *>::iterator iterator;
    139     for (iterator p = m_extras.begin(); p != m_extras.end(); ++p) {
    140         m_store->ReleaseFont((*p)->fontOwner());
    141         delete *p;
    142     }
    143 
    144     delete m_store;
    145     m_heap->Close();
     296    qt_cleanup_symbianFontDatabase();
     297    if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     298        delete m_store;
     299        m_heap->Close();
     300    }
    146301}
    147302
     
    163318#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
    164319
    165 const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &typeface,
     320const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &aTypeface,
    166321                                                                               bool bold, bool italic) const
    167322{
     323    const QString typeface = qt_symbian_fontNameWithAppFontMarker(aTypeface);
    168324    const QString searchKey = typeface + QString::number(int(bold)) + QString::number(int(italic));
    169325    if (!m_extrasHash.contains(searchKey)) {
    170         CFont* font = NULL;
    171326        TFontSpec searchSpec(qt_QString2TPtrC(typeface), 1);
    172327        if (bold)
     
    174329        if (italic)
    175330            searchSpec.iFontStyle.SetPosture(EPostureItalic);
    176         const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, searchSpec);
    177         Q_ASSERT(err == KErrNone && font);
    178         const CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font);
    179         COpenFont *openFont =
     331
     332        CFont* font = NULL;
     333        if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     334            const TInt err = S60->screenDevice()->GetNearestFontToDesignHeightInPixels(font, searchSpec);
     335            Q_ASSERT(err == KErrNone && font);
     336            QScopedPointer<CFont, CFontFromScreenDeviceReleaser> sFont(font);
     337            QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font);
     338            sFont.take();
     339            m_extrasHash.insert(searchKey, extras);
     340        } else {
     341            const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, searchSpec);
     342            Q_ASSERT(err == KErrNone && font);
     343            const CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font);
     344            COpenFont *openFont =
    180345#ifdef FNTSTORE_H_INLINES_SUPPORT_FMM
    181             bitmapFont->openFont();
    182 #else
    183             OpenFontFromBitmapFont(bitmapFont);
     346                bitmapFont->OpenFont();
     347#else // FNTSTORE_H_INLINES_SUPPORT_FMM
     348                OpenFontFromBitmapFont(bitmapFont);
    184349#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
    185         const TOpenFontFaceAttrib* const attrib = openFont->FaceAttrib();
    186         const QString foundKey =
    187                 QString((const QChar*)attrib->FullName().Ptr(), attrib->FullName().Length());
    188         if (!m_extrasHash.contains(foundKey)) {
    189             QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font, openFont);
    190             m_extras.append(extras);
    191             m_extrasHash.insert(searchKey, extras);
    192             m_extrasHash.insert(foundKey, extras);
    193         } else {
    194             m_store->ReleaseFont(font);
    195             m_extrasHash.insert(searchKey, m_extrasHash.value(foundKey));
     350            const TOpenFontFaceAttrib* const attrib = openFont->FaceAttrib();
     351            const QString foundKey =
     352                    QString((const QChar*)attrib->FullName().Ptr(), attrib->FullName().Length());
     353            if (!m_extrasHash.contains(foundKey)) {
     354                QScopedPointer<CFont, CFontFromFontStoreReleaser> sFont(font);
     355                QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font, openFont);
     356                sFont.take();
     357                m_extras.append(extras);
     358                m_extrasHash.insert(searchKey, extras);
     359                m_extrasHash.insert(foundKey, extras);
     360            } else {
     361                m_store->ReleaseFont(font);
     362                m_extrasHash.insert(searchKey, m_extrasHash.value(foundKey));
     363            }
    196364        }
    197365    }
    198366    return m_extrasHash.value(searchKey);
    199367}
    200 #else
     368
     369void QSymbianFontDatabaseExtrasImplementation::removeAppFontData(
     370    QFontDatabasePrivate::ApplicationFont *fnt)
     371{
     372    clear();
     373    if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()
     374            && fnt->fontStoreFontFileUid.iUid != 0)
     375        m_store->RemoveFile(fnt->fontStoreFontFileUid);
     376    if (!fnt->families.isEmpty())
     377        m_applicationFontFamilies.remove(fnt->families.first());
     378    if (fnt->screenDeviceFontFileId != 0)
     379        S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId);
     380    QFile::remove(fnt->temporaryFileName);
     381    *fnt = QFontDatabasePrivate::ApplicationFont();
     382}
     383
     384bool QSymbianFontDatabaseExtrasImplementation::appFontLimitReached()
     385{
     386    QFontDatabasePrivate *db = privateDb();
     387    if (!db)
     388        return false;
     389    const int maxAppFonts = 5;
     390    int registeredAppFonts = 0;
     391    foreach (const QFontDatabasePrivate::ApplicationFont &appFont, db->applicationFonts)
     392        if (!appFont.families.isEmpty() && ++registeredAppFonts == maxAppFonts)
     393            return true;
     394    return false;
     395}
     396
     397TUid QSymbianFontDatabaseExtrasImplementation::addFontFileToFontStore(const QFileInfo &fontFileInfo)
     398{
     399    Q_ASSERT(!QSymbianTypeFaceExtras::symbianFontTableApiAvailable());
     400    const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath());
     401    const TPtrC fontFilePtr(qt_QString2TPtrC(fontFile));
     402    TUid fontUid = {0};
     403    TRAP_IGNORE(fontUid = m_store->AddFileL(fontFilePtr));
     404    return fontUid;
     405}
     406
     407#else // QT_NO_FREETYPE
    201408class QFontEngineFTS60 : public QFontEngineFT
    202409{
     
    210417    default_hint_style = HintFull;
    211418}
    212 #endif // defined(QT_NO_FREETYPE)
     419#endif // QT_NO_FREETYPE
    213420
    214421/*
     
    219426qreal QFontEngineS60::pixelsToPoints(qreal pixels, Qt::Orientation orientation)
    220427{
     428    CWsScreenDevice* device = S60->screenDevice();
    221429    return (orientation == Qt::Horizontal?
    222         S60->screenDevice()->HorizontalPixelsToTwips(pixels)
    223         :S60->screenDevice()->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint;
     430        device->HorizontalPixelsToTwips(pixels)
     431        :device->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint;
    224432}
    225433
    226434qreal QFontEngineS60::pointsToPixels(qreal points, Qt::Orientation orientation)
    227435{
     436    CWsScreenDevice* device = S60->screenDevice();
    228437    const int twips = points * KTwipsPerPoint;
    229438    return orientation == Qt::Horizontal?
    230         S60->screenDevice()->HorizontalTwipsToPixels(twips)
    231         :S60->screenDevice()->VerticalTwipsToPixels(twips);
     439        device->HorizontalTwipsToPixels(twips)
     440        :device->VerticalTwipsToPixels(twips);
    232441}
    233442
     
    256465}
    257466
     467static bool registerScreenDeviceFont(int screenDeviceFontIndex,
     468                                     const QSymbianFontDatabaseExtrasImplementation *dbExtras)
     469{
     470    TTypefaceSupport typefaceSupport;
     471        S60->screenDevice()->TypefaceSupport(typefaceSupport, screenDeviceFontIndex);
     472
     473    QString familyName((const QChar*)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
     474    if (qt_symbian_fontNameHasAppFontMarker(familyName)) {
     475        const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker();
     476        if (familyName.endsWith(marker)) {
     477            familyName = qt_symbian_appFontNameWithoutMarker(familyName);
     478            dbExtras->m_applicationFontFamilies.insert(familyName);
     479        } else {
     480            return false; // This was somebody else's application font. Skip it.
     481        }
     482    }
     483
     484    CFont *font; // We have to get a font instance in order to know all the details
     485    TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11);
     486    if (S60->screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone)
     487        return false;
     488    QScopedPointer<CFont, QSymbianFontDatabaseExtrasImplementation::CFontFromScreenDeviceReleaser> sFont(font);
     489    if (font->TypeUid() != KCFbsFontUid)
     490        return false;
     491    TOpenFontFaceAttrib faceAttrib;
     492    const CFbsFont *cfbsFont = static_cast<const CFbsFont *>(font);
     493    cfbsFont->GetFaceAttrib(faceAttrib);
     494
     495    QtFontStyle::Key styleKey;
     496    styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal;
     497    styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal;
     498
     499    QtFontFamily *family = privateDb()->family(familyName, true);
     500    family->fixedPitch = faceAttrib.IsMonoWidth();
     501    QtFontFoundry *foundry = family->foundry(QString(), true);
     502    QtFontStyle *style = foundry->style(styleKey, true);
     503    style->smoothScalable = typefaceSupport.iIsScalable;
     504    style->pixelSize(0, true);
     505
     506    const QSymbianTypeFaceExtras *typeFaceExtras =
     507            dbExtras->extras(familyName, faceAttrib.IsBold(), faceAttrib.IsItalic());
     508    const QByteArray os2Table = typeFaceExtras->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
     509    const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData());
     510    const unsigned char* ulUnicodeRange = data + 42;
     511    quint32 unicodeRange[4] = {
     512        qFromBigEndian<quint32>(ulUnicodeRange),
     513        qFromBigEndian<quint32>(ulUnicodeRange + 4),
     514        qFromBigEndian<quint32>(ulUnicodeRange + 8),
     515        qFromBigEndian<quint32>(ulUnicodeRange + 12)
     516    };
     517    const unsigned char* ulCodePageRange = data + 78;
     518    quint32 codePageRange[2] = {
     519        qFromBigEndian<quint32>(ulCodePageRange),
     520        qFromBigEndian<quint32>(ulCodePageRange + 4)
     521    };
     522    const QList<QFontDatabase::WritingSystem> writingSystems =
     523        determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
     524    foreach (const QFontDatabase::WritingSystem system, writingSystems)
     525        family->writingSystems[system] = QtFontFamily::Supported;
     526    return true;
     527}
     528
    258529static void initializeDb()
    259530{
     
    262533        return;
    263534
    264 #if defined(QT_NO_FREETYPE)
     535#ifdef QT_NO_FREETYPE
    265536    if (!db->symbianExtras)
    266537        db->symbianExtras = new QSymbianFontDatabaseExtrasImplementation;
    267538
    268539    QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
    269    
    270     const int numTypeFaces = QS60Data::screenDevice()->NumTypefaces();
     540
     541    const int numTypeFaces = S60->screenDevice()->NumTypefaces();
    271542    const QSymbianFontDatabaseExtrasImplementation *dbExtras =
    272543            static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
    273     bool fontAdded = false;
    274     for (int i = 0; i < numTypeFaces; i++) {
    275         TTypefaceSupport typefaceSupport;
    276         QS60Data::screenDevice()->TypefaceSupport(typefaceSupport, i);
    277         CFont *font; // We have to get a font instance in order to know all the details
    278         TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11);
    279         if (QS60Data::screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone)
    280             continue;
    281         if (font->TypeUid() == KCFbsFontUid) {
    282             TOpenFontFaceAttrib faceAttrib;
    283             const CFbsFont *cfbsFont = static_cast<const CFbsFont *>(font);
    284             cfbsFont->GetFaceAttrib(faceAttrib);
    285 
    286             QtFontStyle::Key styleKey;
    287             styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal;
    288             styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal;
    289 
    290             QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
    291             QtFontFamily *family = db->family(familyName, true);
    292             family->fixedPitch = faceAttrib.IsMonoWidth();
    293             QtFontFoundry *foundry = family->foundry(QString(), true);
    294             QtFontStyle *style = foundry->style(styleKey, true);
    295             style->smoothScalable = typefaceSupport.iIsScalable;
    296             style->pixelSize(0, true);
    297 
    298             const QSymbianTypeFaceExtras *typeFaceExtras =
    299                     dbExtras->extras(familyName, faceAttrib.IsBold(), faceAttrib.IsItalic());
    300             const QByteArray os2Table = typeFaceExtras->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
    301             const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData());
    302             const unsigned char* ulUnicodeRange = data + 42;
    303             quint32 unicodeRange[4] = {
    304                 qFromBigEndian<quint32>(ulUnicodeRange),
    305                 qFromBigEndian<quint32>(ulUnicodeRange + 4),
    306                 qFromBigEndian<quint32>(ulUnicodeRange + 8),
    307                 qFromBigEndian<quint32>(ulUnicodeRange + 12)
    308             };
    309             const unsigned char* ulCodePageRange = data + 78;
    310             quint32 codePageRange[2] = {
    311                 qFromBigEndian<quint32>(ulCodePageRange),
    312                 qFromBigEndian<quint32>(ulCodePageRange + 4)
    313             };
    314             const QList<QFontDatabase::WritingSystem> writingSystems =
    315                 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
    316             foreach (const QFontDatabase::WritingSystem system, writingSystems)
    317                 family->writingSystems[system] = QtFontFamily::Supported;
    318 
    319             fontAdded = true;
    320         }
    321         QS60Data::screenDevice()->ReleaseFont(font);
    322     }
    323 
    324     Q_ASSERT(fontAdded);
    325    
    326         lock.relock();
    327 
    328 #else // defined(QT_NO_FREETYPE)
     544    for (int i = 0; i < numTypeFaces; i++)
     545        registerScreenDeviceFont(i, dbExtras);
     546
     547    // We have to clear/release all CFonts, here, in case one of the fonts is
     548    // an application font of another running Qt app. Otherwise the other Qt app
     549    // cannot remove it's application font, anymore -> "Zombie Font".
     550    QSymbianFontDatabaseExtrasImplementation::clear();
     551
     552    lock.relock();
     553
     554#else // QT_NO_FREETYPE
    329555    QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation));
    330556    dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
     
    335561        db->addTTFile(file);
    336562    }
    337 #endif // defined(QT_NO_FREETYPE)
     563#endif // QT_NO_FREETYPE
    338564}
    339565
     
    345571}
    346572
     573struct OffsetTable {
     574    quint32 sfntVersion;
     575    quint16 numTables, searchRange, entrySelector, rangeShift;
     576};
     577
     578struct TableRecord {
     579    quint32 tag, checkSum, offset, length;
     580};
     581
     582struct NameTableHead {
     583    quint16 format, count, stringOffset;
     584};
     585
     586struct NameRecord {
     587    quint16 platformID, encodingID, languageID, nameID, length, offset;
     588};
     589
     590static quint32 ttfCalcChecksum(const char *data, quint32 bytesCount)
     591{
     592    quint32 result = 0;
     593    const quint32 *ptr = reinterpret_cast<const quint32*>(data);
     594    const quint32 *endPtr =
     595            ptr + (bytesCount + sizeof(quint32) - 1) / sizeof(quint32);
     596    while (ptr < endPtr) {
     597        const quint32 unit32Value = *ptr++;
     598        result += qFromBigEndian(unit32Value);
     599    }
     600    return result;
     601}
     602
     603static inline quint32 toDWordBoundary(quint32 value)
     604{
     605    return (value + 3) & ~3;
     606}
     607
     608static inline quint32 dWordPadding(quint32 value)
     609{
     610    return (4 - (value & 3)) & 3;
     611}
     612
     613static inline bool ttfMarkNameTable(QByteArray &table, const QString &marker)
     614{
     615    const quint32 tableLength = static_cast<quint32>(table.size());
     616
     617    if (tableLength > 50000 // hard limit
     618            || tableLength < sizeof(NameTableHead)) // corrupt name table
     619        return false;
     620
     621    const NameTableHead *head = reinterpret_cast<const NameTableHead*>(table.constData());
     622    const quint16 count = qFromBigEndian(head->count);
     623    const quint16 stringOffset = qFromBigEndian(head->stringOffset);
     624    if (count > 200 // hard limit
     625            || stringOffset >= tableLength // corrupt name table
     626            || sizeof(NameTableHead) + count * sizeof(NameRecord) >= tableLength) // corrupt name table
     627        return false;
     628
     629    QTextEncoder encoder(QTextCodec::codecForName("UTF-16BE"), QTextCodec::IgnoreHeader);
     630    const QByteArray markerUtf16BE = encoder.fromUnicode(marker);
     631    const QByteArray markerAscii = marker.toAscii();
     632
     633    QByteArray markedTable;
     634    markedTable.reserve(tableLength + marker.length() * 20); // Original size plus some extra
     635    markedTable.append(table, stringOffset);
     636    QByteArray markedStrings;
     637    quint32 stringDataCount = stringOffset;
     638    for (quint16 i = 0; i < count; ++i) {
     639        const quint32 nameRecordOffset = sizeof(NameTableHead) + sizeof(NameRecord) * i;
     640        NameRecord *nameRecord =
     641                reinterpret_cast<NameRecord*>(markedTable.data() + nameRecordOffset);
     642        const quint16 nameID = qFromBigEndian(nameRecord->nameID);
     643        const quint16 platformID = qFromBigEndian(nameRecord->platformID);
     644        const quint16 encodingID = qFromBigEndian(nameRecord->encodingID);
     645        const quint16 offset = qFromBigEndian(nameRecord->offset);
     646        const quint16 length = qFromBigEndian(nameRecord->length);
     647        stringDataCount += length;
     648        if (stringDataCount > 80000 // hard limit. String data may be > name table size. Multiple records can reference the same string.
     649                || static_cast<quint32>(stringOffset + offset + length) > tableLength) // String outside bounds
     650            return false;
     651        const bool needsMarker =
     652                nameID == 1 || nameID == 3 || nameID == 4 || nameID == 16 || nameID == 21;
     653        const bool isUnicode =
     654                platformID == 0 || platformID == 3 && encodingID == 1;
     655        const QByteArray originalString =
     656                QByteArray::fromRawData(table.constData() + stringOffset + offset, length);
     657        QByteArray markedString;
     658        if (needsMarker) {
     659            const int maxBytesLength = (KMaxTypefaceNameLength - marker.length()) * (isUnicode ? 2 : 1);
     660            markedString = originalString.left(maxBytesLength) + (isUnicode ? markerUtf16BE : markerAscii);
     661        } else {
     662            markedString = originalString;
     663        }
     664        nameRecord->offset = qToBigEndian(static_cast<quint16>(markedStrings.length()));
     665        nameRecord->length = qToBigEndian(static_cast<quint16>(markedString.length()));
     666        markedStrings.append(markedString);
     667    }
     668    markedTable.append(markedStrings);
     669    table = markedTable;
     670    return true;
     671}
     672
     673const quint32 ttfMaxFileSize = 3500000;
     674
     675static inline bool ttfMarkAppFont(QByteArray &ttf, const QString &marker)
     676{
     677    const quint32 ttfChecksumNumber = 0xb1b0afba;
     678    const quint32 alignment = 4;
     679    const quint32 ttfLength = static_cast<quint32>(ttf.size());
     680    if (ttfLength > ttfMaxFileSize // hard limit
     681            || ttfLength % alignment != 0 // ttf sizes are always factors of 4
     682            || ttfLength <= sizeof(OffsetTable) // ttf too short
     683            || ttfCalcChecksum(ttf.constData(), ttf.size()) != ttfChecksumNumber) // ttf checksum is invalid
     684        return false;
     685
     686    const OffsetTable *offsetTable = reinterpret_cast<const OffsetTable*>(ttf.constData());
     687    const quint16 numTables = qFromBigEndian(offsetTable->numTables);
     688    const quint32 recordsLength =
     689            toDWordBoundary(sizeof(OffsetTable) + numTables * sizeof(TableRecord));
     690    if (numTables > 30 // hard limit
     691            || recordsLength + numTables * alignment > ttfLength) // Corrupt ttf. Tables would not fit, even if empty.
     692        return false;
     693
     694    QByteArray markedTtf;
     695    markedTtf.reserve(ttfLength + marker.length() * 20); // Original size plus some extra
     696    markedTtf.append(ttf.constData(), recordsLength);
     697
     698    const quint32 ttfCheckSumAdjustmentOffset = 8; // Offset from the start of 'head'
     699    int indexOfHeadTable = -1;
     700    quint32 ttfDataSize = recordsLength;
     701    typedef QPair<quint32, quint32> Range;
     702    QList<Range> memoryRanges;
     703    memoryRanges.reserve(numTables);
     704    for (int i = 0; i < numTables; ++i) {
     705        TableRecord *tableRecord =
     706                reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord));
     707        const quint32 offset = qFromBigEndian(tableRecord->offset);
     708        const quint32 length = qFromBigEndian(tableRecord->length);
     709        const quint32 lengthAligned = toDWordBoundary(length);
     710        ttfDataSize += lengthAligned;
     711        if (offset < recordsLength // must not intersect ttf header/records
     712                || offset % alignment != 0 // must be aligned
     713                || offset > ttfLength - alignment // table out of bounds
     714                || offset + lengthAligned > ttfLength // table out of bounds
     715                || ttfDataSize > ttfLength) // tables would not fit into the ttf
     716            return false;
     717
     718        foreach (const Range &range, memoryRanges)
     719            if (offset < range.first + range.second && offset + lengthAligned > range.first)
     720                return false; // Overlaps with another table
     721        memoryRanges.append(Range(offset, lengthAligned));
     722
     723        quint32 checkSum = qFromBigEndian(tableRecord->checkSum);
     724        if (tableRecord->tag == qToBigEndian(static_cast<quint32>('head'))) {
     725            if (length < ttfCheckSumAdjustmentOffset + sizeof(quint32))
     726                return false; // Invalid 'head' table
     727            const quint32 *checkSumAdjustmentTag =
     728                    reinterpret_cast<const quint32*>(ttf.constData() + offset + ttfCheckSumAdjustmentOffset);
     729            const quint32 checkSumAdjustment = qFromBigEndian(*checkSumAdjustmentTag);
     730            checkSum += checkSumAdjustment;
     731            indexOfHeadTable = i; // For the ttf checksum re-calculation, later
     732        }
     733        if (checkSum != ttfCalcChecksum(ttf.constData() + offset, length))
     734            return false; // Table checksum is invalid
     735
     736        bool updateTableChecksum = false;
     737        QByteArray table;
     738        if (tableRecord->tag == qToBigEndian(static_cast<quint32>('name'))) {
     739            table = QByteArray(ttf.constData() + offset, length);
     740            if (!ttfMarkNameTable(table, marker))
     741                return false; // Name table was not markable.
     742            updateTableChecksum = true;
     743        } else {
     744            table = QByteArray::fromRawData(ttf.constData() + offset, length);
     745        }
     746
     747        tableRecord->offset = qToBigEndian(markedTtf.size());
     748        tableRecord->length = qToBigEndian(table.size());
     749        markedTtf.append(table);
     750        markedTtf.append(QByteArray(dWordPadding(table.size()), 0)); // 0-padding
     751        if (updateTableChecksum) {
     752            TableRecord *tableRecord = // Need to recalculate, since markedTtf changed
     753                    reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord));
     754            const quint32 offset = qFromBigEndian(tableRecord->offset);
     755            const quint32 length = qFromBigEndian(tableRecord->length);
     756            tableRecord->checkSum = qToBigEndian(ttfCalcChecksum(markedTtf.constData() + offset, length));
     757        }
     758    }
     759    if (indexOfHeadTable == -1 // 'head' table is mandatory
     760            || ttfDataSize != ttfLength) // We do not allow ttf data "holes". Neither does Symbian.
     761        return false;
     762    TableRecord *headRecord =
     763            reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + indexOfHeadTable * sizeof(TableRecord));
     764    quint32 *checkSumAdjustmentTag =
     765            reinterpret_cast<quint32*>(markedTtf.data() + qFromBigEndian(headRecord->offset) + ttfCheckSumAdjustmentOffset);
     766    *checkSumAdjustmentTag = 0;
     767    const quint32 ttfChecksum = ttfCalcChecksum(markedTtf.constData(), markedTtf.count());
     768    *checkSumAdjustmentTag = qToBigEndian(ttfChecksumNumber - ttfChecksum);
     769    ttf = markedTtf;
     770    return true;
     771}
     772
     773static inline bool ttfCanSymbianLoadFont(const QByteArray &data, const QString &fileName)
     774{
     775    bool result = false;
     776    QString ttfFileName;
     777    QFile tempFileGuard;
     778    QFileInfo info(fileName);
     779    if (!data.isEmpty()) {
     780        QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
     781                                + QSymbianFontDatabaseExtrasImplementation::appFontMarker()
     782                                + QLatin1String("XXXXXX.ttf"));
     783        if (!tempfile.open() || tempfile.write(data) == -1)
     784            return false;
     785        ttfFileName = QDir::toNativeSeparators(QFileInfo(tempfile).canonicalFilePath());
     786        tempfile.setAutoRemove(false);
     787        tempfile.close();
     788        tempFileGuard.setFileName(ttfFileName);
     789        if (!tempFileGuard.open(QIODevice::ReadOnly))
     790            return false;
     791    } else if (info.isFile()) {
     792        ttfFileName = QDir::toNativeSeparators(info.canonicalFilePath());
     793    } else {
     794        return false;
     795    }
     796
     797    CFontStore *store = 0;
     798    RHeap* heap = User::ChunkHeap(NULL, 0x1000, 0x20000);
     799    if (heap) {
     800        QT_TRAP_THROWING(
     801            CleanupClosePushL(*heap);
     802            store = CFontStore::NewL(heap);
     803            CleanupStack::PushL(store);
     804            COpenFontRasterizer *rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E));
     805            CleanupStack::PushL(rasterizer);
     806            store->InstallRasterizerL(rasterizer);
     807            CleanupStack::Pop(rasterizer);
     808            TUid fontUid = {-1};
     809            TRAP_IGNORE(fontUid = store->AddFileL(qt_QString2TPtrC(ttfFileName)));
     810            if (fontUid.iUid != -1)
     811                result = true;
     812            CleanupStack::PopAndDestroy(2, heap); // heap, store
     813        );
     814    }
     815
     816    if (tempFileGuard.isOpen())
     817        tempFileGuard.remove();
     818
     819    return result;
     820}
     821
    347822static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
    348823{
    349     Q_UNUSED(fnt);
     824    if (QSymbianFontDatabaseExtrasImplementation::appFontLimitReached()
     825            || fnt->data.size() > ttfMaxFileSize // hard limit
     826            || fnt->data.isEmpty() && (!fnt->fileName.endsWith(QLatin1String(".ttf"), Qt::CaseInsensitive) // Only buffer or .ttf
     827                                       || QFileInfo(fnt->fileName).size() > ttfMaxFileSize)) // hard limit
     828        return;
     829
     830//    Using ttfCanSymbianLoadFont() causes crashes on app destruction (Symbian^3|PR1 and lower).
     831//    Therefore, not using it for now, but eventually in a later version.
     832//    if (!ttfCanSymbianLoadFont(fnt->data, fnt->fileName))
     833//        return;
     834
     835    QFontDatabasePrivate *db = privateDb();
     836    if (!db)
     837        return;
     838
     839    if (!db->count)
     840        initializeDb();
     841
     842    QSymbianFontDatabaseExtrasImplementation *dbExtras =
     843            static_cast<QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
     844    if (!dbExtras)
     845        return;
     846
     847    const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker();
     848
     849    // The QTemporaryFile object being used in the following section must be
     850    // destructed before letting Symbian load the TTF file. Symbian would not
     851    // load it otherwise, because QTemporaryFile will still keep some handle
     852    // on it. The scope is used to reduce the life time of the QTemporaryFile.
     853    // In order to prevent other processes from modifying the file between the
     854    // moment where the QTemporaryFile is destructed and the file is loaded by
     855    // Symbian, we have a QFile "tempFileGuard" outside the scope which opens
     856    // the file in ReadOnly mode while the QTemporaryFile is still alive.
     857    QFile tempFileGuard;
     858    {
     859        QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
     860                                + marker + QLatin1String("XXXXXX.ttf"));
     861        if (!tempfile.open())
     862            return;
     863        const QString tempFileName = QFileInfo(tempfile).canonicalFilePath();
     864        if (fnt->data.isEmpty()) {
     865            QFile sourceFile(fnt->fileName);
     866            if (!sourceFile.open(QIODevice::ReadOnly))
     867                return;
     868            fnt->data = sourceFile.readAll();
     869        }
     870        if (!ttfMarkAppFont(fnt->data, marker) || tempfile.write(fnt->data) == -1)
     871            return;
     872        tempfile.setAutoRemove(false);
     873        tempfile.close(); // Tempfile still keeps a file handle, forbidding write access
     874        fnt->data.clear(); // The TTF data was marked and saved. Not needed in memory, anymore.
     875        tempFileGuard.setFileName(tempFileName);
     876        if (!tempFileGuard.open(QIODevice::ReadOnly))
     877            return;
     878        fnt->temporaryFileName = tempFileName;
     879    }
     880
     881    const QString fullFileName = QDir::toNativeSeparators(fnt->temporaryFileName);
     882    QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
     883    const QStringList fontsOnServerBefore = qt_symbian_fontFamiliesOnFontServer();
     884    const TInt err =
     885            S60->screenDevice()->AddFile(qt_QString2TPtrC(fullFileName), fnt->screenDeviceFontFileId);
     886    tempFileGuard.close(); // Did its job
     887    const QStringList fontsOnServerAfter = qt_symbian_fontFamiliesOnFontServer();
     888    if (err == KErrNone && fontsOnServerBefore.count() < fontsOnServerAfter.count()) { // Added to screen device?
     889        int fontOnServerIndex = fontsOnServerAfter.count() - 1;
     890        for (int i = 0; i < fontsOnServerBefore.count(); i++) {
     891            if (fontsOnServerBefore.at(i) != fontsOnServerAfter.at(i)) {
     892                fontOnServerIndex = i;
     893                break;
     894            }
     895        }
     896
     897        // Must remove all font engines with their CFonts, first.
     898        QFontCache::instance()->clear();
     899        db->free();
     900        QSymbianFontDatabaseExtrasImplementation::clear();
     901
     902        if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable())
     903            fnt->fontStoreFontFileUid = dbExtras->addFontFileToFontStore(QFileInfo(fullFileName));
     904
     905        const QString &appFontName = fontsOnServerAfter.at(fontOnServerIndex);
     906        fnt->families.append(qt_symbian_appFontNameWithoutMarker(appFontName));
     907        if (!qt_symbian_fontNameHasAppFontMarker(appFontName)
     908                || !registerScreenDeviceFont(fontOnServerIndex, dbExtras))
     909            dbExtras->removeAppFontData(fnt);
     910    } else {
     911        if (fnt->screenDeviceFontFileId > 0)
     912            S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId); // May still have the file open!
     913        QFile::remove(fnt->temporaryFileName);
     914        *fnt = QFontDatabasePrivate::ApplicationFont();
     915    }
     916    lock.relock();
    350917}
    351918
    352919bool QFontDatabase::removeApplicationFont(int handle)
    353920{
    354     Q_UNUSED(handle);
    355     return false;
     921    QMutexLocker locker(fontDatabaseMutex());
     922
     923    QFontDatabasePrivate *db = privateDb();
     924    if (!db || handle < 0 || handle >= db->applicationFonts.count())
     925        return false;
     926    QSymbianFontDatabaseExtrasImplementation *dbExtras =
     927            static_cast<QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
     928    if (!dbExtras)
     929        return false;
     930
     931    QFontDatabasePrivate::ApplicationFont *fnt = &db->applicationFonts[handle];
     932    if (fnt->families.isEmpty())
     933        return true; // Nothing to remove. Return peacefully.
     934
     935    // Must remove all font engines with their CFonts, first
     936    QFontCache::instance()->clear();
     937    db->free();
     938    dbExtras->removeAppFontData(fnt);
     939
     940    db->invalidate(); // This will just emit 'fontDatabaseChanged()'
     941    return true;
    356942}
    357943
    358944bool QFontDatabase::removeAllApplicationFonts()
    359945{
    360     return false;
     946    QMutexLocker locker(fontDatabaseMutex());
     947
     948    const int applicationFontsCount = privateDb()->applicationFonts.count();
     949    for (int i = 0; i < applicationFontsCount; ++i)
     950        if (!removeApplicationFont(i))
     951            return false;
     952    return true;
    361953}
    362954
     
    377969}
    378970
    379 QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *, const QFontDef &req)
     971QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *d, const QFontDef &req)
    380972{
    381973    const QFontCache::Key key(cleanedFontDef(req), script);
     
    391983        QtFontDesc desc;
    392984        QList<int> blacklistedFamilies;
    393         match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies);
     985        match(script, key.def, key.def.family, QString(), -1, &desc, blacklistedFamilies);
    394986        if (!desc.family) // falling back to application font
    395987            desc.family = db->family(QApplication::font().defaultFamily());
     
    4171009        QFontDef request = req;
    4181010        request.family = fontFamily;
    419 #if defined(QT_NO_FREETYPE)
     1011#ifdef QT_NO_FREETYPE
    4201012        const QSymbianFontDatabaseExtrasImplementation *dbExtras =
    4211013                static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
    4221014        const QSymbianTypeFaceExtras *typeFaceExtras =
    4231015                dbExtras->extras(fontFamily, request.weight > QFont::Normal, request.style != QFont::StyleNormal);
     1016
     1017        // We need a valid pixelSize, e.g. for lineThickness()
     1018        if (request.pixelSize < 0)
     1019            request.pixelSize = request.pointSize * d->dpi / 72;
     1020
    4241021        fe = new QFontEngineS60(request, typeFaceExtras);
    425 #else
     1022#else // QT_NO_FREETYPE
     1023        Q_UNUSED(d)
    4261024        QFontEngine::FaceId faceId;
    4271025        const QtFontFamily * const reqQtFontFamily = db->family(fontFamily);
     
    4341032        else
    4351033            delete fte;
    436 #endif
     1034#endif // QT_NO_FREETYPE
    4371035
    4381036        Q_ASSERT(fe);
Note: See TracChangeset for help on using the changeset viewer.