Fix freetype font rendering for Windows CE

Windows CE does not have support for GetGlyphOutline.
So addGlyphToPath will not work. QML uses it for their
distance field rendering. One option to bypass this issue
is to use freetype as rendering backend.

Change-Id: I965254344945cbdad771a5d505fb61c1cc2087df
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
This commit is contained in:
Andreas Holzammer 2012-08-20 11:25:41 +02:00 committed by Qt by Nokia
parent 806dda08d6
commit f2fabf77f9
7 changed files with 185 additions and 2 deletions

View File

@ -182,7 +182,7 @@ typedef unsigned long ulg;
#endif
/* Diagnostic functions */
#ifdef DEBUG
#if defined(DEBUG) && !defined(_WIN32_WCE)
# include <stdio.h>
extern int z_verbose;
extern void z_error OF((char *m));

View File

@ -48,6 +48,7 @@
#include <QtCore/QLibraryInfo>
#include <QtCore/QDir>
#include <QtCore/QUuid>
#include <QtCore/QtEndian>
#undef QT_NO_FREETYPE
#include <QtGui/private/qfontengine_ft_p.h>
@ -135,6 +136,37 @@ static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
{ 14, 127 },
};
typedef struct {
quint16 majorVersion;
quint16 minorVersion;
quint16 numTables;
quint16 searchRange;
quint16 entrySelector;
quint16 rangeShift;
} OFFSET_TABLE;
typedef struct {
quint32 tag;
quint32 checkSum;
quint32 offset;
quint32 length;
} TABLE_DIRECTORY;
typedef struct {
quint16 fontSelector;
quint16 nrCount;
quint16 storageOffset;
} NAME_TABLE_HEADER;
typedef struct {
quint16 platformID;
quint16 encodingID;
quint16 languageID;
quint16 nameID;
quint16 stringLength;
quint16 stringOffset;
} NAME_RECORD;
QSupportedWritingSystems QBasicFontDatabase::determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2])
{
QSupportedWritingSystems writingSystems;
@ -430,4 +462,92 @@ QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByt
return families;
}
QString QBasicFontDatabase::fontNameFromTTFile(const QString &filename)
{
QFile f(filename);
QString retVal;
qint64 bytesRead;
qint64 bytesToRead;
if (f.open(QIODevice::ReadOnly)) {
OFFSET_TABLE ttOffsetTable;
bytesToRead = sizeof(OFFSET_TABLE);
bytesRead = f.read((char*)&ttOffsetTable, bytesToRead);
if (bytesToRead != bytesRead)
return retVal;
ttOffsetTable.numTables = qFromBigEndian(ttOffsetTable.numTables);
ttOffsetTable.majorVersion = qFromBigEndian(ttOffsetTable.majorVersion);
ttOffsetTable.minorVersion = qFromBigEndian(ttOffsetTable.minorVersion);
if (ttOffsetTable.majorVersion != 1 || ttOffsetTable.minorVersion != 0)
return retVal;
TABLE_DIRECTORY tblDir;
bool found = false;
for (int i = 0; i < ttOffsetTable.numTables; i++) {
bytesToRead = sizeof(TABLE_DIRECTORY);
bytesRead = f.read((char*)&tblDir, bytesToRead);
if (bytesToRead != bytesRead)
return retVal;
if (qFromBigEndian(tblDir.tag) == MAKE_TAG('n', 'a', 'm', 'e')) {
found = true;
tblDir.length = qFromBigEndian(tblDir.length);
tblDir.offset = qFromBigEndian(tblDir.offset);
break;
}
}
if (found) {
f.seek(tblDir.offset);
NAME_TABLE_HEADER ttNTHeader;
bytesToRead = sizeof(NAME_TABLE_HEADER);
bytesRead = f.read((char*)&ttNTHeader, bytesToRead);
if (bytesToRead != bytesRead)
return retVal;
ttNTHeader.nrCount = qFromBigEndian(ttNTHeader.nrCount);
ttNTHeader.storageOffset = qFromBigEndian(ttNTHeader.storageOffset);
NAME_RECORD ttRecord;
found = false;
for (int i = 0; i < ttNTHeader.nrCount; i++) {
bytesToRead = sizeof(NAME_RECORD);
bytesRead = f.read((char*)&ttRecord, bytesToRead);
if (bytesToRead != bytesRead)
return retVal;
ttRecord.nameID = qFromBigEndian(ttRecord.nameID);
if (ttRecord.nameID == 1) {
ttRecord.stringLength = qFromBigEndian(ttRecord.stringLength);
ttRecord.stringOffset = qFromBigEndian(ttRecord.stringOffset);
int nPos = f.pos();
f.seek(tblDir.offset + ttRecord.stringOffset + ttNTHeader.storageOffset);
QByteArray nameByteArray = f.read(ttRecord.stringLength);
if (!nameByteArray.isEmpty()) {
if (ttRecord.encodingID == 256 || ttRecord.encodingID == 768) {
//This is UTF-16 in big endian
int stringLength = ttRecord.stringLength / 2;
retVal.resize(stringLength);
QChar *data = retVal.data();
const ushort *srcData = (const ushort *)nameByteArray.data();
for (int i = 0; i < stringLength; ++i)
data[i] = qFromBigEndian(srcData[i]);
return retVal;
} else if (ttRecord.encodingID == 0) {
//This is Latin1
retVal = QString::fromLatin1(nameByteArray);
} else {
qWarning("Could not retrieve Font name from file: %s", qPrintable(QDir::toNativeSeparators(filename)));
}
break;
}
f.seek(nPos);
}
}
}
f.close();
}
return retVal;
}
QT_END_NAMESPACE

View File

@ -66,6 +66,7 @@ public:
static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file);
static QSupportedWritingSystems determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]);
static QString fontNameFromTTFile(const QString &filename);
};
QT_END_NAMESPACE

View File

@ -47,6 +47,7 @@
#include FT_TRUETYPE_TABLES_H
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtCore/QSettings>
#include <QtGui/private/qfontengine_ft_p.h>
#include <QtGui/QGuiApplication>
@ -189,6 +190,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
writingSystems.setSupported(ws);
}
#ifndef Q_OS_WINCE
const QSettings fontRegistry(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"),
QSettings::NativeFormat);
@ -225,6 +227,51 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
if (!value.isEmpty())
break;
}
#else
QString value;
int index = 0;
static QHash<QString, QString> fontCache;
if (fontCache.isEmpty()) {
QSettings settings(QSettings::SystemScope, QStringLiteral("Qt-Project"), QStringLiteral("Qtbase"));
settings.beginGroup(QStringLiteral("CEFontCache"));
foreach (const QString &fontName, settings.allKeys()) {
const QString fontFileName = settings.value(fontName).toString();
fontCache.insert(fontName, fontFileName);
}
settings.endGroup(); // CEFontCache
}
value = fontCache.value(faceName);
//Fallback if we havent cached the font yet or the font got removed/renamed iterate again over all fonts
if (value.isEmpty() || !QFile::exists(value)) {
QSettings settings(QSettings::SystemScope, QStringLiteral("Qt-Project"), QStringLiteral("Qtbase"));
settings.beginGroup(QStringLiteral("CEFontCache"));
//empty the cache first, as it seems that it is dirty
foreach (const QString &fontName, settings.allKeys())
settings.remove(fontName);
QDirIterator it(QStringLiteral("/Windows"), QStringList(QStringLiteral("*.ttf")), QDir::Files | QDir::Hidden | QDir::System);
while (it.hasNext()) {
const QString fontFile = it.next();
const QString fontName = QBasicFontDatabase::fontNameFromTTFile(fontFile);
if (fontName.isEmpty())
continue;
fontCache.insert(fontName, fontFile);
settings.setValue(fontName, fontFile);
}
value = fontCache.value(faceName);
settings.endGroup(); // CEFontCache
}
#endif
if (value.isEmpty())
return false;

View File

@ -4,6 +4,7 @@ TARGET = tst_qfontdatabase
SOURCES += tst_qfontdatabase.cpp
DEFINES += SRCDIR=\\\"$$PWD\\\"
QT += testlib
!mac: QT += core-private gui-private platformsupport-private
wince* {
additionalFiles.files = FreeMono.ttf

View File

@ -44,6 +44,9 @@
#include <qfontdatabase.h>
#include <qfontinfo.h>
#include <qfontmetrics.h>
#ifndef Q_OS_MAC
#include <QtPlatformSupport/private/qbasicfontdatabase_p.h>
#endif
class tst_QFontDatabase : public QObject
{
@ -73,6 +76,10 @@ private slots:
void addAppFont_data();
void addAppFont();
#ifndef Q_OS_MAC
void fontName();
#endif
};
tst_QFontDatabase::tst_QFontDatabase()
@ -268,5 +275,13 @@ void tst_QFontDatabase::addAppFont()
QCOMPARE(db.families(), oldFamilies);
}
#ifndef Q_OS_MAC
void tst_QFontDatabase::fontName()
{
QString fontName = QBasicFontDatabase::fontNameFromTTFile(QStringLiteral("FreeMono.ttf"));
QCOMPARE(fontName, QStringLiteral("FreeMono"));
}
#endif
QTEST_MAIN(tst_QFontDatabase)
#include "tst_qfontdatabase.moc"

View File

@ -1482,7 +1482,6 @@ void Configure::applySpecSpecifics()
dictionary[ "STYLE_WINDOWSMOBILE" ] = "yes";
dictionary[ "STYLE_MOTIF" ] = "no";
dictionary[ "STYLE_CDE" ] = "no";
dictionary[ "FREETYPE" ] = "no";
dictionary[ "OPENGL" ] = "no";
dictionary[ "OPENSSL" ] = "no";
dictionary[ "RTTI" ] = "no";