From cfb7c16d738993fc8a594361f4bdf10e24fa754a Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 24 Jan 2011 21:43:03 +0100 Subject: Avoid possible font name collisions on fbserv QTBUG-6611 implemented the long awaited app font support on Symbian. One of the problems with the underlying Symbian Api for font loading is that all fonts go into one system wide font store on fbserv. All fonts are visible to and accessible by every application. And there is no way to find out if a font is an app font and whose process' app font it is. If a font with a certain family name is already loaded on fbserv, no other application can load its font with the same family name. If two applications access the same font, bad things can happen (details: QTBUG-16514). This patch works around naming collisions on the fbserv. It also prevents Qt applications from using other Qt applications' app fonts. It does so by "marking" the name of the temporary ttf file before the file gets loaded by fbserv. All font name strings in the font's 'name' table get a marker string appended. The marker is composed by a "Q", the uid3, and on Symbian^3|PR1&below the pid. The marker length is four characters. When the QFontDatabase is populated, all own app font names are cleand from the marker, so that the Qt app can use the original font name. Other applications' app fonts are detected and filtered out of the own font database. Symbian's font Api supports only 24 characters as names for font families. The name marker reduces the effective characters to 20. The reduced name length is documented for QFontDatabase::addApplication[FontFromData] as a note. Since the app font feature is much safer now, it got re-enabled for Symbian^1 and below by reverting 25ac59fcf1bb03c9af9a2c967218c96c7c77361a . Task-number: QTBUG-16514 --- src/gui/text/qfontdatabase.cpp | 4 + src/gui/text/qfontdatabase_s60.cpp | 357 ++++++++++++++++++++++++++++++++++--- src/gui/text/qfontengine_s60.cpp | 5 +- 3 files changed, 343 insertions(+), 23 deletions(-) diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 637957d..6b612eb 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -2543,6 +2543,8 @@ bool QFontDatabasePrivate::isApplicationFont(const QString &fileName) \note Adding application fonts on Unix/X11 platforms without fontconfig is currently not supported. + \note On Symbian, the font family names get truncated to a length of 20 characters. + \sa addApplicationFontFromData(), applicationFontFamilies(), removeApplicationFont() */ int QFontDatabase::addApplicationFont(const QString &fileName) @@ -2573,6 +2575,8 @@ int QFontDatabase::addApplicationFont(const QString &fileName) \bold{Note:} Adding application fonts on Unix/X11 platforms without fontconfig is currently not supported. + \note On Symbian, the font family names get truncated to a length of 20 characters. + \sa addApplicationFont(), applicationFontFamilies(), removeApplicationFont() */ int QFontDatabase::addApplicationFontFromData(const QByteArray &fontData) diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp index 06462c4..ad67189 100644 --- a/src/gui/text/qfontdatabase_s60.cpp +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -46,6 +46,7 @@ #include "qabstractfileengine.h" #include "qdesktopservices.h" #include "qtemporaryfile.h" +#include "qtextcodec.h" #include #include #include "qendian.h" @@ -152,10 +153,11 @@ public: mutable QList m_extras; mutable QHash m_extrasHash; + mutable QSet m_applicationFontFamilies; }; const QString QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix = - QLatin1String("qaf"); + QLatin1String("Q"); inline QString QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder() { @@ -166,21 +168,60 @@ QString QSymbianFontDatabaseExtrasImplementation::appFontMarker() { static QString result; if (result.isEmpty()) { - const quint32 uid = RProcess().Type().MostDerived().iUid; - quint16 crossSum = static_cast(uid + (uid >> 16)); - if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) { + quint16 id = 0; + if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) { + // We are allowed to load app fonts even from previous, crashed runs + // of this application, since we can access the font tables. + const quint32 uid = RProcess().Type().MostDerived().iUid; + id = static_cast(uid + (uid >> 16)); + } else { // If no font table Api is available, we must not even load a font // from a previous (crashed) run of this application. Reason: we // won't get the font tables, they are not in the CFontStore. - // So, we add the pid to the uniqueness of the marker. - const quint32 pid = static_cast(RProcess().Id().Id()); - crossSum += static_cast(pid + (pid >> 16)); + // So, we use the pid, for more uniqueness. + id = static_cast(RProcess().Id().Id()); } - result = appFontMarkerPrefix + QString::number(crossSum, 16); + result = appFontMarkerPrefix + QString::fromLatin1("%1").arg(id & 0x7fff, 3, 32, QLatin1Char('0')); + Q_ASSERT(appFontMarkerPrefix.length() == 1 && result.length() == 4); } return result; } +static inline bool qt_symbian_fontNameHasAppFontMarker(const QString &fontName) +{ + const int idLength = 3; // Keep in sync with id length in appFontMarker(). + const QString &prefix = QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix; + if (fontName.length() < prefix.length() + idLength + || fontName.mid(fontName.length() - idLength - prefix.length(), prefix.length()) != prefix) + return false; + // Testing if the the id is base32 data + for (int i = fontName.length() - idLength; i < fontName.length(); ++i) { + const QChar &c = fontName.at(i); + if (!(c >= QLatin1Char('0') && c <= QLatin1Char('9') + || c >= QLatin1Char('a') && c <= QLatin1Char('v'))) + return false; + } + return true; +} + +// If fontName is an application font of this app, prepend the app font marker +QString qt_symbian_fontNameWithAppFontMarker(const QString &fontName) +{ + QFontDatabasePrivate *db = privateDb(); + Q_ASSERT(db); + const QSymbianFontDatabaseExtrasImplementation *dbExtras = + static_cast(db->symbianExtras); + return dbExtras->m_applicationFontFamilies.contains(fontName) ? + fontName + QSymbianFontDatabaseExtrasImplementation::appFontMarker() + : fontName; +} + +static inline QString qt_symbian_appFontNameWithoutMarker(const QString &markedFontName) +{ + return markedFontName.left(markedFontName.length() + - QSymbianFontDatabaseExtrasImplementation::appFontMarker().length()); +} + QSymbianFontDatabaseExtrasImplementation::QSymbianFontDatabaseExtrasImplementation() { if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) { @@ -276,9 +317,10 @@ COpenFont* OpenFontFromBitmapFont(const CBitmapFont* aBitmapFont) } #endif // FNTSTORE_H_INLINES_SUPPORT_FMM -const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &typeface, +const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &aTypeface, bool bold, bool italic) const { + const QString typeface = qt_symbian_fontNameWithAppFontMarker(aTypeface); const QString searchKey = typeface + QString::number(int(bold)) + QString::number(int(italic)); if (!m_extrasHash.contains(searchKey)) { TFontSpec searchSpec(qt_QString2TPtrC(typeface), 1); @@ -331,6 +373,8 @@ void QSymbianFontDatabaseExtrasImplementation::removeAppFontData( if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable() && fnt->fontStoreFontFileUid.iUid != 0) m_store->RemoveFile(fnt->fontStoreFontFileUid); + if (!fnt->families.isEmpty()) + m_applicationFontFamilies.remove(fnt->families.first()); if (fnt->screenDeviceFontFileId != 0) S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId); QFile::remove(fnt->temporaryFileName); @@ -425,6 +469,18 @@ static bool registerScreenDeviceFont(int screenDeviceFontIndex, { TTypefaceSupport typefaceSupport; S60->screenDevice()->TypefaceSupport(typefaceSupport, screenDeviceFontIndex); + + QString familyName((const QChar*)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length()); + if (qt_symbian_fontNameHasAppFontMarker(familyName)) { + const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker(); + if (familyName.endsWith(marker)) { + familyName = qt_symbian_appFontNameWithoutMarker(familyName); + dbExtras->m_applicationFontFamilies.insert(familyName); + } else { + return false; // This was somebody else's application font. Skip it. + } + } + CFont *font; // We have to get a font instance in order to know all the details TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11); if (S60->screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone) @@ -440,7 +496,6 @@ static bool registerScreenDeviceFont(int screenDeviceFontIndex, styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal; styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal; - QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length()); QtFontFamily *family = privateDb()->family(familyName, true); family->fixedPitch = faceAttrib.IsMonoWidth(); QtFontFoundry *foundry = family->foundry(QString(), true); @@ -515,14 +570,268 @@ static inline void load(const QString &family = QString(), int script = -1) initializeDb(); } -static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) +struct OffsetTable { + quint32 sfntVersion; + quint16 numTables, searchRange, entrySelector, rangeShift; +}; + +struct TableRecord { + quint32 tag, checkSum, offset, length; +}; + +struct NameTableHead { + quint16 format, count, stringOffset; +}; + +struct NameRecord { + quint16 platformID, encodingID, languageID, nameID, length, offset; +}; + +static quint32 ttfCalcChecksum(const char *data, quint32 bytesCount) +{ + quint32 result = 0; + const quint32 *ptr = reinterpret_cast(data); + const quint32 *endPtr = + ptr + (bytesCount + sizeof(quint32) - 1) / sizeof(quint32); + while (ptr < endPtr) { + const quint32 unit32Value = *ptr++; + result += qFromBigEndian(unit32Value); + } + return result; +} + +static inline quint32 toDWordBoundary(quint32 value) +{ + return (value + 3) & ~3; +} + +static inline quint32 dWordPadding(quint32 value) +{ + return (4 - (value & 3)) & 3; +} + +static inline bool ttfMarkNameTable(QByteArray &table, const QString &marker) +{ + const quint32 tableLength = static_cast(table.size()); + + if (tableLength > 50000 // hard limit + || tableLength < sizeof(NameTableHead)) // corrupt name table + return false; + + const NameTableHead *head = reinterpret_cast(table.constData()); + const quint16 count = qFromBigEndian(head->count); + const quint16 stringOffset = qFromBigEndian(head->stringOffset); + if (count > 200 // hard limit + || stringOffset >= tableLength // corrupt name table + || sizeof(NameTableHead) + count * sizeof(NameRecord) >= tableLength) // corrupt name table + return false; + + QTextEncoder encoder(QTextCodec::codecForName("UTF-16BE"), QTextCodec::IgnoreHeader); + const QByteArray markerUtf16BE = encoder.fromUnicode(marker); + const QByteArray markerAscii = marker.toAscii(); + + QByteArray markedTable; + markedTable.reserve(tableLength + marker.length() * 20); // Original size plus some extra + markedTable.append(table, stringOffset); + QByteArray markedStrings; + quint32 stringDataCount = stringOffset; + for (quint16 i = 0; i < count; ++i) { + const quint32 nameRecordOffset = sizeof(NameTableHead) + sizeof(NameRecord) * i; + NameRecord *nameRecord = + reinterpret_cast(markedTable.data() + nameRecordOffset); + const quint16 nameID = qFromBigEndian(nameRecord->nameID); + const quint16 platformID = qFromBigEndian(nameRecord->platformID); + const quint16 encodingID = qFromBigEndian(nameRecord->encodingID); + const quint16 offset = qFromBigEndian(nameRecord->offset); + const quint16 length = qFromBigEndian(nameRecord->length); + stringDataCount += length; + if (stringDataCount > 80000 // hard limit. String data may be > name table size. Multiple records can reference the same string. + || static_cast(stringOffset + offset + length) > tableLength) // String outside bounds + return false; + const bool needsMarker = + nameID == 1 || nameID == 3 || nameID == 4 || nameID == 16 || nameID == 21; + const bool isUnicode = + platformID == 0 || platformID == 3 && encodingID == 1; + const QByteArray originalString = + QByteArray::fromRawData(table.constData() + stringOffset + offset, length); + QByteArray markedString; + if (needsMarker) { + const int maxBytesLength = (KMaxTypefaceNameLength - marker.length()) * (isUnicode ? 2 : 1); + markedString = originalString.left(maxBytesLength) + (isUnicode ? markerUtf16BE : markerAscii); + } else { + markedString = originalString; + } + nameRecord->offset = qToBigEndian(static_cast(markedStrings.length())); + nameRecord->length = qToBigEndian(static_cast(markedString.length())); + markedStrings.append(markedString); + } + markedTable.append(markedStrings); + table = markedTable; + return true; +} + +const quint32 ttfMaxFileSize = 3500000; + +static inline bool ttfMarkAppFont(QByteArray &ttf, const QString &marker) { - if (QSysInfo::symbianVersion() <= QSysInfo::SV_SF_2) - return; // See QTBUG-16514 for what 'font collisions' can cause in Symbian^1 and lower + const quint32 ttfChecksumNumber = 0xb1b0afba; + const quint32 alignment = 4; + const quint32 ttfLength = static_cast(ttf.size()); + if (ttfLength > ttfMaxFileSize // hard limit + || ttfLength % alignment != 0 // ttf sizes are always factors of 4 + || ttfLength <= sizeof(OffsetTable) // ttf too short + || ttfCalcChecksum(ttf.constData(), ttf.size()) != ttfChecksumNumber) // ttf checksum is invalid + return false; + + const OffsetTable *offsetTable = reinterpret_cast(ttf.constData()); + const quint16 numTables = qFromBigEndian(offsetTable->numTables); + const quint32 recordsLength = + toDWordBoundary(sizeof(OffsetTable) + numTables * sizeof(TableRecord)); + if (numTables > 30 // hard limit + || recordsLength + numTables * alignment > ttfLength) // Corrupt ttf. Tables would not fit, even if empty. + return false; + + QByteArray markedTtf; + markedTtf.reserve(ttfLength + marker.length() * 20); // Original size plus some extra + markedTtf.append(ttf.constData(), recordsLength); + + const quint32 ttfCheckSumAdjustmentOffset = 8; // Offset from the start of 'head' + int indexOfHeadTable = -1; + quint32 ttfDataSize = recordsLength; + typedef QPair Range; + QList memoryRanges; + memoryRanges.reserve(numTables); + for (int i = 0; i < numTables; ++i) { + TableRecord *tableRecord = + reinterpret_cast(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord)); + const quint32 offset = qFromBigEndian(tableRecord->offset); + const quint32 length = qFromBigEndian(tableRecord->length); + const quint32 lengthAligned = toDWordBoundary(length); + ttfDataSize += lengthAligned; + if (offset < recordsLength // must not intersect ttf header/records + || offset % alignment != 0 // must be aligned + || offset > ttfLength - alignment // table out of bounds + || offset + lengthAligned > ttfLength // table out of bounds + || ttfDataSize > ttfLength) // tables would not fit into the ttf + return false; - if (QSymbianFontDatabaseExtrasImplementation::appFontLimitReached()) + foreach (const Range &range, memoryRanges) + if (offset < range.first + range.second && offset + lengthAligned > range.first) + return false; // Overlaps with another table + memoryRanges.append(Range(offset, lengthAligned)); + + quint32 checkSum = qFromBigEndian(tableRecord->checkSum); + if (tableRecord->tag == qToBigEndian('head')) { + if (length < ttfCheckSumAdjustmentOffset + sizeof(quint32)) + return false; // Invalid 'head' table + const quint32 *checkSumAdjustmentTag = + reinterpret_cast(ttf.constData() + offset + ttfCheckSumAdjustmentOffset); + const quint32 checkSumAdjustment = qFromBigEndian(*checkSumAdjustmentTag); + checkSum += checkSumAdjustment; + indexOfHeadTable = i; // For the ttf checksum re-calculation, later + } + if (checkSum != ttfCalcChecksum(ttf.constData() + offset, length)) + return false; // Table checksum is invalid + + bool updateTableChecksum = false; + QByteArray table; + if (tableRecord->tag == qToBigEndian('name')) { + table = QByteArray(ttf.constData() + offset, length); + if (!ttfMarkNameTable(table, marker)) + return false; // Name table was not markable. + updateTableChecksum = true; + } else { + table = QByteArray::fromRawData(ttf.constData() + offset, length); + } + + tableRecord->offset = qToBigEndian(markedTtf.size()); + tableRecord->length = qToBigEndian(table.size()); + markedTtf.append(table); + markedTtf.append(QByteArray(dWordPadding(table.size()), 0)); // 0-padding + if (updateTableChecksum) { + TableRecord *tableRecord = // Need to recalculate, since markedTtf changed + reinterpret_cast(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord)); + const quint32 offset = qFromBigEndian(tableRecord->offset); + const quint32 length = qFromBigEndian(tableRecord->length); + tableRecord->checkSum = qToBigEndian(ttfCalcChecksum(markedTtf.constData() + offset, length)); + } + } + if (indexOfHeadTable == -1 // 'head' table is mandatory + || ttfDataSize != ttfLength) // We do not allow ttf data "holes". Neither does Symbian. + return false; + TableRecord *headRecord = + reinterpret_cast(markedTtf.data() + sizeof(OffsetTable) + indexOfHeadTable * sizeof(TableRecord)); + quint32 *checkSumAdjustmentTag = + reinterpret_cast(markedTtf.data() + qFromBigEndian(headRecord->offset) + ttfCheckSumAdjustmentOffset); + *checkSumAdjustmentTag = 0; + const quint32 ttfChecksum = ttfCalcChecksum(markedTtf.constData(), markedTtf.count()); + *checkSumAdjustmentTag = qToBigEndian(ttfChecksumNumber - ttfChecksum); + ttf = markedTtf; + return true; +} + +static inline bool ttfCanSymbianLoadFont(const QByteArray &data, const QString &fileName) +{ + bool result = false; + QString ttfFileName; + QFile tempFileGuard; + QFileInfo info(fileName); + if (!data.isEmpty()) { + QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder() + + QSymbianFontDatabaseExtrasImplementation::appFontMarker() + + QLatin1String("XXXXXX.ttf")); + if (!tempfile.open() || tempfile.write(data) == -1) + return false; + ttfFileName = QDir::toNativeSeparators(QFileInfo(tempfile).canonicalFilePath()); + tempfile.setAutoRemove(false); + tempfile.close(); + tempFileGuard.setFileName(ttfFileName); + if (!tempFileGuard.open(QIODevice::ReadOnly)) + return false; + } else if (info.isFile()) { + ttfFileName = QDir::toNativeSeparators(info.canonicalFilePath()); + } else { + return false; + } + + CFontStore *store = 0; + RHeap* heap = User::ChunkHeap(NULL, 0x1000, 0x20000); + if (heap) { + QT_TRAP_THROWING( + CleanupClosePushL(*heap); + store = CFontStore::NewL(heap); + CleanupStack::PushL(store); + COpenFontRasterizer *rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E)); + CleanupStack::PushL(rasterizer); + store->InstallRasterizerL(rasterizer); + CleanupStack::Pop(rasterizer); + TUid fontUid = {-1}; + TRAP_IGNORE(fontUid = store->AddFileL(qt_QString2TPtrC(ttfFileName))); + if (fontUid.iUid != -1) + result = true; + CleanupStack::PopAndDestroy(2, heap); // heap, store + ); + } + + if (tempFileGuard.isOpen()) + tempFileGuard.remove(); + + return result; +} + +static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) +{ + if (QSymbianFontDatabaseExtrasImplementation::appFontLimitReached() + || fnt->data.size() > ttfMaxFileSize // hard limit + || fnt->data.isEmpty() && (!fnt->fileName.endsWith(QLatin1String(".ttf"), Qt::CaseInsensitive) // Only buffer or .ttf + || QFileInfo(fnt->fileName).size() > ttfMaxFileSize)) // hard limit return; +// Using ttfCanSymbianLoadFont() causes crashes on app destruction (Symbian^3|PR1 and lower). +// Therefore, not using it for now, but eventually in a later version. +// if (!ttfCanSymbianLoadFont(fnt->data, fnt->fileName)) +// return; + QFontDatabasePrivate *db = privateDb(); if (!db) return; @@ -530,13 +839,13 @@ static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) if (!db->count) initializeDb(); - if (fnt->data.isEmpty() && !fnt->fileName.endsWith(QLatin1String(".ttf"), Qt::CaseInsensitive)) - return; // Only buffer or .ttf QSymbianFontDatabaseExtrasImplementation *dbExtras = static_cast(db->symbianExtras); if (!dbExtras) return; + const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker(); + // The QTemporaryFile object being used in the following section must be // destructed before letting Symbian load the TTF file. Symbian would not // load it otherwise, because QTemporaryFile will still keep some handle @@ -548,8 +857,7 @@ static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) QFile tempFileGuard; { QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder() - + QSymbianFontDatabaseExtrasImplementation::appFontMarker() - + QLatin1String("XXXXXX.ttf")); + + marker + QLatin1String("XXXXXX.ttf")); if (!tempfile.open()) return; const QString tempFileName = QFileInfo(tempfile).canonicalFilePath(); @@ -559,10 +867,11 @@ static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) return; fnt->data = sourceFile.readAll(); } - if (tempfile.write(fnt->data) == -1) + if (!ttfMarkAppFont(fnt->data, marker) || tempfile.write(fnt->data) == -1) return; tempfile.setAutoRemove(false); tempfile.close(); // Tempfile still keeps a file handle, forbidding write access + fnt->data.clear(); // The TTF data was marked and saved. Not needed in memory, anymore. tempFileGuard.setFileName(tempFileName); if (!tempFileGuard.open(QIODevice::ReadOnly)) return; @@ -593,10 +902,14 @@ static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) fnt->fontStoreFontFileUid = dbExtras->addFontFileToFontStore(QFileInfo(fullFileName)); - fnt->families.append(fontsOnServerAfter.at(fontOnServerIndex)); - if (!registerScreenDeviceFont(fontOnServerIndex, dbExtras)) + const QString &appFontName = fontsOnServerAfter.at(fontOnServerIndex); + fnt->families.append(qt_symbian_appFontNameWithoutMarker(appFontName)); + if (!qt_symbian_fontNameHasAppFontMarker(appFontName) + || !registerScreenDeviceFont(fontOnServerIndex, dbExtras)) dbExtras->removeAppFontData(fnt); } else { + if (fnt->screenDeviceFontFileId > 0) + S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId); // May still have the file open! QFile::remove(fnt->temporaryFileName); *fnt = QFontDatabasePrivate::ApplicationFont(); } @@ -669,7 +982,7 @@ QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *d, const QF QFontDatabasePrivate *db = privateDb(); QtFontDesc desc; QList blacklistedFamilies; - match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies); + match(script, key.def, key.def.family, QString(), -1, &desc, blacklistedFamilies); if (!desc.family) // falling back to application font desc.family = db->family(QApplication::font().defaultFamily()); Q_ASSERT(desc.family); diff --git a/src/gui/text/qfontengine_s60.cpp b/src/gui/text/qfontengine_s60.cpp index b572cdd..f2b6f5c 100644 --- a/src/gui/text/qfontengine_s60.cpp +++ b/src/gui/text/qfontengine_s60.cpp @@ -243,10 +243,13 @@ static inline unsigned int getChar(const QChar *str, int &i, const int len) return uc; } +extern QString qt_symbian_fontNameWithAppFontMarker(const QString &fontName); // qfontdatabase_s60.cpp + CFont *QFontEngineS60::fontWithSize(qreal size) const { CFont *result = 0; - TFontSpec fontSpec(qt_QString2TPtrC(QFontEngine::fontDef.family), TInt(size)); + const QString family = qt_symbian_fontNameWithAppFontMarker(QFontEngine::fontDef.family); + TFontSpec fontSpec(qt_QString2TPtrC(family), TInt(size)); fontSpec.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap); fontSpec.iFontStyle.SetPosture(QFontEngine::fontDef.style == QFont::StyleNormal?EPostureUpright:EPostureItalic); fontSpec.iFontStyle.SetStrokeWeight(QFontEngine::fontDef.weight > QFont::Normal?EStrokeWeightBold:EStrokeWeightNormal); -- cgit v0.12