summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2011-01-26 00:46:16 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2011-01-26 00:46:16 (GMT)
commitb885787eee96f444e73c7a9d6f6b63f65ef2c172 (patch)
tree6155bcb6bd920c6dd021218d93126c12c3db07a1 /src/gui/text
parent57a4353c8e082dfc0f536a1e642e4a8df0e5b9c9 (diff)
parent5422e929cad04633a06c156cba96cfcd69262522 (diff)
downloadQt-b885787eee96f444e73c7a9d6f6b63f65ef2c172.zip
Qt-b885787eee96f444e73c7a9d6f6b63f65ef2c172.tar.gz
Qt-b885787eee96f444e73c7a9d6f6b63f65ef2c172.tar.bz2
Merge branch 'qt-master-from-4.7' of scm.dev.nokia.troll.no:qt/qt-integration into master-integration
* 'qt-master-from-4.7' of scm.dev.nokia.troll.no:qt/qt-integration: (67 commits) Avoid possible font name collisions on fbserv Update of Czech translation for Qt 4.7-stable Fix crash in QtScript/JSC stack allocator on Symbian HTTP: fix digest authentication Fix loop count in animanted gifs sometimes being incorrect Fixed UTF-8 application names in device application menu in Symbian Validate arguments to QDBusConnection::connect make the test a bit stricter ignore the warning from auto-detach in destructor get rid of extra calls to handle() simplify QSharedMemory::detach() avoid extra calculations fix error reporting on detach() fix error reporting Make QMAKE_EXTENSION_SHLIB and friends work in all Symbian mkspecs. Fix to pen state handling in OpenVG paint engine. BorderImage fails for .sci source containing a URL positionViewAtIndex can fail when positioned near end of list. Revert "Fix loaded() signal to be emitted only once" Revert "don't include harfbuzz where we don't use it" ...
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qfontdatabase.cpp20
-rw-r--r--src/gui/text/qfontdatabase_s60.cpp551
-rw-r--r--src/gui/text/qfontengine_s60.cpp5
3 files changed, 550 insertions, 26 deletions
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 20c72dd..8e92b1a 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -646,6 +646,10 @@ public:
{ }
~QFontDatabasePrivate() {
free();
+#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
+ if (symbianExtras)
+ delete symbianExtras;
+#endif
}
QtFontFamily *family(const QString &f, bool = false);
void free() {
@@ -654,12 +658,6 @@ public:
::free(families);
families = 0;
count = 0;
-#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
- if (symbianExtras) {
- delete symbianExtras;
- symbianExtras = 0;
- }
-#endif
// don't clear the memory fonts!
}
@@ -678,6 +676,10 @@ public:
QVector<FONTSIGNATURE> signatures;
#elif defined(Q_WS_MAC)
ATSFontContainerRef handle;
+#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
+ QString temporaryFileName;
+ TInt screenDeviceFontFileId;
+ TUid fontStoreFontFileUid;
#endif
QStringList families;
};
@@ -704,7 +706,7 @@ public:
#if defined(Q_WS_QWS)
QDataStream *stream;
#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
- const QSymbianFontDatabaseExtras *symbianExtras;
+ QSymbianFontDatabaseExtras *symbianExtras;
#endif
#if defined(Q_WS_QWS) || defined(Q_WS_QPA)
QStringList fallbackFamilies;
@@ -2573,6 +2575,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)
@@ -2603,6 +2607,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 6ba035e..ad67189 100644
--- a/src/gui/text/qfontdatabase_s60.cpp
+++ b/src/gui/text/qfontdatabase_s60.cpp
@@ -45,6 +45,8 @@
#include "qfontengine_s60_p.h"
#include "qabstractfileengine.h"
#include "qdesktopservices.h"
+#include "qtemporaryfile.h"
+#include "qtextcodec.h"
#include <private/qpixmap_s60_p.h>
#include <private/qt_s60_p.h>
#include "qendian.h"
@@ -114,7 +116,14 @@ public:
~QSymbianFontDatabaseExtrasImplementation();
const QSymbianTypeFaceExtras *extras(const QString &typeface, bool bold, bool italic) const;
- void addFontFileToFontStore(const QFileInfo &fontFileInfo);
+ void removeAppFontData(QFontDatabasePrivate::ApplicationFont *fnt);
+ static inline bool appFontLimitReached();
+ TUid addFontFileToFontStore(const QFileInfo &fontFileInfo);
+ static void clear();
+
+ static inline QString tempAppFontFolder();
+ static const QString appFontMarkerPrefix;
+ static QString appFontMarker(); // 'qaf<shortUid[+shortPid]>'
struct CFontFromFontStoreReleaser {
static inline void cleanup(CFont *font)
@@ -144,8 +153,75 @@ public:
mutable QList<const QSymbianTypeFaceExtras *> m_extras;
mutable QHash<QString, const QSymbianTypeFaceExtras *> m_extrasHash;
+ mutable QSet<QString> m_applicationFontFamilies;
};
+const QString QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix =
+ QLatin1String("Q");
+
+inline QString QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
+{
+ return QDir::toNativeSeparators(QDir::tempPath()) + QLatin1Char('\\');
+}
+
+QString QSymbianFontDatabaseExtrasImplementation::appFontMarker()
+{
+ static QString result;
+ if (result.isEmpty()) {
+ 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<quint16>(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 use the pid, for more uniqueness.
+ id = static_cast<quint16>(RProcess().Id().Id());
+ }
+ 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<const QSymbianFontDatabaseExtrasImplementation*>(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()) {
@@ -170,10 +246,13 @@ QSymbianFontDatabaseExtrasImplementation::QSymbianFontDatabaseExtrasImplementati
}
}
-void qt_cleanup_symbianFontDatabaseExtras()
+void QSymbianFontDatabaseExtrasImplementation::clear()
{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db)
+ return;
const QSymbianFontDatabaseExtrasImplementation *dbExtras =
- static_cast<const QSymbianFontDatabaseExtrasImplementation*>(privateDb()->symbianExtras);
+ static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
if (!dbExtras)
return; // initializeDb() has never been called
if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
@@ -189,9 +268,32 @@ void qt_cleanup_symbianFontDatabaseExtras()
dbExtras->m_extrasHash.clear();
}
+void qt_cleanup_symbianFontDatabase()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db)
+ return;
+
+ QSymbianFontDatabaseExtrasImplementation::clear();
+
+ if (!db->applicationFonts.isEmpty()) {
+ QFontDatabase::removeAllApplicationFonts();
+ // We remove the left over temporary font files of Qt application.
+ // Active fonts are undeletable since the font server holds a handle
+ // on them, so we do not need to worry to delete other running
+ // applications' fonts.
+ const QDir dir(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder());
+ const QStringList filter(
+ QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix + QLatin1String("*.ttf"));
+ foreach (const QFileInfo &ttfFile, dir.entryInfoList(filter))
+ QFile(ttfFile.absoluteFilePath()).remove();
+ db->applicationFonts.clear();
+ }
+}
+
QSymbianFontDatabaseExtrasImplementation::~QSymbianFontDatabaseExtrasImplementation()
{
- qt_cleanup_symbianFontDatabaseExtras();
+ qt_cleanup_symbianFontDatabase();
if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
delete m_store;
m_heap->Close();
@@ -215,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);
@@ -263,12 +366,42 @@ const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(c
return m_extrasHash.value(searchKey);
}
-void QSymbianFontDatabaseExtrasImplementation::addFontFileToFontStore(const QFileInfo &fontFileInfo)
+void QSymbianFontDatabaseExtrasImplementation::removeAppFontData(
+ QFontDatabasePrivate::ApplicationFont *fnt)
+{
+ clear();
+ 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);
+ *fnt = QFontDatabasePrivate::ApplicationFont();
+}
+
+bool QSymbianFontDatabaseExtrasImplementation::appFontLimitReached()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db)
+ return false;
+ const int maxAppFonts = 5;
+ int registeredAppFonts = 0;
+ foreach (const QFontDatabasePrivate::ApplicationFont &appFont, db->applicationFonts)
+ if (!appFont.families.isEmpty() && ++registeredAppFonts == maxAppFonts)
+ return true;
+ return false;
+}
+
+TUid QSymbianFontDatabaseExtrasImplementation::addFontFileToFontStore(const QFileInfo &fontFileInfo)
{
Q_ASSERT(!QSymbianTypeFaceExtras::symbianFontTableApiAvailable());
const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath());
- TPtrC fontFilePtr(qt_QString2TPtrC(fontFile));
- QT_TRAP_THROWING(m_store->AddFileL(fontFilePtr));
+ const TPtrC fontFilePtr(qt_QString2TPtrC(fontFile));
+ TUid fontUid = {0};
+ TRAP_IGNORE(fontUid = m_store->AddFileL(fontFilePtr));
+ return fontUid;
}
#else // QT_NO_FREETYPE
@@ -331,11 +464,23 @@ void QFontEngineMultiS60::loadEngine(int at)
Q_ASSERT(engines[at]);
}
-static bool addFontToScreenDevice(int screenDeviceFontIndex,
- const QSymbianFontDatabaseExtrasImplementation *dbExtras)
-{
+static bool registerScreenDeviceFont(int screenDeviceFontIndex,
+ const QSymbianFontDatabaseExtrasImplementation *dbExtras)
+{
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)
@@ -351,7 +496,6 @@ static bool addFontToScreenDevice(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);
@@ -398,7 +542,12 @@ static void initializeDb()
const QSymbianFontDatabaseExtrasImplementation *dbExtras =
static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
for (int i = 0; i < numTypeFaces; i++)
- addFontToScreenDevice(i, dbExtras);
+ registerScreenDeviceFont(i, dbExtras);
+
+ // We have to clear/release all CFonts, here, in case one of the fonts is
+ // an application font of another running Qt app. Otherwise the other Qt app
+ // cannot remove it's application font, anymore -> "Zombie Font".
+ QSymbianFontDatabaseExtrasImplementation::clear();
lock.relock();
@@ -421,20 +570,386 @@ static inline void load(const QString &family = QString(), int script = -1)
initializeDb();
}
+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<const quint32*>(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<quint32>(table.size());
+
+ if (tableLength > 50000 // hard limit
+ || tableLength < sizeof(NameTableHead)) // corrupt name table
+ return false;
+
+ const NameTableHead *head = reinterpret_cast<const NameTableHead*>(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<NameRecord*>(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<quint32>(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<quint16>(markedStrings.length()));
+ nameRecord->length = qToBigEndian(static_cast<quint16>(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)
+{
+ const quint32 ttfChecksumNumber = 0xb1b0afba;
+ const quint32 alignment = 4;
+ const quint32 ttfLength = static_cast<quint32>(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<const OffsetTable*>(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<quint32, quint32> Range;
+ QList<Range> memoryRanges;
+ memoryRanges.reserve(numTables);
+ for (int i = 0; i < numTables; ++i) {
+ TableRecord *tableRecord =
+ reinterpret_cast<TableRecord*>(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;
+
+ 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<const quint32*>(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<TableRecord*>(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<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + indexOfHeadTable * sizeof(TableRecord));
+ quint32 *checkSumAdjustmentTag =
+ reinterpret_cast<quint32*>(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)
{
- Q_UNUSED(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;
+
+ if (!db->count)
+ initializeDb();
+
+ QSymbianFontDatabaseExtrasImplementation *dbExtras =
+ static_cast<QSymbianFontDatabaseExtrasImplementation*>(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
+ // on it. The scope is used to reduce the life time of the QTemporaryFile.
+ // In order to prevent other processes from modifying the file between the
+ // moment where the QTemporaryFile is destructed and the file is loaded by
+ // Symbian, we have a QFile "tempFileGuard" outside the scope which opens
+ // the file in ReadOnly mode while the QTemporaryFile is still alive.
+ QFile tempFileGuard;
+ {
+ QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
+ + marker + QLatin1String("XXXXXX.ttf"));
+ if (!tempfile.open())
+ return;
+ const QString tempFileName = QFileInfo(tempfile).canonicalFilePath();
+ if (fnt->data.isEmpty()) {
+ QFile sourceFile(fnt->fileName);
+ if (!sourceFile.open(QIODevice::ReadOnly))
+ return;
+ fnt->data = sourceFile.readAll();
+ }
+ 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;
+ fnt->temporaryFileName = tempFileName;
+ }
+
+ const QString fullFileName = QDir::toNativeSeparators(fnt->temporaryFileName);
+ QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
+ const QStringList fontsOnServerBefore = qt_symbian_fontFamiliesOnFontServer();
+ const TInt err =
+ S60->screenDevice()->AddFile(qt_QString2TPtrC(fullFileName), fnt->screenDeviceFontFileId);
+ tempFileGuard.close(); // Did its job
+ const QStringList fontsOnServerAfter = qt_symbian_fontFamiliesOnFontServer();
+ if (err == KErrNone && fontsOnServerBefore.count() < fontsOnServerAfter.count()) { // Added to screen device?
+ int fontOnServerIndex = fontsOnServerAfter.count() - 1;
+ for (int i = 0; i < fontsOnServerBefore.count(); i++) {
+ if (fontsOnServerBefore.at(i) != fontsOnServerAfter.at(i)) {
+ fontOnServerIndex = i;
+ break;
+ }
+ }
+
+ // Must remove all font engines with their CFonts, first.
+ QFontCache::instance()->clear();
+ db->free();
+ QSymbianFontDatabaseExtrasImplementation::clear();
+
+ if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable())
+ fnt->fontStoreFontFileUid = dbExtras->addFontFileToFontStore(QFileInfo(fullFileName));
+
+ 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();
+ }
+ lock.relock();
}
bool QFontDatabase::removeApplicationFont(int handle)
{
- Q_UNUSED(handle);
- return false;
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ if (!db || handle < 0 || handle >= db->applicationFonts.count())
+ return false;
+ QSymbianFontDatabaseExtrasImplementation *dbExtras =
+ static_cast<QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
+ if (!dbExtras)
+ return false;
+
+ QFontDatabasePrivate::ApplicationFont *fnt = &db->applicationFonts[handle];
+ if (fnt->families.isEmpty())
+ return true; // Nothing to remove. Return peacefully.
+
+ // Must remove all font engines with their CFonts, first
+ QFontCache::instance()->clear();
+ db->free();
+ dbExtras->removeAppFontData(fnt);
+
+ db->invalidate(); // This will just emit 'fontDatabaseChanged()'
+ return true;
}
bool QFontDatabase::removeAllApplicationFonts()
{
- return false;
+ QMutexLocker locker(fontDatabaseMutex());
+
+ const int applicationFontsCount = privateDb()->applicationFonts.count();
+ for (int i = 0; i < applicationFontsCount; ++i)
+ if (!removeApplicationFont(i))
+ return false;
+ return true;
}
bool QFontDatabase::supportsThreadedFontRendering()
@@ -467,7 +982,7 @@ QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *d, const QF
QFontDatabasePrivate *db = privateDb();
QtFontDesc desc;
QList<int> 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 4317ee6..e9b54e3 100644
--- a/src/gui/text/qfontengine_s60.cpp
+++ b/src/gui/text/qfontengine_s60.cpp
@@ -244,10 +244,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);