diff options
author | Jørgen Lind <jorgen.lind@nokia.com> | 2010-08-20 10:33:33 (GMT) |
---|---|---|
committer | Jørgen Lind <jorgen.lind@nokia.com> | 2010-09-02 13:25:37 (GMT) |
commit | 5e7fdcc7a4a2bb070ad7ece920ac5db81e3e6f77 (patch) | |
tree | 5a67130cd7144084adceed7c5e1697e650cee20f | |
parent | de66ffa4d7d057f0c782edc45374ad58322a0c4c (diff) | |
download | Qt-5e7fdcc7a4a2bb070ad7ece920ac5db81e3e6f77.zip Qt-5e7fdcc7a4a2bb070ad7ece920ac5db81e3e6f77.tar.gz Qt-5e7fdcc7a4a2bb070ad7ece920ac5db81e3e6f77.tar.bz2 |
Initial pluggable fontdatabase
QPlatformFontDatabase added. QPlatformIntegration now has a new virtual
function: QPlatformDatabase::fontDatabase() const. Most unix platform
plugins wants to follow the pattern implemented in directfb, linuxfb,
vnc etc. In the pro file do:
include(../fontdatabases/genericunix/genericunix.pri)
In the QPlatformIntegration class do:
and instansiate a QGenericFontDatabase in the constructor and return
it in the getter function.
49 files changed, 2894 insertions, 62 deletions
@@ -6093,6 +6093,30 @@ if [ "$PLATFORM_QPA" = "yes" ]; then exit 1 fi fi + + # auto-detect FontConfig support + if [ "$CFG_FONTCONFIG" != "no" ]; then + if [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists fontconfig --exists freetype2 2>/dev/null; then + QT_CFLAGS_FONTCONFIG=`$PKG_CONFIG --cflags fontconfig --cflags freetype2 2>/dev/null` + QT_LIBS_FONTCONFIG=`$PKG_CONFIG --libs fontconfig --libs freetype2 2>/dev/null` + else + QT_CFLAGS_FONTCONFIG= + QT_LIBS_FONTCONFIG="-lfreetype -lfontconfig" + fi + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/x11/fontconfig "FontConfig" $L_FLAGS $I_FLAGS $l_FLAGS $X11TESTS_FLAGS $QT_CFLAGS_FONTCONFIG $QT_LIBS_FONTCONFIG; then + QT_CONFIG="$QT_CONFIG fontconfig" + QMakeVar set QMAKE_CFLAGS_FONTCONFIG "$QT_CFLAGS_FONTCONFIG" + QMakeVar set QMAKE_LIBS_FONTCONFIG "$QT_LIBS_FONTCONFIG" + CFG_LIBFREETYPE=system + fi + fi + + # MIT_SHM is required for testlite + if [ "$CFG_MITSHM" != "no" ]; then + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/x11/mitshm "mitshm" $L_FLAGS $I_FLAGS $l_FLAGS $X11TESTS_FLAGS; then + QT_CONFIG="$QT_CONFIG mitshm" + fi + fi fi diff --git a/lib/fonts/dejavu_sans_11_50.qpf2 b/lib/fonts/dejavu_sans_11_50.qpf2 Binary files differnew file mode 100644 index 0000000..c88d099 --- /dev/null +++ b/lib/fonts/dejavu_sans_11_50.qpf2 diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp index b4987f2..e2a493d 100644 --- a/src/gui/kernel/qplatformintegration_qpa.cpp +++ b/src/gui/kernel/qplatformintegration_qpa.cpp @@ -41,6 +41,8 @@ #include "qplatformintegration_qpa.h" +#include <QtGui/QPlatformFontDatabase> + QT_BEGIN_NAMESPACE QPixmap QPlatformIntegration::grabWindow(WId window, int x, int y, int width, int height) const @@ -63,4 +65,13 @@ bool QPlatformIntegration::hasOpenGL() const return false; } +QPlatformFontDatabase *QPlatformIntegration::fontDatabase() const +{ + static QPlatformFontDatabase *db = 0; + if (!db) { + db = new QPlatformFontDatabase; + } + return db; +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h index 9460910..b1f4e5f 100644 --- a/src/gui/kernel/qplatformintegration_qpa.h +++ b/src/gui/kernel/qplatformintegration_qpa.h @@ -58,6 +58,7 @@ class QWindowSurface; class QBlittable; class QWidget; class QPlatformEventLoopIntegration; +class QPlatformFontDatabase; class Q_GUI_EXPORT QPlatformIntegration { @@ -75,6 +76,9 @@ public: virtual bool isVirtualDesktop() { return false; } virtual QPixmap grabWindow(WId window, int x, int y, int width, int height) const; +//Fontdatabase integration. + virtual QPlatformFontDatabase *fontDatabase() const; + // Experimental in mainthread eventloop integration // This should only be used if it is only possible to do window system event processing in // the gui thread. All of the functions in QWindowSystemInterface are thread safe. diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h index ddb6195..ee9b457 100644 --- a/src/gui/painting/qpaintengine.h +++ b/src/gui/painting/qpaintengine.h @@ -272,7 +272,7 @@ private: friend class QProxyFontEngine; #endif #ifdef Q_WS_QPA - friend class QProxyFontEngine; + friend class QFontEngineQPA; #endif friend class QPainter; friend class QPainterPrivate; diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index df32ea8..7dee7e4 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3396,9 +3396,36 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte } #endif // Q_WS_QWS -#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_QPA)) && !defined(QT_NO_FREETYPE) +#ifdef Q_WS_QPA + if (s->matrix.type() < QTransform::TxScale) { -#if (defined(Q_WS_QWS) || defined(Q_WS_QPA)) && !defined(QT_NO_QWS_QPF2) + QVarLengthArray<QFixedPoint> positions; + QVarLengthArray<glyph_t> glyphs; + QTransform matrix = state()->transform(); + + qreal _x = qFloor(p.x() + aliasedCoordinateDelta); + qreal _y = qFloor(p.y() + aliasedCoordinateDelta); + matrix.translate(_x, _y); + + fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + if (glyphs.size() == 0) + return; + + for(int i = 0; i < glyphs.size(); i++) { + QImage img = fontEngine->alphaMapForGlyph(glyphs[i]); + glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]); + alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(), + qRound(positions[i].x + metrics.x), + qRound(positions[i].y + metrics.y), + img.width(), img.height()); + } + return; + } +#endif //Q_WS_QPA + +#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE) + +#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2) if (fontEngine->type() == QFontEngine::QPF2) { QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine(); if (renderingEngine) diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 6e02435..fdb84e0 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -916,7 +916,7 @@ const char *QPdf::paperSizeToString(QPrinter::PaperSize paperSize) } -QByteArray QPdf::stripSpecialCharacters(const QByteArray &string) +Q_GUI_EXPORT QByteArray QPdf::stripSpecialCharacters(const QByteArray &string) { QByteArray s = string; s.replace(' ', ""); diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index fd1a2dd..2cc41e1 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -46,7 +46,7 @@ #include <QtCore/qstring.h> #include <QtCore/qsharedpointer.h> -#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_QPA) +#if defined(Q_WS_X11) || defined(Q_WS_QWS) typedef struct FT_FaceRec_* FT_Face; #endif @@ -236,7 +236,7 @@ public: #ifdef Q_WS_MAC quint32 macFontID() const; #endif -#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_QPA) +#if defined(Q_WS_X11) || defined(Q_WS_QWS) FT_Face freetypeFace() const; #endif diff --git a/src/gui/text/qfont_qpa.cpp b/src/gui/text/qfont_qpa.cpp new file mode 100644 index 0000000..5fed18b --- /dev/null +++ b/src/gui/text/qfont_qpa.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/private/qapplication_p.h> +#include <QtGui/QPlatformFontDatabase> + +QT_BEGIN_NAMESPACE + +void QFont::initialize() +{ + QApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase(); +} + +void QFont::cleanup() +{ + QFontCache::cleanup(); +} + + +/***************************************************************************** + QFont member functions + *****************************************************************************/ + +Qt::HANDLE QFont::handle() const +{ + return 0; +} + +QString QFont::rawName() const +{ + return QLatin1String("unknown"); +} + +void QFont::setRawName(const QString &) +{ +} + +QString QFont::defaultFamily() const +{ + QString familyName; + switch(d->request.styleHint) { + case QFont::Times: + familyName = QString::fromLatin1("times"); + case QFont::Courier: + case QFont::Monospace: + familyName = QString::fromLatin1("monospace"); + case QFont::Decorative: + familyName = QString::fromLatin1("old english"); + case QFont::Helvetica: + case QFont::System: + default: + familyName = QString::fromLatin1("helvetica"); + } + + QStringList list = QApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(familyName,QFont::StyleNormal,QUnicodeTables::Common); + if (list.size()) { + familyName = list.at(0); + } + return familyName; +} + +QString QFont::lastResortFamily() const +{ + return QString::fromLatin1("helvetica"); +} + +QString QFont::lastResortFont() const +{ + qFatal("QFont::lastResortFont: Cannot find any reasonable font"); + // Shut compiler up + return QString(); +} + + +QT_END_NAMESPACE + diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 7ece6ea..72ffb1c 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -50,13 +50,19 @@ #include "private/qunicodetables_p.h" #include "qfontengine_p.h" +#ifdef Q_WS_QPA +#include <QtGui/private/qapplication_p.h> +#include <QtGui/qplatformfontdatabase_qpa.h> +#include "qabstractfileengine.h" +#endif + #ifdef Q_WS_X11 #include <locale.h> #endif #include <stdlib.h> #include <limits.h> -#if (defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE) +#if (defined(Q_WS_QWS)|| defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE) # include <ft2build.h> # include FT_TRUETYPE_TABLES_H #endif @@ -143,7 +149,7 @@ struct QtFontEncoding uchar pitch : 8; }; -struct QtFontSize +struct QtFontSize { #ifdef Q_WS_X11 QtFontEncoding *encodings; @@ -152,10 +158,13 @@ struct QtFontSize unsigned short count : 16; #endif // Q_WS_X11 -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) QByteArray fileName; int fileIndex; #endif // defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_QPA) + void *handle; +#endif unsigned short pixelSize : 16; }; @@ -238,9 +247,15 @@ struct QtFontStyle #ifdef Q_WS_X11 free(pixelSizes[count].encodings); #endif -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) pixelSizes[count].fileName.~QByteArray(); #endif +#if defined (Q_WS_QPA) + QPlatformIntegration *integration = QApplicationPrivate::platformIntegration(); + if (integration) { //on shut down there will be some that we don't release. + integration->fontDatabase()->releaseHandle(pixelSizes[count].handle); + } +#endif } #endif free(pixelSizes); @@ -302,10 +317,13 @@ QtFontSize *QtFontStyle::pixelSize(unsigned short size, bool add) pixelSizes[count].count = 0; pixelSizes[count].encodings = 0; #endif -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) new (&pixelSizes[count].fileName) QByteArray; pixelSizes[count].fileIndex = 0; #endif +#if defined(Q_WS_QPA) + pixelSizes[count].handle = 0; +#endif return pixelSizes + (count++); } @@ -362,7 +380,7 @@ QtFontStyle *QtFontFoundry::style(const QtFontStyle::Key &key, bool create) } -struct QtFontFamily +struct QtFontFamily { enum WritingSystemStatus { Unknown = 0, @@ -391,6 +409,9 @@ struct QtFontFamily #if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE) , bogusWritingSystems(false) #endif +#if defined(Q_WS_QPA) + , askedForFallback(false) +#endif { memset(writingSystems, 0, sizeof(writingSystems)); } @@ -432,6 +453,9 @@ struct QtFontFamily bool bogusWritingSystems; QStringList fallbackFamilies; #endif +#if defined (Q_WS_QPA) + bool askedForFallback; +#endif unsigned char writingSystems[QFontDatabase::WritingSystemsCount]; QtFontFoundry *foundry(const QString &f, bool = false); @@ -475,7 +499,7 @@ QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create) // ### copied to tools/makeqpf/qpf2.cpp -#if ((defined(Q_WS_QWS) || defined(Q_WS_QPA)) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || (defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)) +#if (defined(Q_WS_QWS) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || (defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)) // see the Unicode subset bitfields in the MSDN docs static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { @@ -617,7 +641,7 @@ class QFontDatabasePrivate public: QFontDatabasePrivate() : count(0), families(0), reregisterAppFonts(false) -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) +#if defined(Q_WS_QWS) , stream(0) #endif #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) @@ -665,11 +689,11 @@ public: void invalidate(); -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) +#if defined(Q_WS_QWS) bool loadFromCache(const QString &fontPath); void addQPF2File(const QByteArray &file); #endif // Q_WS_QWS -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE) +#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE) void addFont(const QString &familyname, const char *foundryname, int weight, bool italic, int pixelSize, const QByteArray &file, int fileIndex, bool antialiased, @@ -678,12 +702,14 @@ public: QStringList addTTFile(const QByteArray &file, const QByteArray &fontData = QByteArray()); #endif // QT_NO_FREETYPE #endif -#if defined(Q_WS_QWS) || defined (Q_WS_QPA) +#if defined(Q_WS_QWS) QDataStream *stream; - QStringList fallbackFamilies; #elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) const QSymbianFontDatabaseExtras *symbianExtras; #endif +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) + QStringList fallbackFamilies; +#endif }; void QFontDatabasePrivate::invalidate() @@ -732,7 +758,7 @@ QtFontFamily *QFontDatabasePrivate::family(const QString &f, bool create) return families[pos]; } -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE) +#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE) void QFontDatabasePrivate::addFont(const QString &familyname, const char *foundryname, int weight, bool italic, int pixelSize, const QByteArray &file, int fileIndex, bool antialiased, const QList<QFontDatabase::WritingSystem> &writingSystems) @@ -763,7 +789,7 @@ void QFontDatabasePrivate::addFont(const QString &familyname, const char *foundr size->fileName = file; size->fileIndex = fileIndex; -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) +#if defined(Q_WS_QWS) if (stream) { *stream << familyname << foundry->name << weight << quint8(italic) << pixelSize << file << fileIndex << quint8(antialiased); @@ -778,7 +804,7 @@ void QFontDatabasePrivate::addFont(const QString &familyname, const char *foundr } #endif -#if (defined(Q_WS_QWS) || defined (Q_WS_QPA) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE) +#if (defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE) QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteArray &fontData) { QStringList families; @@ -891,7 +917,7 @@ static const int scriptForWritingSystem[] = { }; -#if defined Q_WS_QWS || defined(Q_WS_QPA) || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)) || defined(Q_WS_WIN) +#if defined Q_WS_QWS || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)) || defined(Q_WS_WIN) static inline bool requiresOpenType(int writingSystem) { return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala) @@ -994,7 +1020,7 @@ static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDe #endif #endif -#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || defined(Q_WS_QPA) static void getEngineData(const QFontPrivate *d, const QFontCache::Key &key) { // look for the requested font in the engine data cache @@ -1053,8 +1079,10 @@ QT_BEGIN_INCLUDE_NAMESPACE # include "qfontdatabase_mac.cpp" #elif defined(Q_WS_WIN) # include "qfontdatabase_win.cpp" -#elif defined(Q_WS_QWS) || defined(Q_WS_QPA) +#elif defined(Q_WS_QWS) # include "qfontdatabase_qws.cpp" +#elif defined(Q_WS_QPA) +# include "qfontdatabase_qpa.cpp" #elif defined(Q_OS_SYMBIAN) # include "qfontdatabase_s60.cpp" #endif @@ -1340,6 +1368,7 @@ static void match(int script, const QFontDef &request, styleKey.stretch = request.stretch; char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p'; + FM_DEBUG("QFontDatabase::match\n" " request:\n" " family: %s [%s], script: %d\n" @@ -2485,7 +2514,7 @@ void QFontDatabase::createDatabase() { initializeDb(); } // used from qfontengine_ft.cpp -QByteArray qt_fontdata_from_index(int index) +Q_GUI_EXPORT QByteArray qt_fontdata_from_index(int index) { QMutexLocker locker(fontDatabaseMutex()); return privateDb()->applicationFonts.value(index).data; diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 6a09b77..f31c19c 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -167,6 +167,7 @@ private: friend class QFontEngineMultiXLFD; friend class QFontEngineMultiQWS; friend class QFontEngineMultiS60; + friend class QFontEngineMultiQPA; QFontDatabasePrivate *d; }; diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp new file mode 100644 index 0000000..53594aa --- /dev/null +++ b/src/gui/text/qfontdatabase_qpa.cpp @@ -0,0 +1,392 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlibraryinfo.h" +#include <QtCore/qsettings.h> + +#include "qfontengine_qpa_p.h" +#include "qplatformdefs.h" + +#include <QtGui/private/qapplication_p.h> +#include <QtGui/qplatformfontdatabase_qpa.h> + +#include <QtCore/qmath.h> + +QT_BEGIN_NAMESPACE + +Q_GUI_EXPORT void qt_registerFont(const QString &familyName, const QString &foundryname, int weight, + QFont::Style style, int stretch, bool antialiased, bool scalable, int pixelSize, + const QSupportedWritingSystems &writingSystems, void *handle) +{ + QFontDatabasePrivate *d = privateDb(); + // qDebug() << "Adding font" << familyname << weight << italic << pixelSize << file << fileIndex << antialiased; + QtFontStyle::Key styleKey; + styleKey.style = style; + styleKey.weight = weight; + styleKey.stretch = stretch; + QtFontFamily *f = d->family(familyName, true); + + for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) { + if (writingSystems.supported(QFontDatabase::WritingSystem(i))) { + f->writingSystems[i] = QtFontFamily::Supported; + } else { + f->writingSystems[i] = QtFontFamily::Unsupported; + } + } + + QtFontFoundry *foundry = f->foundry(foundryname, true); + QtFontStyle *fontStyle = foundry->style(styleKey, true); + fontStyle->smoothScalable = scalable; + fontStyle->antialiased = antialiased; + QtFontSize *size = fontStyle->pixelSize(pixelSize?pixelSize:SMOOTH_SCALABLE, true); + size->handle = handle; +} + +static QStringList fallbackFamilies(const QString &family, const QFont::Style &style, const QUnicodeTables::Script &script) +{ + QStringList retList = QApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,script); + QFontDatabasePrivate *db = privateDb(); + + QStringList::iterator i; + for (i = retList.begin(); i != retList.end(); ++i) { + bool contains = false; + for (int j = 0; j < db->count; j++) { + QtFontFamily *qtFamily = db->families[j]; + if (!(i->compare(qtFamily->name,Qt::CaseInsensitive))) { + contains = true; + break; + } + } + if (!contains) { + i = retList.erase(i); + i--; + } + } + return retList; +} + +static void initializeDb() +{ + static int initialized = false; + + if (!initialized) { + //init by asking for the platformfontdb for the first time :) + QApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase(); + initialized = true; + } +} + +#ifndef QT_NO_SETTINGS +// called from qapplication_qws.cpp +void qt_applyFontDatabaseSettings(const QSettings &settings) +{ + initializeDb(); + QFontDatabasePrivate *db = privateDb(); + for (int i = 0; i < db->count; ++i) { + QtFontFamily *family = db->families[i]; + if (settings.contains(family->name)) + family->fallbackFamilies = settings.value(family->name).toStringList(); + } + + if (settings.contains(QLatin1String("Global Fallbacks"))) + db->fallbackFamilies = settings.value(QLatin1String("Global Fallbacks")).toStringList(); +} +#endif // QT_NO_SETTINGS + +static inline void load(const QString & = QString(), int = -1) +{ + initializeDb(); +} + +static +QFontEngine *loadSingleEngine(int script, + const QFontDef &request, + QtFontFoundry *foundry, + QtFontStyle *style, QtFontSize *size) +{ + Q_UNUSED(foundry); + + Q_ASSERT(size); + int pixelSize = size->pixelSize; + if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE)) + pixelSize = request.pixelSize; + + QFontDef def = request; + def.pixelSize = pixelSize; + + QFontCache::Key key(def,script); + QFontEngine *engine = QFontCache::instance()->findEngine(key); + if (!engine) { + QPlatformFontDatabase *pfdb = QApplicationPrivate::platformIntegration()->fontDatabase(); + if (size->handle) { + engine = pfdb->fontEngine(def,QUnicodeTables::Script(script),size->handle); + if (engine) { + QFontCache::Key key(def,script); + QFontCache::instance()->instance()->insertEngine(key,engine); + } + } + + } + return engine; +} + +static +QFontEngine *loadEngine(int script, const QFontDef &request, + QtFontFamily *family, QtFontFoundry *foundry, + QtFontStyle *style, QtFontSize *size) +{ + + QFontEngine *engine = loadSingleEngine(script, request, foundry, style, size); + //make sure that the db has all fallback families + if (engine + && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol ) { + + if (family && !family->askedForFallback) { + family->fallbackFamilies = fallbackFamilies(family->name,QFont::Style(style->key.style),QUnicodeTables::Script(script)); + + family->askedForFallback = true; + } + + QStringList fallbacks = privateDb()->fallbackFamilies; + if (family && !family->fallbackFamilies.isEmpty()) + fallbacks = family->fallbackFamilies; + + engine = new QFontEngineMultiQPA(engine, script, fallbacks); + } + + return engine; +} + +static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) +{ + QFontDatabasePrivate *db = privateDb(); + + QApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data,fnt->fileName); + db->reregisterAppFonts = true; +} + +bool QFontDatabase::removeApplicationFont(int handle) +{ + QMutexLocker locker(fontDatabaseMutex()); + + QFontDatabasePrivate *db = privateDb(); + if (handle < 0 || handle >= db->applicationFonts.count()) + return false; + + db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont(); + + db->reregisterAppFonts = true; + db->invalidate(); + return true; +} + +bool QFontDatabase::removeAllApplicationFonts() +{ + QMutexLocker locker(fontDatabaseMutex()); + + QFontDatabasePrivate *db = privateDb(); + if (db->applicationFonts.isEmpty()) + return false; + + db->applicationFonts.clear(); + db->invalidate(); + return true; +} + +bool QFontDatabase::supportsThreadedFontRendering() +{ + return true; +} + +/*! + \internal +*/ +QFontEngine * +QFontDatabase::findFont(int script, const QFontPrivate *fp, + const QFontDef &request) +{ + QMutexLocker locker(fontDatabaseMutex()); + + const int force_encoding_id = -1; + + if (!privateDb()->count) + initializeDb(); + + QFontEngine *engine; + QFontCache::Key key(request, script); + engine = QFontCache::instance()->findEngine(key); + if (engine) { + qDebug() << "Cache hit level 1"; + return engine; + } + + QString family_name, foundry_name; + + parseFontName(request.family, foundry_name, family_name); + + if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) { + engine =new QTestFontEngine(request.pixelSize); + engine->fontDef = request; + } + + QtFontDesc desc; + match(script, request, family_name, foundry_name, force_encoding_id, &desc); + if (desc.family != 0 && desc.foundry != 0 && desc.style != 0) { + engine = loadEngine(script, request, desc.family, desc.foundry, desc.style, desc.size); + } else { + FM_DEBUG(" NO MATCH FOUND\n"); + } + + if (engine) { + initFontDef(desc, request, &engine->fontDef); + + if (fp) { + QFontDef def = request; + if (def.family.isEmpty()) { + def.family = fp->request.family; + def.family = def.family.left(def.family.indexOf(QLatin1Char(','))); + } + } + } + + if (!engine) { + if (!request.family.isEmpty()) { + QStringList fallbacks = fallbackFamilies(request.family,QFont::Style(request.style),QUnicodeTables::Script(script)); + for (int i = 0; i < fallbacks.size(); i++) { + QFontDef def = request; + def.family = fallbacks.at(i); + QFontCache::Key key(def,script); + engine = QFontCache::instance()->findEngine(key); + if (!engine) { + QtFontDesc desc; + match(script, def, def.family, QLatin1String(""), 0, &desc); + if (desc.family == 0 && desc.foundry == 0 && desc.style == 0) { + continue; + } + engine = loadEngine(script, def, desc.family, desc.foundry, desc.style, desc.size); + if (engine) { + initFontDef(desc, def, &engine->fontDef); + break; + } + } + } + } + + if (!engine) + engine = new QFontEngineBox(request.pixelSize); + + FM_DEBUG("returning box engine"); + } + + if (fp && fp->dpi > 0) { + engine->fontDef.pointSize = qreal(double((engine->fontDef.pixelSize * 72) / fp->dpi)); + } else { + engine->fontDef.pointSize = request.pointSize; + } + + return engine; +} + +void QFontDatabase::load(const QFontPrivate *d, int script) +{ + QFontDef req = d->request; + + if (req.pixelSize == -1) { + req.pixelSize = floor(((req.pointSize * d->dpi) / 72) * 100 + 0.5) / 100; + req.pixelSize = qRound(req.pixelSize); + } + if (req.pointSize < 0) + req.pointSize = req.pixelSize*72.0/d->dpi; + if (req.weight == 0) + req.weight = QFont::Normal; + if (req.stretch == 0) + req.stretch = 100; + + QFontCache::Key key(req, script); + + if (!d->engineData) + getEngineData(d, key); + + // the cached engineData could have already loaded the engine we want + if (d->engineData->engines[script]) + return; + + QFontEngine *fe = QFontCache::instance()->findEngine(key); + + // list of families to try + QStringList family_list; + + if (!req.family.isEmpty()) { + family_list = familyList(req); + + // add the default family + QString defaultFamily = QApplication::font().family(); + if (! family_list.contains(defaultFamily)) + family_list << defaultFamily; + + } + + // null family means find the first font matching the specified script + family_list << QString(); + + QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd(); + for (; !fe && it != end; ++it) { + req.family = *it; + + fe = QFontDatabase::findFont(script, d, req); + if (fe && (fe->type()==QFontEngine::Box) && !req.family.isEmpty()) + fe = 0; + } + + if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) { + for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) { + if (!d->engineData->engines[i]) { + d->engineData->engines[i] = fe; + fe->ref.ref(); + } + } + } else { + d->engineData->engines[script] = fe; + fe->ref.ref(); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index fdb86ce..1c705ae 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -481,7 +481,7 @@ static void collectSingleContour(qreal x0, qreal y0, uint *grid, int x, int y, i path->closeSubpath(); } -void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path) +Q_GUI_EXPORT void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path) { uint *grid = new uint[(w+1)*(h+1)]; // set up edges diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 2c4fbab..1ee7144 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -717,7 +717,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format) metrics = face->size->metrics; -#if defined(Q_WS_QWS) +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) /* TrueType fonts with embedded bitmaps may have a bitmap font specific ascent/descent in the EBLC table. There is no direct public API @@ -749,6 +749,11 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format) return true; } +void QFontEngineFT::setDefaultHintStyle(HintStyle style) +{ + default_hint_style = style; +} + QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph) const { Glyph *g = set->getGlyph(glyph); diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index 372ad0c..f40ce04 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -271,7 +271,7 @@ private: QGlyphSet *loadTransformedGlyphSet(const QTransform &matrix); bool loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, GlyphFormat format = Format_Render); -#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) virtual void draw(QPaintEngine * /*p*/, qreal /*x*/, qreal /*y*/, const QTextItemInt & /*si*/) {} #endif @@ -282,6 +282,14 @@ private: virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints); + enum HintStyle { + HintNone, + HintLight, + HintMedium, + HintFull + }; + + void setDefaultHintStyle(HintStyle style); protected: void freeGlyphSets(); @@ -293,12 +301,6 @@ protected: QFreetypeFace *freetype; int default_load_flags; - enum HintStyle { - HintNone, - HintLight, - HintMedium, - HintFull - }; HintStyle default_hint_style; diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index fb4556b..897f76f 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -168,7 +168,7 @@ public: virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const {} virtual void doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const; -#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_OS_SYMBIAN) +#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_OS_SYMBIAN) && !defined(Q_WS_QPA) virtual void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si) = 0; #endif virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, diff --git a/src/gui/text/qfontengine_qpa.cpp b/src/gui/text/qfontengine_qpa.cpp new file mode 100644 index 0000000..910bbfe --- /dev/null +++ b/src/gui/text/qfontengine_qpa.cpp @@ -0,0 +1,650 @@ +#include "qfontengine_qpa_p.h" + +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtCore/QBuffer> + +#include <QtGui/private/qapplication_p.h> +#include <QtGui/QPlatformFontDatabase> +#include <QtGui/private/qpaintengine_raster_p.h> + +QT_BEGIN_NAMESPACE + +//#define DEBUG_HEADER +//#define DEBUG_FONTENGINE + +static QFontEngineQPA::TagType tagTypes[QFontEngineQPA::NumTags] = { + QFontEngineQPA::StringType, // FontName + QFontEngineQPA::StringType, // FileName + QFontEngineQPA::UInt32Type, // FileIndex + QFontEngineQPA::UInt32Type, // FontRevision + QFontEngineQPA::StringType, // FreeText + QFontEngineQPA::FixedType, // Ascent + QFontEngineQPA::FixedType, // Descent + QFontEngineQPA::FixedType, // Leading + QFontEngineQPA::FixedType, // XHeight + QFontEngineQPA::FixedType, // AverageCharWidth + QFontEngineQPA::FixedType, // MaxCharWidth + QFontEngineQPA::FixedType, // LineThickness + QFontEngineQPA::FixedType, // MinLeftBearing + QFontEngineQPA::FixedType, // MinRightBearing + QFontEngineQPA::FixedType, // UnderlinePosition + QFontEngineQPA::UInt8Type, // GlyphFormat + QFontEngineQPA::UInt8Type, // PixelSize + QFontEngineQPA::UInt8Type, // Weight + QFontEngineQPA::UInt8Type, // Style + QFontEngineQPA::StringType, // EndOfHeader + QFontEngineQPA::BitFieldType// WritingSystems +}; + + +#if defined(DEBUG_HEADER) +# define DEBUG_VERIFY qDebug +#else +# define DEBUG_VERIFY if (0) qDebug +#endif + +#define READ_VERIFY(type, variable) \ + if (tagPtr + sizeof(type) > endPtr) { \ + DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \ + return 0; \ + } \ + variable = qFromBigEndian<type>(tagPtr); \ + DEBUG_VERIFY() << "read value" << variable << "of type " #type; \ + tagPtr += sizeof(type) + +template <typename T> +T readValue(const uchar *&data) +{ + T value = qFromBigEndian<T>(data); + data += sizeof(T); + return value; +} + +#define VERIFY(condition) \ + if (!(condition)) { \ + DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \ + return 0; \ + } + +#define VERIFY_TAG(condition) \ + if (!(condition)) { \ + DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \ + return 0; \ + } + +static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr) +{ + quint16 tag, length; + READ_VERIFY(quint16, tag); + READ_VERIFY(quint16, length); + if (tag == QFontEngineQPA::Tag_EndOfHeader) + return endPtr; + if (tag < QFontEngineQPA::NumTags) { + switch (tagTypes[tag]) { + case QFontEngineQPA::BitFieldType: + case QFontEngineQPA::StringType: + // can't do anything... + break; + case QFontEngineQPA::UInt32Type: + VERIFY_TAG(length == sizeof(quint32)); + break; + case QFontEngineQPA::FixedType: + VERIFY_TAG(length == sizeof(quint32)); + break; + case QFontEngineQPA::UInt8Type: + VERIFY_TAG(length == sizeof(quint8)); + break; + } +#if defined(DEBUG_HEADER) + if (length == 1) + qDebug() << "tag data" << hex << *tagPtr; + else if (length == 4) + qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3]; +#endif + } + return tagPtr + length; +} + +const QFontEngineQPA::Glyph *QFontEngineQPA::findGlyph(glyph_t g) const +{ + if (!g || g >= glyphMapEntries) + return 0; + const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset); + quint32 glyphPos = qFromBigEndian<quint32>(gmapPtr[g]); + if (glyphPos > glyphDataSize) { + if (glyphPos == 0xffffffff) + return 0; +#if defined(DEBUG_FONTENGINE) + qDebug() << "glyph" << g << "outside of glyphData, remapping font file"; +#endif + if (glyphPos > glyphDataSize) + return 0; + } + return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos); +} + +bool QFontEngineQPA::verifyHeader(const uchar *data, int size) +{ + VERIFY(size >= int(sizeof(Header))); + const Header *header = reinterpret_cast<const Header *>(data); + if (header->magic[0] != 'Q' + || header->magic[1] != 'P' + || header->magic[2] != 'F' + || header->magic[3] != '2') + return false; + + VERIFY(header->majorVersion <= CurrentMajorVersion); + const quint16 dataSize = qFromBigEndian<quint16>(header->dataSize); + VERIFY(size >= int(sizeof(Header)) + dataSize); + + const uchar *tagPtr = data + sizeof(Header); + const uchar *tagEndPtr = tagPtr + dataSize; + while (tagPtr < tagEndPtr - 3) { + tagPtr = verifyTag(tagPtr, tagEndPtr); + VERIFY(tagPtr); + } + + VERIFY(tagPtr <= tagEndPtr); + return true; +} + +QVariant QFontEngineQPA::extractHeaderField(const uchar *data, HeaderTag requestedTag) +{ + const Header *header = reinterpret_cast<const Header *>(data); + const uchar *tagPtr = data + sizeof(Header); + const uchar *endPtr = tagPtr + qFromBigEndian<quint16>(header->dataSize); + while (tagPtr < endPtr - 3) { + quint16 tag = readValue<quint16>(tagPtr); + quint16 length = readValue<quint16>(tagPtr); + if (tag == requestedTag) { + switch (tagTypes[requestedTag]) { + case StringType: + return QVariant(QString::fromUtf8(reinterpret_cast<const char *>(tagPtr), length)); + case UInt32Type: + return QVariant(readValue<quint32>(tagPtr)); + case UInt8Type: + return QVariant(uint(*tagPtr)); + case FixedType: + return QVariant(QFixed::fromFixed(readValue<quint32>(tagPtr)).toReal()); + case BitFieldType: + return QVariant(QByteArray(reinterpret_cast<const char *>(tagPtr), length)); + } + return QVariant(); + } else if (tag == Tag_EndOfHeader) { + break; + } + tagPtr += length; + } + + return QVariant(); +} + + + +static inline unsigned int getChar(const QChar *str, int &i, const int len) +{ + unsigned int uc = str[i].unicode(); + if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) { + uint low = str[i+1].unicode(); + if (low >= 0xdc00 && low < 0xe000) { + uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000; + ++i; + } + } + return uc; +} + +QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data) + : fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size()) +{ + fontDef = def; + cache_cost = 100; + externalCMap = 0; + cmapOffset = 0; + cmapSize = 0; + glyphMapOffset = 0; + glyphMapEntries = 0; + glyphDataOffset = 0; + glyphDataSize = 0; + kerning_pairs_loaded = false; + readOnly = true; + +#if defined(DEBUG_FONTENGINE) + qDebug() << "QFontEngineQPA::QFontEngineQPA( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')'; +#endif + + if (!verifyHeader(fontData, dataSize)) { +#if defined(DEBUG_FONTENGINE) + qDebug() << "verifyHeader failed!"; +#endif + return; + } + + const Header *header = reinterpret_cast<const Header *>(fontData); + + readOnly = (header->lock == 0xffffffff); + + const uchar *imgData = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize); + const uchar *endPtr = fontData + dataSize; + while (imgData <= endPtr - 8) { + quint16 blockTag = readValue<quint16>(imgData); + imgData += 2; // skip padding + quint32 blockSize = readValue<quint32>(imgData); + + if (blockTag == CMapBlock) { + cmapOffset = imgData - fontData; + cmapSize = blockSize; + } else if (blockTag == GMapBlock) { + glyphMapOffset = imgData - fontData; + glyphMapEntries = blockSize / 4; + } else if (blockTag == GlyphBlock) { + glyphDataOffset = imgData - fontData; + glyphDataSize = blockSize; + } + + imgData += blockSize; + } + + face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString()); + face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt(); + + // get the real cmap + if (cmapOffset) { + int tableSize = cmapSize; + const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize); + if (cmapPtr) + cmapOffset = cmapPtr - fontData; + else + cmapOffset = 0; + } else if (externalCMap) { + int tableSize = cmapSize; + externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize); + } + + // verify all the positions in the glyphMap + if (glyphMapOffset) { + const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset); + for (uint i = 0; i < glyphMapEntries; ++i) { + quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]); + if (glyphDataPos == 0xffffffff) + continue; + if (glyphDataPos >= glyphDataSize) { + // error + glyphMapOffset = 0; + glyphMapEntries = 0; + break; + } + } + } + +#if defined(DEBUG_FONTENGINE) + if (!isValid()) + qDebug() << "fontData" << fontData << "dataSize" << dataSize + << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset + << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset + << "fd" << fd << "glyphDataSize" << glyphDataSize; +#endif +} + +QFontEngineQPA::~QFontEngineQPA() +{ +} + +bool QFontEngineQPA::getSfntTableData(uint tag, uchar *buffer, uint *length) const +{ + Q_UNUSED(tag); + Q_UNUSED(buffer); + *length = 0; + return false; +} + +bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const +{ + if (*nglyphs < len) { + *nglyphs = len; + return false; + } + +#if defined(DEBUG_FONTENGINE) + QSet<QChar> seenGlyphs; +#endif + + const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset); + + bool mirrored = flags & QTextEngine::RightToLeft; + int glyph_pos = 0; + if (symbol) { + for (int i = 0; i < len; ++i) { + unsigned int uc = getChar(str, i, len); + if (mirrored) + uc = QChar::mirroredChar(uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + if(!glyphs->glyphs[glyph_pos] && uc < 0x100) + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); + ++glyph_pos; + } + } else { + for (int i = 0; i < len; ++i) { + unsigned int uc = getChar(str, i, len); + if (mirrored) + uc = QChar::mirroredChar(uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); +#if 0 && defined(DEBUG_FONTENGINE) + QChar c(uc); + if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c)) + qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph; + + seenGlyphs.insert(c); +#endif + ++glyph_pos; + } + } + + *nglyphs = glyph_pos; + glyphs->numGlyphs = glyph_pos; + recalcAdvances(glyphs, flags); + return true; +} + +void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const +{ + for (int i = 0; i < glyphs->numGlyphs; ++i) { + const Glyph *g = findGlyph(glyphs->glyphs[i]); + if (!g) { + glyphs->glyphs[i] = 0; + continue; + } + glyphs->advances_x[i] = g->advance; + glyphs->advances_y[i] = 0; + } +} + +QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g) +{ + const Glyph *glyph = findGlyph(g); + if (!glyph) + return QImage(); + + const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph); + + QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8); + + return image; +} + +void QFontEngineQPA::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) +{ + addBitmapFontToPath(x, y, glyphs, path, flags); +} + +glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs) +{ + glyph_metrics_t overall; + // initialize with line height, we get the same behaviour on all platforms + overall.y = -ascent(); + overall.height = ascent() + descent() + 1; + + QFixed ymax = 0; + QFixed xmax = 0; + for (int i = 0; i < glyphs.numGlyphs; i++) { + const Glyph *g = findGlyph(glyphs.glyphs[i]); + if (!g) + continue; + + QFixed x = overall.xoff + glyphs.offsets[i].x + g->x; + QFixed y = overall.yoff + glyphs.offsets[i].y + g->y; + overall.x = qMin(overall.x, x); + overall.y = qMin(overall.y, y); + xmax = qMax(xmax, x + g->width); + ymax = qMax(ymax, y + g->height); + overall.xoff += g->advance; + } + overall.height = qMax(overall.height, ymax - overall.y); + overall.width = xmax - overall.x; + + return overall; +} + +glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph) +{ + glyph_metrics_t overall; + const Glyph *g = findGlyph(glyph); + if (!g) + return overall; + overall.x = g->x; + overall.y = g->y; + overall.width = g->width; + overall.height = g->height; + overall.xoff = g->advance; + return overall; +} + +QFixed QFontEngineQPA::ascent() const +{ + return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>()); +} + +QFixed QFontEngineQPA::descent() const +{ + return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>()); +} + +QFixed QFontEngineQPA::leading() const +{ + return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>()); +} + +qreal QFontEngineQPA::maxCharWidth() const +{ + return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>(); +} + +qreal QFontEngineQPA::minLeftBearing() const +{ + return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>(); +} + +qreal QFontEngineQPA::minRightBearing() const +{ + return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>(); +} + +QFixed QFontEngineQPA::underlinePosition() const +{ + return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>()); +} + +QFixed QFontEngineQPA::lineThickness() const +{ + return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>()); +} + +QFontEngine::Type QFontEngineQPA::type() const +{ + return QFontEngine::QPF2; +} + +bool QFontEngineQPA::canRender(const QChar *string, int len) +{ + const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset); + + if (symbol) { + for (int i = 0; i < len; ++i) { + unsigned int uc = getChar(string, i, len); + glyph_t g = getTrueTypeGlyphIndex(cmap, uc); + if(!g && uc < 0x100) + g = getTrueTypeGlyphIndex(cmap, uc + 0xf000); + if (!g) + return false; + } + } else { + for (int i = 0; i < len; ++i) { + unsigned int uc = getChar(string, i, len); + if (!getTrueTypeGlyphIndex(cmap, uc)) + return false; + } + } + return true; +} + +bool QFontEngineQPA::isValid() const +{ + return fontData && dataSize && (cmapOffset || externalCMap) + && glyphMapOffset && glyphDataOffset && glyphDataSize > 0; +} + +void QPAGenerator::generate() +{ + writeHeader(); + writeGMap(); + writeBlock(QFontEngineQPA::GlyphBlock, QByteArray()); + + dev->seek(4); // position of header.lock + writeUInt32(0); +} + +void QPAGenerator::writeHeader() +{ + QFontEngineQPA::Header header; + + header.magic[0] = 'Q'; + header.magic[1] = 'P'; + header.magic[2] = 'F'; + header.magic[3] = '2'; + header.lock = 1; + header.majorVersion = QFontEngineQPA::CurrentMajorVersion; + header.minorVersion = QFontEngineQPA::CurrentMinorVersion; + header.dataSize = 0; + dev->write((const char *)&header, sizeof(header)); + + writeTaggedString(QFontEngineQPA::Tag_FontName, fe->fontDef.family.toUtf8()); + + QFontEngine::FaceId face = fe->faceId(); + writeTaggedString(QFontEngineQPA::Tag_FileName, face.filename); + writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index); + + { + uchar data[4]; + uint len = 4; + bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len); + if (ok) { + const quint32 revision = qFromBigEndian<quint32>(data); + writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision); + } + } + + writeTaggedQFixed(QFontEngineQPA::Tag_Ascent, fe->ascent()); + writeTaggedQFixed(QFontEngineQPA::Tag_Descent, fe->descent()); + writeTaggedQFixed(QFontEngineQPA::Tag_Leading, fe->leading()); + writeTaggedQFixed(QFontEngineQPA::Tag_XHeight, fe->xHeight()); + writeTaggedQFixed(QFontEngineQPA::Tag_AverageCharWidth, fe->averageCharWidth()); + writeTaggedQFixed(QFontEngineQPA::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth())); + writeTaggedQFixed(QFontEngineQPA::Tag_LineThickness, fe->lineThickness()); + writeTaggedQFixed(QFontEngineQPA::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing())); + writeTaggedQFixed(QFontEngineQPA::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing())); + writeTaggedQFixed(QFontEngineQPA::Tag_UnderlinePosition, fe->underlinePosition()); + writeTaggedUInt8(QFontEngineQPA::Tag_PixelSize, fe->fontDef.pixelSize); + writeTaggedUInt8(QFontEngineQPA::Tag_Weight, fe->fontDef.weight); + writeTaggedUInt8(QFontEngineQPA::Tag_Style, fe->fontDef.style); + + writeTaggedUInt8(QFontEngineQPA::Tag_GlyphFormat, QFontEngineQPA::AlphamapGlyphs); + + writeTaggedString(QFontEngineQPA::Tag_EndOfHeader, QByteArray()); + align4(); + + const quint64 size = dev->pos(); + header.dataSize = qToBigEndian<quint16>(size - sizeof(header)); + dev->seek(0); + dev->write((const char *)&header, sizeof(header)); + dev->seek(size); +} + +void QPAGenerator::writeGMap() +{ + const quint16 glyphCount = fe->glyphCount(); + + writeUInt16(QFontEngineQPA::GMapBlock); + writeUInt16(0); // padding + writeUInt32(glyphCount * 4); + + QByteArray &buffer = dev->buffer(); + const int numBytes = glyphCount * sizeof(quint32); + qint64 pos = buffer.size(); + buffer.resize(pos + numBytes); + qMemSet(buffer.data() + pos, 0xff, numBytes); + dev->seek(pos + numBytes); +} + +void QPAGenerator::writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data) +{ + writeUInt16(tag); + writeUInt16(0); // padding + const int padSize = ((data.size() + 3) / 4) * 4 - data.size(); + writeUInt32(data.size() + padSize); + dev->write(data); + for (int i = 0; i < padSize; ++i) + writeUInt8(0); +} + +void QPAGenerator::writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string) +{ + writeUInt16(tag); + writeUInt16(string.length()); + dev->write(string); +} + +void QPAGenerator::writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value) +{ + writeUInt16(tag); + writeUInt16(sizeof(value)); + writeUInt32(value); +} + +void QPAGenerator::writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value) +{ + writeUInt16(tag); + writeUInt16(sizeof(value)); + writeUInt8(value); +} + +void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value) +{ + writeUInt16(tag); + writeUInt16(sizeof(quint32)); + writeUInt32(value.value()); +} + + +/* + Creates a new multi QPA engine. + + This function takes ownership of the QFontEngine, increasing it's refcount. +*/ +QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks) + : QFontEngineMulti(fallbacks.size() + 1), + fallbackFamilies(fallbacks), script(_script) +{ + engines[0] = fe; + fe->ref.ref(); + fontDef = engines[0]->fontDef; +} + +void QFontEngineMultiQPA::loadEngine(int at) +{ + Q_ASSERT(at < engines.size()); + Q_ASSERT(engines.at(at) == 0); + + QFontDef request = fontDef; + request.styleStrategy |= QFont::NoFontMerging; + request.family = fallbackFamilies.at(at-1); + engines[at] = QFontDatabase::findFont(script, + /*fontprivate*/0, + request); + Q_ASSERT(engines[at]); + engines[at]->ref.ref(); + engines[at]->fontDef = request; +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine_qpa_p.h b/src/gui/text/qfontengine_qpa_p.h new file mode 100644 index 0000000..467fca6 --- /dev/null +++ b/src/gui/text/qfontengine_qpa_p.h @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFONTENGINE_QPA_P_H +#define QFONTENGINE_QPA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +#include <QtCore/qconfig.h> +#include <QtCore/qglobal.h> +#include <QtCore/qendian.h> +#include <QtCore/QBuffer> + +#include "qfontengine_p.h" + +#include <QtCore/QFile> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QFontEngine; +class QFreetypeFace; +class QBuffer; + +class Q_GUI_EXPORT QFontEngineQPA : public QFontEngine +{ +public: + // if you add new tags please make sure to update the tables in + // qpfutil.cpp and tools/makeqpf/qpf2.cpp + enum HeaderTag { + Tag_FontName, // 0 string + Tag_FileName, // 1 string + Tag_FileIndex, // 2 quint32 + Tag_FontRevision, // 3 quint32 + Tag_FreeText, // 4 string + Tag_Ascent, // 5 QFixed + Tag_Descent, // 6 QFixed + Tag_Leading, // 7 QFixed + Tag_XHeight, // 8 QFixed + Tag_AverageCharWidth, // 9 QFixed + Tag_MaxCharWidth, // 10 QFixed + Tag_LineThickness, // 11 QFixed + Tag_MinLeftBearing, // 12 QFixed + Tag_MinRightBearing, // 13 QFixed + Tag_UnderlinePosition, // 14 QFixed + Tag_GlyphFormat, // 15 quint8 + Tag_PixelSize, // 16 quint8 + Tag_Weight, // 17 quint8 + Tag_Style, // 18 quint8 + Tag_EndOfHeader, // 19 string + Tag_WritingSystems, // 20 bitfield + + NumTags + }; + + enum TagType { + StringType, + FixedType, + UInt8Type, + UInt32Type, + BitFieldType + }; + + struct Tag + { + quint16 tag; + quint16 size; + }; + + enum GlyphFormat { + BitmapGlyphs = 1, + AlphamapGlyphs = 8 + }; + + enum { + CurrentMajorVersion = 2, + CurrentMinorVersion = 0 + }; + + // The CMap is identical to the TrueType CMap table format + // The GMap table is a normal array with the total number of + // covered glyphs in the TrueType font + enum BlockTag { + CMapBlock, + GMapBlock, + GlyphBlock + }; + + struct Q_PACKED Header + { + char magic[4]; // 'QPF2' + quint32 lock; // values: 0 = unlocked, 0xffffffff = read-only, otherwise qws client id of locking process + quint8 majorVersion; + quint8 minorVersion; + quint16 dataSize; + }; + + struct Q_PACKED Block + { + quint16 tag; + quint16 pad; + quint32 dataSize; + }; + + struct Q_PACKED Glyph + { + quint8 width; + quint8 height; + quint8 bytesPerLine; + qint8 x; + qint8 y; + qint8 advance; + }; + + QFontEngineQPA(const QFontDef &def, const QByteArray &data); + ~QFontEngineQPA(); + + FaceId faceId() const { return face_id; } + bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; + + bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; + void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const; + + void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags); + QImage alphaMapForGlyph(glyph_t t); + + glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); + glyph_metrics_t boundingBox(glyph_t glyph); + + QFixed ascent() const; + QFixed descent() const; + QFixed leading() const; + qreal maxCharWidth() const; + qreal minLeftBearing() const; + qreal minRightBearing() const; + QFixed underlinePosition() const; + QFixed lineThickness() const; + + Type type() const; + + bool canRender(const QChar *string, int len); + inline const char *name() const { return "QPF2"; } + + virtual int glyphCount() const { return glyphMapEntries; } + + bool isValid() const; + + const Glyph *findGlyph(glyph_t g) const; + + static bool verifyHeader(const uchar *data, int size); + static QVariant extractHeaderField(const uchar *data, HeaderTag tag); + +private: + + const uchar *fontData; + int dataSize; + const uchar *externalCMap; + quint32 cmapOffset; + int cmapSize; + quint32 glyphMapOffset; + quint32 glyphMapEntries; + quint32 glyphDataOffset; + quint32 glyphDataSize; + QString internalFileName; + QString encodedFileName; + bool readOnly; + + FaceId face_id; + QByteArray freetypeCMapTable; + mutable bool kerning_pairs_loaded; +}; + +struct QPAGenerator +{ + QPAGenerator(QBuffer *device, QFontEngine *engine) + : dev(device), fe(engine) {} + + void generate(); + void writeHeader(); + void writeGMap(); + void writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data); + + void writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string); + void writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value); + void writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value); + void writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value); + + void writeUInt16(quint16 value) { value = qToBigEndian(value); dev->write((const char *)&value, sizeof(value)); } + void writeUInt32(quint32 value) { value = qToBigEndian(value); dev->write((const char *)&value, sizeof(value)); } + void writeUInt8(quint8 value) { dev->write((const char *)&value, sizeof(value)); } + void writeInt8(qint8 value) { dev->write((const char *)&value, sizeof(value)); } + + void align4() { while (dev->pos() & 3) { dev->putChar('\0'); } } + + QBuffer *dev; + QFontEngine *fe; +}; + +class QFontEngineMultiQPA : public QFontEngineMulti +{ +public: + QFontEngineMultiQPA(QFontEngine *fe, int script, const QStringList &fallbacks); + + void loadEngine(int at); + +private: + QStringList fallbackFamilies; + int script; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QFONTENGINE_QPA_P_H diff --git a/src/gui/text/qplatformfontdatabase_qpa.cpp b/src/gui/text/qplatformfontdatabase_qpa.cpp new file mode 100644 index 0000000..7bb1f9a --- /dev/null +++ b/src/gui/text/qplatformfontdatabase_qpa.cpp @@ -0,0 +1,195 @@ +#include "qplatformfontdatabase_qpa.h" +#include <QtGui/private/qfontengine_p.h> +#include <QtGui/private/qfontengine_qpa_p.h> +#include <QtCore/QLibraryInfo> +#include <QtCore/QDir> + +QT_BEGIN_NAMESPACE + +extern void qt_registerFont(const QString &familyname, const QString &foundryname, int weight, + QFont::Style style, int stretch, bool antialiased,bool scalable, int pixelSize, + const QSupportedWritingSystems &writingSystems, void *hanlde); + +void QPlatformFontDatabase::registerQPF2Font(const QByteArray &dataArray, void *handle) +{ + if (dataArray.size() == 0) + return; + + const uchar *data = reinterpret_cast<const uchar *>(dataArray.constData()); + if (QFontEngineQPA::verifyHeader(data, dataArray.size())) { + QString fontName = QFontEngineQPA::extractHeaderField(data, QFontEngineQPA::Tag_FontName).toString(); + int pixelSize = QFontEngineQPA::extractHeaderField(data, QFontEngineQPA::Tag_PixelSize).toInt(); + QVariant weight = QFontEngineQPA::extractHeaderField(data, QFontEngineQPA::Tag_Weight); + QVariant style = QFontEngineQPA::extractHeaderField(data, QFontEngineQPA::Tag_Style); + QByteArray writingSystemBits = QFontEngineQPA::extractHeaderField(data, QFontEngineQPA::Tag_WritingSystems).toByteArray(); + + if (!fontName.isEmpty() && pixelSize) { + int fontWeight = 50; + if (weight.type() == QVariant::Int || weight.type() == QVariant::UInt) + fontWeight = weight.toInt(); + + QFont::Style fontStyle = static_cast<QFont::Style>(style.toInt()); + + QSupportedWritingSystems writingSystems; + for (int i = 0; i < writingSystemBits.count(); ++i) { + uchar currentByte = writingSystemBits.at(i); + for (int j = 0; j < 8; ++j) { + if (currentByte & 1) + writingSystems.setSupported(QFontDatabase::WritingSystem(i * 8 + j)); + currentByte >>= 1; + } + } + + registerFont(fontName,QString(),fontWeight,fontStyle,100,true,false,pixelSize,writingSystems,handle); + } + } else { + qDebug() << "header verification of QPF2 font failed. maybe it is corrupt?"; + } +} + +void QPlatformFontDatabase::registerFont(const QString &familyname, const QString &foundryname, int weight, + QFont::Style style, int stretch, bool antialiased, bool scalable, int pixelSize, + const QSupportedWritingSystems &writingSystems, void *usrPtr) +{ + if (scalable) + pixelSize = 0; + qt_registerFont(familyname,foundryname,weight,style,stretch,antialiased,scalable,pixelSize,writingSystems,usrPtr); +} + +class QWritingSystemsPrivate +{ +public: + QWritingSystemsPrivate() + : ref(1) + , vector(QFontDatabase::WritingSystemsCount,false) + { + } + + QWritingSystemsPrivate(const QWritingSystemsPrivate *other) + : ref(1) + , vector(other->vector) + { + } + + QAtomicInt ref; + QVector<bool> vector; +}; + +QSupportedWritingSystems::QSupportedWritingSystems() +{ + d = new QWritingSystemsPrivate; +} + +QSupportedWritingSystems::QSupportedWritingSystems(const QSupportedWritingSystems &other) +{ + d = other.d; + d->ref.ref(); +} + +QSupportedWritingSystems &QSupportedWritingSystems::operator=(const QSupportedWritingSystems &other) +{ + if (d != other.d) { + other.d->ref.ref(); + if (!d->ref.deref()) + delete d; + d = other.d; + } + return *this; +} + +QSupportedWritingSystems::~QSupportedWritingSystems() +{ + if (!d->ref.deref()) + delete d; +} + +void QSupportedWritingSystems::detach() +{ + if (d->ref != 1) { + QWritingSystemsPrivate *newd = new QWritingSystemsPrivate(d); + if (!d->ref.deref()) + delete d; + d = newd; + } +} + +void QSupportedWritingSystems::setSupported(QFontDatabase::WritingSystem writingSystem, bool support) +{ + detach(); + d->vector[writingSystem] = support; +} + +bool QSupportedWritingSystems::supported(QFontDatabase::WritingSystem writingSystem) const +{ + return d->vector.at(writingSystem); +} + +void QPlatformFontDatabase::populateFontDatabase() +{ + QString fontpath = fontDir(); + + if(!QFile::exists(fontpath)) { + qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?", + qPrintable(fontpath)); + } + + QDir dir(fontpath); + dir.setNameFilters(QStringList() << QLatin1String("*.qpf2")); + dir.refresh(); + for (int i = 0; i < int(dir.count()); ++i) { + const QByteArray fileName = QFile::encodeName(dir.absoluteFilePath(dir[i])); + QFile file(QString::fromLocal8Bit(fileName)); + if (file.open(QFile::ReadOnly)) { + const QByteArray fileData = file.readAll(); + QByteArray *fileDataPtr = new QByteArray(fileData); + registerQPF2Font(fileData, fileDataPtr); + } + } +} + +QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle) +{ + Q_UNUSED(script); + Q_UNUSED(handle); + QByteArray *fileDataPtr = static_cast<QByteArray *>(handle); + QFontEngineQPA *engine = new QFontEngineQPA(fontDef,*fileDataPtr); + qDebug() << fontDef.pixelSize << fontDef.weight << fontDef.style << fontDef.stretch << fontDef.styleHint << fontDef.styleStrategy << fontDef.family << script; + return engine; +} + +QStringList QPlatformFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QUnicodeTables::Script &script) const +{ + Q_UNUSED(family); + Q_UNUSED(style); + Q_UNUSED(script); + return QStringList(); +} + +void QPlatformFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) +{ + Q_UNUSED(fontData); + Q_UNUSED(fileName); + + qWarning("This plugin does not support application fonts"); +} + +void QPlatformFontDatabase::releaseHandle(void *handle) +{ + QByteArray *fileDataPtr = static_cast<QByteArray *>(handle); + delete fileDataPtr; +} + +QString QPlatformFontDatabase::fontDir() const +{ + QString fontpath = QString::fromLocal8Bit(qgetenv("QT_QPA_FONTDIR")); + if (fontpath.isEmpty()) { +#ifndef QT_NO_SETTINGS + fontpath = QLibraryInfo::location(QLibraryInfo::LibrariesPath); + fontpath += QLatin1String("/fonts"); +#endif + } + + return fontpath; +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qplatformfontdatabase_qpa.h b/src/gui/text/qplatformfontdatabase_qpa.h new file mode 100644 index 0000000..a34033f --- /dev/null +++ b/src/gui/text/qplatformfontdatabase_qpa.h @@ -0,0 +1,65 @@ +#ifndef QPLATFORMFONTDATABASE_QPA_H +#define QPLATFORMFONTDATABASE_QPA_H + +#include <QtCore/qconfig.h> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QList> +#include <QtGui/QFontDatabase> +#include <QtGui/private/qfont_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QWritingSystemsPrivate; + +class Q_GUI_EXPORT QSupportedWritingSystems +{ +public: + + QSupportedWritingSystems(); + QSupportedWritingSystems(const QSupportedWritingSystems &other); + QSupportedWritingSystems &operator=(const QSupportedWritingSystems &other); + ~QSupportedWritingSystems(); + + void setSupported(QFontDatabase::WritingSystem, bool supported = true); + bool supported(QFontDatabase::WritingSystem) const; + +private: + void detach(); + + QWritingSystemsPrivate *d; + + friend Q_GUI_EXPORT bool operator==(const QSupportedWritingSystems &, const QSupportedWritingSystems &); + friend Q_GUI_EXPORT bool operator!=(const QSupportedWritingSystems &, const QSupportedWritingSystems &); +}; + +Q_GUI_EXPORT bool operator==(const QSupportedWritingSystems &, const QSupportedWritingSystems &); +Q_GUI_EXPORT bool operator!=(const QSupportedWritingSystems &, const QSupportedWritingSystems &); + +class QFontRequestPrivate; + +class Q_GUI_EXPORT QPlatformFontDatabase +{ +public: + virtual void populateFontDatabase(); + virtual QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); + virtual QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QUnicodeTables::Script &script) const; + virtual void addApplicationFont(const QByteArray &fontData, const QString &fileName); + virtual void releaseHandle(void *handle); + + virtual QString fontDir() const; + + //callback + static void registerQPF2Font(const QByteArray &dataArray, void *handle); + static void registerFont(const QString &familyname, const QString &foundryname, int weight, + QFont::Style style, int stetch, bool antialiased, bool scalable, int pixelSize, + const QSupportedWritingSystems &writingSystems, void *handle); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPLATFORMFONTDATABASE_QPA_H diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 1040ad8..8721d80 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -25,7 +25,7 @@ HEADERS += \ text/qabstracttextdocumentlayout.h \ text/qtextdocumentlayout_p.h \ text/qtextcursor.h \ - text/qtextcursor_p.h \ + text/qtextcursor_p.h \ text/qtextdocumentfragment.h \ text/qtextdocumentfragment_p.h \ text/qtextimagehandler_p.h \ @@ -39,7 +39,7 @@ HEADERS += \ text/qzipwriter_p.h \ text/qtextodfwriter_p.h \ text/qstatictext_p.h \ - text/qstatictext.h + text/qstatictext.h SOURCES += \ text/qfont.cpp \ @@ -69,7 +69,7 @@ SOURCES += \ text/qcssparser.cpp \ text/qzip.cpp \ text/qtextodfwriter.cpp \ - text/qstatictext.cpp + text/qstatictext.cpp win32 { SOURCES += \ @@ -112,15 +112,15 @@ embedded { qpa { SOURCES += \ - text/qfont_qws.cpp \ - text/qfontengine_ft.cpp \ - text/qfontengine_qpf.cpp \ - text/qabstractfontengine_qws.cpp + text/qfont_qpa.cpp \ + text/qfontengine_qpa.cpp \ + text/qplatformfontdatabase_qpa.cpp + HEADERS += \ - text/qfontengine_ft_p.h \ - text/qabstractfontengine_qws.h \ - text/qabstractfontengine_p.h + text/qplatformfontdatabase_qpa.h + DEFINES += QT_NO_FONTCONFIG + DEFINES += QT_NO_FREETYPE } symbian { @@ -142,6 +142,7 @@ symbian { } } +!qpa { contains(QT_CONFIG, freetype) { SOURCES += \ ../3rdparty/freetype/src/base/ftbase.c \ @@ -215,6 +216,7 @@ contains(QT_CONFIG, freetype) { contains(QT_CONFIG, fontconfig) { CONFIG += opentype } +}#!qpa DEFINES += QT_NO_OPENTYPE INCLUDEPATH += ../3rdparty/harfbuzz/src diff --git a/src/plugins/platforms/directfb/directfb.pro b/src/plugins/platforms/directfb/directfb.pro index f81ec31..48128fb 100644 --- a/src/plugins/platforms/directfb/directfb.pro +++ b/src/plugins/platforms/directfb/directfb.pro @@ -27,5 +27,7 @@ HEADERS = qdirectfbintegration.h \ qdirectfbinput.h \ qdirectfbcursor.h \ qdirectfbwindow.h + +include(../fontdatabases/genericunix/genericunix.pri) target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.cpp b/src/plugins/platforms/directfb/qdirectfbintegration.cpp index b19a1d9..64b98db 100644 --- a/src/plugins/platforms/directfb/qdirectfbintegration.cpp +++ b/src/plugins/platforms/directfb/qdirectfbintegration.cpp @@ -46,6 +46,8 @@ #include "qdirectfbcursor.h" #include "qdirectfbwindow.h" +#include "qgenericunixfontdatabase.h" + #include <private/qwindowsurface_raster_p.h> #include <private/qpixmap_raster_p.h> @@ -80,6 +82,7 @@ QDirectFbScreen::~QDirectFbScreen() } QDirectFbIntegration::QDirectFbIntegration() + : mFontDb(new QGenericUnixFontDatabase()) { const QStringList args = QCoreApplication::arguments(); int argc = args.size(); @@ -133,9 +136,9 @@ QWindowSurface *QDirectFbIntegration::createWindowSurface(QWidget *widget, WId w return new QDirectFbWindowSurface(widget,winId); } -QBlittable *QDirectFbIntegration::createBlittable(const QSize &size) const +QPlatformFontDatabase *QDirectFbIntegration::fontDatabase() const { - return new QDirectFbBlitter(size); + return mFontDb; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.h b/src/plugins/platforms/directfb/qdirectfbintegration.h index 27847e2..d2d8367 100644 --- a/src/plugins/platforms/directfb/qdirectfbintegration.h +++ b/src/plugins/platforms/directfb/qdirectfbintegration.h @@ -87,14 +87,16 @@ public: QPixmapData *createPixmapData(QPixmapData::PixelType type) const; QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId = 0) const; QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; - QBlittable *createBlittable(const QSize &size) const; QList<QPlatformScreen *> screens() const { return mScreens; } + QPlatformFontDatabase *fontDatabase() const; + private: QList<QPlatformScreen *> mScreens; QDirectFbInput *mInput; QThread *mInputRunner; + QPlatformFontDatabase *mFontDb; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro index 5d1318a..7ad8fd9 100644 --- a/src/plugins/platforms/eglfs/eglfs.pro +++ b/src/plugins/platforms/eglfs/eglfs.pro @@ -25,5 +25,7 @@ HEADERS = qeglfsintegration.h \ qeglfswindowsurface.h \ qeglfsscreen.h +include(../fontdatabases/genericunix/genericunix.pri) + target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index 2b673ae..07605ec 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -48,11 +48,14 @@ #include <QtGui/QPlatformWindowFormat> #include <QtOpenGL/private/qpixmapdata_gl_p.h> +#include "qgenericunixfontdatabase.h" + #include <EGL/egl.h> QT_BEGIN_NAMESPACE QEglFSIntegration::QEglFSIntegration() + mFontDb(new QGenericUnixFontDatabase()) { m_primaryScreen = new QEglFSScreen(EGL_DEFAULT_DISPLAY); @@ -90,4 +93,9 @@ QWindowSurface *QEglFSIntegration::createWindowSurface(QWidget *widget, WId winI return new QEglFSWindowSurface(m_primaryScreen,widget); } +QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const +{ + return mFontDb; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index f15b6b2..0342539 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -62,7 +62,10 @@ public: QList<QPlatformScreen *> screens() const { return mScreens; } + QPlatformFontDatabase *fontDatabase() const; + private: + QPlatformFontDatabase *mFontDb; QList<QPlatformScreen *> mScreens; QEglFSScreen *m_primaryScreen; }; diff --git a/src/plugins/platforms/fontdatabases/basicunix/basicunix.pri b/src/plugins/platforms/fontdatabases/basicunix/basicunix.pri new file mode 100644 index 0000000..21aedba --- /dev/null +++ b/src/plugins/platforms/fontdatabases/basicunix/basicunix.pri @@ -0,0 +1,82 @@ +DEFINES += QT_NO_FONTCONFIG +HEADERS += \ + $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h \ + $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft_p.h + +SOURCES += \ + $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp \ + $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft.cpp + +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src + +INCLUDEPATH += $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/basicunix + +CONFIG += opentype + +contains(QT_CONFIG, freetype) { + SOURCES += \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftbase.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftbbox.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftdebug.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftglyph.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftinit.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftmm.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/fttype1.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftsynth.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftbitmap.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/bdf/bdf.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/cache/ftcache.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/cff/cff.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/cid/type1cid.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/gzip/ftgzip.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/pcf/pcf.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/pfr/pfr.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/psaux/psaux.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/pshinter/pshinter.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/psnames/psmodule.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/raster/raster.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/sfnt/sfnt.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/smooth/smooth.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/truetype/truetype.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/type1/type1.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/type42/type42.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/winfonts/winfnt.c \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/lzw/ftlzw.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvalid.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvbase.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvgdef.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvjstf.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvcommn.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvgpos.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvgsub.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvmod.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afangles.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afglobal.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/aflatin.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afmodule.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afdummy.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afhints.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afloader.c\ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/autofit.c + + symbian { + SOURCES += \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftsystem.c + } else { + SOURCES += \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/builds/unix/ftsystem.c + INCLUDEPATH += \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/builds/unix + } + + INCLUDEPATH += \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/src \ + $$QT_SOURCE_TREE/src/3rdparty/freetype/include + + DEFINES += FT2_BUILD_LIBRARY FT_CONFIG_OPTION_SYSTEM_ZLIB + } else:contains(QT_CONFIG, system-freetype) { + # pull in the proper freetype2 include directory + include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri) + LIBS_PRIVATE += -lfreetype + } + diff --git a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp b/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp new file mode 100644 index 0000000..5b8ca63 --- /dev/null +++ b/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp @@ -0,0 +1,281 @@ +#include "qbasicunixfontdatabase.h" + +#include <QtGui/private/qapplication_p.h> +#include <QtGui/QPlatformScreen> + +#include <QtCore/QFile> +#include <QtCore/QLibraryInfo> +#include <QtCore/QDir> + +#undef QT_NO_FREETYPE +#include <QtGui/private/qfontengine_ft_p.h> +#include <QtGui/private/qfontengine_p.h> + +#include <ft2build.h> +#include FT_TRUETYPE_TABLES_H + +#define SimplifiedChineseCsbBit 18 +#define TraditionalChineseCsbBit 20 +#define JapaneseCsbBit 17 +#define KoreanCsbBit 21 + +static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { + // Any, + { 127, 127 }, + // Latin, + { 0, 127 }, + // Greek, + { 7, 127 }, + // Cyrillic, + { 9, 127 }, + // Armenian, + { 10, 127 }, + // Hebrew, + { 11, 127 }, + // Arabic, + { 13, 127 }, + // Syriac, + { 71, 127 }, + //Thaana, + { 72, 127 }, + //Devanagari, + { 15, 127 }, + //Bengali, + { 16, 127 }, + //Gurmukhi, + { 17, 127 }, + //Gujarati, + { 18, 127 }, + //Oriya, + { 19, 127 }, + //Tamil, + { 20, 127 }, + //Telugu, + { 21, 127 }, + //Kannada, + { 22, 127 }, + //Malayalam, + { 23, 127 }, + //Sinhala, + { 73, 127 }, + //Thai, + { 24, 127 }, + //Lao, + { 25, 127 }, + //Tibetan, + { 70, 127 }, + //Myanmar, + { 74, 127 }, + // Georgian, + { 26, 127 }, + // Khmer, + { 80, 127 }, + // SimplifiedChinese, + { 126, 127 }, + // TraditionalChinese, + { 126, 127 }, + // Japanese, + { 126, 127 }, + // Korean, + { 56, 127 }, + // Vietnamese, + { 0, 127 }, // same as latin1 + // Other, + { 126, 127 }, + // Ogham, + { 78, 127 }, + // Runic, + { 79, 127 }, + // Nko, + { 14, 127 }, +}; + +static QSupportedWritingSystems determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]) +{ + QSupportedWritingSystems writingSystems; + bool hasScript = false; + + int i; + for(i = 0; i < QFontDatabase::WritingSystemsCount; i++) { + int bit = requiredUnicodeBits[i][0]; + int index = bit/32; + int flag = 1 << (bit&31); + if (bit != 126 && unicodeRange[index] & flag) { + bit = requiredUnicodeBits[i][1]; + index = bit/32; + + flag = 1 << (bit&31); + if (bit == 127 || unicodeRange[index] & flag) { + writingSystems.setSupported(QFontDatabase::WritingSystem(i)); + hasScript = true; + // qDebug("font %s: index=%d, flag=%8x supports script %d", familyName.latin1(), index, flag, i); + } + } + } + if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) { + writingSystems.setSupported(QFontDatabase::SimplifiedChinese); + hasScript = true; + //qDebug("font %s supports Simplified Chinese", familyName.latin1()); + } + if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) { + writingSystems.setSupported(QFontDatabase::TraditionalChinese); + hasScript = true; + //qDebug("font %s supports Traditional Chinese", familyName.latin1()); + } + if(codePageRange[0] & (1 << JapaneseCsbBit)) { + writingSystems.setSupported(QFontDatabase::Japanese); + hasScript = true; + //qDebug("font %s supports Japanese", familyName.latin1()); + } + if(codePageRange[0] & (1 << KoreanCsbBit)) { + writingSystems.setSupported(QFontDatabase::Korean); + hasScript = true; + //qDebug("font %s supports Korean", familyName.latin1()); + } + if (!hasScript) + writingSystems.setSupported(QFontDatabase::Symbol); + + return writingSystems; +} + +static inline bool scriptRequiresOpenType(int script) +{ + return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) + || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); +} + +void QBasicUnixFontDatabase::populateFontDatabase() +{ + QPlatformFontDatabase::populateFontDatabase(); + QString fontpath = fontDir(); + + if(!QFile::exists(fontpath)) { + qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?", + qPrintable(fontpath)); + } + + QDir dir(fontpath); + dir.setNameFilters(QStringList() << QLatin1String("*.ttf") + << QLatin1String("*.ttc") << QLatin1String("*.pfa") + << QLatin1String("*.pfb")); + dir.refresh(); + for (int i = 0; i < int(dir.count()); ++i) { + const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i])); +// qDebug() << "looking at" << file; + addTTFile(QByteArray(), file); + } +} + +QFontEngine *QBasicUnixFontDatabase::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *usrPtr) +{ + QFontEngineFT *engine; + FontFile *fontfile = static_cast<FontFile *> (usrPtr); + QFontEngine::FaceId fid; + fid.filename = fontfile->fileName.toLocal8Bit(); + fid.index = fontfile->indexValue; + engine = new QFontEngineFT(fontDef); + + bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); + QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; + if (!engine->init(fid,antialias,format)) { + delete engine; + engine = 0; + return engine; + } + if (engine->invalid()) { + delete engine; + engine = 0; + } else if (scriptRequiresOpenType(script)) { + HB_Face hbFace = engine->harfbuzzFace(); + if (!hbFace || !hbFace->supported_scripts[script]) { + delete engine; + engine = 0; + } + } + + return engine; +} + +QStringList QBasicUnixFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QUnicodeTables::Script &script) const +{ + Q_UNUSED(family); + Q_UNUSED(style); + Q_UNUSED(script); + return QStringList(); +} + +void QBasicUnixFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) +{ + addTTFile(fontData,fileName.toLocal8Bit()); +} + +void QBasicUnixFontDatabase::releaseHandle(void *handle) +{ + FontFile *file = static_cast<FontFile *>(handle); + delete file; +} + +void QBasicUnixFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) +{ + extern FT_Library qt_getFreetype(); + FT_Library library = qt_getFreetype(); + + int index = 0; + int numFaces = 0; + do { + FT_Face face; + FT_Error error; + if (!fontData.isEmpty()) { + error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); + } else { + error = FT_New_Face(library, file.constData(), index, &face); + } + if (error != FT_Err_Ok) { + qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; + break; + } + numFaces = face->num_faces; + + int weight = QFont::Normal; + + QFont::Style style = QFont::StyleNormal; + if (face->style_flags & FT_STYLE_FLAG_ITALIC) + style = QFont::StyleItalic; + + if (face->style_flags & FT_STYLE_FLAG_BOLD) + weight = QFont::Bold; + + QSupportedWritingSystems writingSystems; + // detect symbol fonts + for (int i = 0; i < face->num_charmaps; ++i) { + FT_CharMap cm = face->charmaps[i]; + if (cm->encoding == ft_encoding_adobe_custom + || cm->encoding == ft_encoding_symbol) { + writingSystems.setSupported(QFontDatabase::Symbol); + break; + } + } + + TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); + if (os2) { + quint32 unicodeRange[4] = { + os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4 + }; + quint32 codePageRange[2] = { + os2->ulCodePageRange1, os2->ulCodePageRange2 + }; + + writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + } + + QString family = QString::fromAscii(face->family_name); + FontFile *fontFile = new FontFile; + fontFile->fileName = file; + fontFile->indexValue = index; + + registerFont(family,"",weight,style,100,true,true,0,writingSystems,fontFile); + + FT_Done_Face(face); + ++index; + } while (index < numFaces); +} diff --git a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h b/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h new file mode 100644 index 0000000..401a4aa --- /dev/null +++ b/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h @@ -0,0 +1,26 @@ +#ifndef QBASICUNIXFONTDATABASE_H +#define QBASICUNIXFONTDATABASE_H + +#include <QPlatformFontDatabase> +#include <QtCore/QByteArray> +#include <QtCore/QString> + +struct FontFile +{ + QString fileName; + int indexValue; +}; + +class QBasicUnixFontDatabase : public QPlatformFontDatabase +{ +public: + void populateFontDatabase(); + QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); + QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QUnicodeTables::Script &script) const; + void addApplicationFont(const QByteArray &fontData, const QString &fileName); + void releaseHandle(void *handle); + + static void addTTFile(const QByteArray &fontData, const QByteArray &file); +}; + +#endif // QBASICUNIXFONTDATABASE_H diff --git a/src/plugins/platforms/fontdatabases/fontconfig/fontconfig.pri b/src/plugins/platforms/fontdatabases/fontconfig/fontconfig.pri new file mode 100644 index 0000000..19c74ed --- /dev/null +++ b/src/plugins/platforms/fontdatabases/fontconfig/fontconfig.pri @@ -0,0 +1,12 @@ +include(../basicunix/basicunix.pri) + +HEADERS += \ + $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h + +SOURCES += \ + $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp + +INCLUDEPATH += $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/fontconfig +LIBS_PRIVATE += -lfontconfig + + diff --git a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp new file mode 100644 index 0000000..562cb2d --- /dev/null +++ b/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -0,0 +1,528 @@ +#include "qfontconfigdatabase.h" + +#include <QtCore/QList> +#include <QtGui/private/qfont_p.h> + +#include <QtCore/QElapsedTimer> + +#include <QtGui/private/qapplication_p.h> +#include <QtGui/QPlatformScreen> + +#include <QtGui/private/qfontengine_ft_p.h> +#include <QtGui/private/qfontengine_p.h> + + + +#include <ft2build.h> +#include FT_TRUETYPE_TABLES_H + +#include <fontconfig/fontconfig.h> + +#define SimplifiedChineseCsbBit 18 +#define TraditionalChineseCsbBit 20 +#define JapaneseCsbBit 17 +#define KoreanCsbBit 21 + +static inline bool requiresOpenType(int writingSystem) +{ + return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala) + || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko); +} +static inline bool scriptRequiresOpenType(int script) +{ + return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) + || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); +} + +static int getFCWeight(int fc_weight) +{ + int qtweight = QFont::Black; + if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2) + qtweight = QFont::Light; + else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) + qtweight = QFont::Normal; + else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) + qtweight = QFont::DemiBold; + else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2) + qtweight = QFont::Bold; + + return qtweight; +} + +static const char *specialLanguages[] = { + "en", // Common + "el", // Greek + "ru", // Cyrillic + "hy", // Armenian + "he", // Hebrew + "ar", // Arabic + "syr", // Syriac + "div", // Thaana + "hi", // Devanagari + "bn", // Bengali + "pa", // Gurmukhi + "gu", // Gujarati + "or", // Oriya + "ta", // Tamil + "te", // Telugu + "kn", // Kannada + "ml", // Malayalam + "si", // Sinhala + "th", // Thai + "lo", // Lao + "bo", // Tibetan + "my", // Myanmar + "ka", // Georgian + "ko", // Hangul + "", // Ogham + "", // Runic + "km", // Khmer + "" // N'Ko +}; +enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) }; + +static const ushort specialChars[] = { + 0, // English + 0, // Greek + 0, // Cyrillic + 0, // Armenian + 0, // Hebrew + 0, // Arabic + 0, // Syriac + 0, // Thaana + 0, // Devanagari + 0, // Bengali + 0, // Gurmukhi + 0, // Gujarati + 0, // Oriya + 0, // Tamil + 0xc15, // Telugu + 0xc95, // Kannada + 0xd15, // Malayalam + 0xd9a, // Sinhala + 0, // Thai + 0, // Lao + 0, // Tibetan + 0x1000, // Myanmar + 0, // Georgian + 0, // Hangul + 0x1681, // Ogham + 0x16a0, // Runic + 0, // Khmer + 0x7ca // N'Ko +}; +enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) }; + +// this could become a list of all languages used for each writing +// system, instead of using the single most common language. +static const char *languageForWritingSystem[] = { + 0, // Any + "en", // Latin + "el", // Greek + "ru", // Cyrillic + "hy", // Armenian + "he", // Hebrew + "ar", // Arabic + "syr", // Syriac + "div", // Thaana + "hi", // Devanagari + "bn", // Bengali + "pa", // Gurmukhi + "gu", // Gujarati + "or", // Oriya + "ta", // Tamil + "te", // Telugu + "kn", // Kannada + "ml", // Malayalam + "si", // Sinhala + "th", // Thai + "lo", // Lao + "bo", // Tibetan + "my", // Myanmar + "ka", // Georgian + "km", // Khmer + "zh-cn", // SimplifiedChinese + "zh-tw", // TraditionalChinese + "ja", // Japanese + "ko", // Korean + "vi", // Vietnamese + 0, // Symbol + 0, // Ogham + 0, // Runic + 0 // N'Ko +}; +enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) }; + +// Unfortunately FontConfig doesn't know about some languages. We have to test these through the +// charset. The lists below contain the systems where we need to do this. +static const ushort sampleCharForWritingSystem[] = { + 0, // Any + 0, // Latin + 0, // Greek + 0, // Cyrillic + 0, // Armenian + 0, // Hebrew + 0, // Arabic + 0, // Syriac + 0, // Thaana + 0, // Devanagari + 0, // Bengali + 0, // Gurmukhi + 0, // Gujarati + 0, // Oriya + 0, // Tamil + 0xc15, // Telugu + 0xc95, // Kannada + 0xd15, // Malayalam + 0xd9a, // Sinhala + 0, // Thai + 0, // Lao + 0, // Tibetan + 0x1000, // Myanmar + 0, // Georgian + 0, // Khmer + 0, // SimplifiedChinese + 0, // TraditionalChinese + 0, // Japanese + 0, // Korean + 0, // Vietnamese + 0, // Symbol + 0x1681, // Ogham + 0x16a0, // Runic + 0x7ca // N'Ko +}; +enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) }; + +// Newer FontConfig let's us sort out fonts that contain certain glyphs, but no +// open type tables for is directly. Do this so we don't pick some strange +// pseudo unicode font +static const char *openType[] = { + 0, // Any + 0, // Latin + 0, // Greek + 0, // Cyrillic + 0, // Armenian + 0, // Hebrew + 0, // Arabic + "syrc", // Syriac + "thaa", // Thaana + "deva", // Devanagari + "beng", // Bengali + "guru", // Gurmukhi + "gurj", // Gujarati + "orya", // Oriya + "taml", // Tamil + "telu", // Telugu + "knda", // Kannada + "mlym", // Malayalam + "sinh", // Sinhala + 0, // Thai + 0, // Lao + "tibt", // Tibetan + "mymr", // Myanmar + 0, // Georgian + "khmr", // Khmer + 0, // SimplifiedChinese + 0, // TraditionalChinese + 0, // Japanese + 0, // Korean + 0, // Vietnamese + 0, // Symbol + 0, // Ogham + 0, // Runic + "nko " // N'Ko +}; + +void QFontconfigDatabase::populateFontDatabase() +{ + FcFontSet *fonts; + + QString familyName; + FcChar8 *value = 0; + int weight_value; + int slant_value; + int spacing_value; + FcChar8 *file_value; + int indexValue; + FcChar8 *foundry_value; + FcBool scalable; + FcBool antialias; + + { + FcObjectSet *os = FcObjectSetCreate(); + FcPattern *pattern = FcPatternCreate(); + const char *properties [] = { + FC_FAMILY, FC_WEIGHT, FC_SLANT, + FC_SPACING, FC_FILE, FC_INDEX, + FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT, + FC_WIDTH, +#if FC_VERSION >= 20297 + FC_CAPABILITY, +#endif + (const char *)0 + }; + const char **p = properties; + while (*p) { + FcObjectSetAdd(os, *p); + ++p; + } + fonts = FcFontList(0, pattern, os); + FcObjectSetDestroy(os); + FcPatternDestroy(pattern); + } + + for (int i = 0; i < fonts->nfont; i++) { + if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) + continue; + // capitalize(value); + familyName = QString::fromUtf8((const char *)value); + slant_value = FC_SLANT_ROMAN; + weight_value = FC_WEIGHT_MEDIUM; + spacing_value = FC_PROPORTIONAL; + file_value = 0; + indexValue = 0; + scalable = FcTrue; + + + if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch) + slant_value = FC_SLANT_ROMAN; + if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch) + weight_value = FC_WEIGHT_MEDIUM; + if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch) + spacing_value = FC_PROPORTIONAL; + if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch) + file_value = 0; + if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch) + indexValue = 0; + if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch) + scalable = FcTrue; + if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) + foundry_value = 0; + if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch) + antialias = true; + + QSupportedWritingSystems writingSystems; + FcLangSet *langset = 0; + FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset); + if (res == FcResultMatch) { + for (int i = 1; i < LanguageCount; ++i) { + const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i]; + if (lang) { + FcLangResult langRes = FcLangSetHasLang(langset, lang); + if (langRes != FcLangDifferentLang) + writingSystems.setSupported(QFontDatabase::WritingSystem(i)); + } + } + } else { + // we set Other to supported for symbol fonts. It makes no + // sense to merge these with other ones, as they are + // special in a way. + writingSystems.setSupported(QFontDatabase::Other); + } + + FcCharSet *cs = 0; + res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs); + if (res == FcResultMatch) { + // some languages are not supported by FontConfig, we rather check the + // charset to detect these + for (int i = 1; i < SampleCharCount; ++i) { + if (!sampleCharForWritingSystem[i]) + continue; + if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i])) + writingSystems.setSupported(QFontDatabase::WritingSystem(i)); + } + } + +#if FC_VERSION >= 20297 + for (int j = 1; j < LanguageCount; ++j) { + if (writingSystems.supported(QFontDatabase::WritingSystem(j)) + && requiresOpenType(j) && openType[j]) { + FcChar8 *cap; + res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap); + if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) + writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); + } + } +#endif + + FontFile *fontFile = new FontFile; + fontFile->fileName = QLatin1String((const char *)file_value); + fontFile->indexValue = indexValue; + + QFont::Style style = (slant_value == FC_SLANT_ITALIC) + ? QFont::StyleItalic + : ((slant_value == FC_SLANT_OBLIQUE) + ? QFont::StyleOblique + : QFont::StyleNormal); + int weight = getFCWeight(weight_value); + + double pixel_size = 0; + if (!scalable) { + int width = 100; + FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width); + FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size); + } + + QPlatformFontDatabase::registerFont(familyName,QLatin1String((const char *)foundry_value),weight,style,100,antialias,scalable,pixel_size,writingSystems,fontFile); +// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; + } + + FcFontSetDestroy (fonts); + + struct FcDefaultFont { + const char *qtname; + const char *rawname; + bool fixed; + }; + const FcDefaultFont defaults[] = { + { "Serif", "serif", false }, + { "Sans Serif", "sans-serif", false }, + { "Monospace", "monospace", true }, + { 0, 0, false } + }; + const FcDefaultFont *f = defaults; + // aliases only make sense for 'common', not for any of the specials + QSupportedWritingSystems ws; + ws.setSupported(QFontDatabase::Latin); + + while (f->qtname) { + registerFont(f->qtname,"",50,QFont::StyleNormal,100,true,true,0,ws,0); + registerFont(f->qtname,"",50,QFont::StyleItalic,100,true,true,0,ws,0); + registerFont(f->qtname,"",50,QFont::StyleOblique,100,true,true,0,ws,0); + ++f; + } + + const FcDefaultFont *s = defaults; + QFont font("Sans Serif"); + font.setPointSize(9); + QApplication::setFont(font); +} + +QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QUnicodeTables::Script script, void *usrPtr) +{ + QFontDef fontDef = f; + + QFontEngineFT *engine; + FontFile *fontfile = static_cast<FontFile *> (usrPtr); + QFontEngine::FaceId fid; + fid.filename = fontfile->fileName.toLocal8Bit(); + fid.index = fontfile->indexValue; + + //try and get the pattern + FcPattern *pattern = FcPatternCreate(); + + bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); + QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; + + engine = new QFontEngineFT(fontDef); + + FcValue value; + value.type = FcTypeString; + QByteArray cs = fontDef.family.toUtf8(); + value.u.s = (const FcChar8 *)cs.data(); + FcPatternAdd(pattern,FC_FAMILY,value,true); + + + value.u.s = (const FcChar8 *)fid.filename.data(); + FcPatternAdd(pattern,FC_FILE,value,true); + + value.type = FcTypeInteger; + value.u.i = fid.index; + FcPatternAdd(pattern,FC_INDEX,value,true); + + QFontEngineFT::HintStyle default_hint_style; + + if (FcConfigSubstitute(0,pattern,FcMatchPattern)) { + + //hinting + int hint_style = 0; + if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch) + hint_style = QFontEngineFT::HintFull; + switch (hint_style) { + case FC_HINT_NONE: + default_hint_style = QFontEngineFT::HintNone; + break; + case FC_HINT_SLIGHT: + default_hint_style = QFontEngineFT::HintLight; + break; + case FC_HINT_MEDIUM: + default_hint_style = QFontEngineFT::HintMedium; + break; + default: + default_hint_style = QFontEngineFT::HintFull; + break; + } + } + + engine->setDefaultHintStyle(default_hint_style); + if (!engine->init(fid,antialias,format)) { + delete engine; + engine = 0; + return engine; + } + if (engine->invalid()) { + delete engine; + engine = 0; + } else if (scriptRequiresOpenType(script)) { + HB_Face hbFace = engine->harfbuzzFace(); + if (!hbFace || !hbFace->supported_scripts[script]) { + delete engine; + engine = 0; + } + } + + return engine; +} + +QStringList QFontconfigDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QUnicodeTables::Script &script) const +{ + QStringList fallbackFamilies; + FcPattern *pattern = FcPatternCreate(); + if (!pattern) + return fallbackFamilies; + + FcValue value; + value.type = FcTypeString; + QByteArray cs = family.toUtf8(); + value.u.s = (const FcChar8 *)cs.data(); + FcPatternAdd(pattern,FC_FAMILY,value,true); + + int slant_value = FC_SLANT_ROMAN; + if (style == QFont::StyleItalic) + slant_value = FC_SLANT_ITALIC; + else if (style == QFont::StyleOblique) + slant_value = FC_SLANT_OBLIQUE; + FcPatternAddInteger(pattern, FC_SLANT, slant_value); + + if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') { + Q_ASSERT(script < QUnicodeTables::ScriptCount); + FcLangSet *ls = FcLangSetCreate(); + FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]); + FcPatternAddLangSet(pattern, FC_LANG, ls); + FcLangSetDestroy(ls); + } + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcConfigSubstitute(0, pattern, FcMatchFont); + + FcResult result = FcResultMatch; + FcFontSet *fontSet = FcFontSort(0,pattern,FcFalse,0,&result); + + if (fontSet && result == FcResultMatch) + { + for (int i = 0; i < fontSet->nfont; i++) { + FcChar8 *value = 0; + if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) + continue; + // capitalize(value); + QString familyName = QString::fromUtf8((const char *)value); + if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive)) { + fallbackFamilies << familyName; + } + + } + } +// qDebug() << "fallbackFamilies for:" << family << fallbackFamilies; + + return fallbackFamilies; +} diff --git a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h b/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h new file mode 100644 index 0000000..5945b6e --- /dev/null +++ b/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h @@ -0,0 +1,15 @@ +#ifndef QFONTCONFIGDATABASE_H +#define QFONTCONFIGDATABASE_H + +#include <QPlatformFontDatabase> +#include "qbasicunixfontdatabase.h" + +class QFontconfigDatabase : public QBasicUnixFontDatabase +{ +public: + void populateFontDatabase(); + QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); + QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QUnicodeTables::Script &script) const; +}; + +#endif // QFONTCONFIGDATABASE_H diff --git a/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri b/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri new file mode 100644 index 0000000..dbcfbce --- /dev/null +++ b/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri @@ -0,0 +1,10 @@ +contains(QT_CONFIG, fontconfig) { + include(../fontconfig/fontconfig.pri) + DEFINES += Q_FONTCONFIGDATABASE +} else { + include(../basicunix/basicunix.pri) +} + +INCLUDEPATH += $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/genericunix +HEADERS += \ + $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/genericunix/qgenericunixfontdatabase.h diff --git a/src/plugins/platforms/fontdatabases/genericunix/qgenericunixfontdatabase.h b/src/plugins/platforms/fontdatabases/genericunix/qgenericunixfontdatabase.h new file mode 100644 index 0000000..ec083f8 --- /dev/null +++ b/src/plugins/platforms/fontdatabases/genericunix/qgenericunixfontdatabase.h @@ -0,0 +1,12 @@ +#ifndef QGENERICUNIXFONTDATABASE_H +#define QGENERICUNIXFONTDATABASE_H + +#ifdef Q_FONTCONFIGDATABASE +#include "qfontconfigdatabase.h" +typedef QFontconfigDatabase QGenericUnixFontDatabase; +#else +#include "qbasicunixfontdatabase.h" +typedef QBasicUnixFontDatabase QGenericUnixFontDatabase; +#endif //Q_FONTCONFIGDATABASE + +#endif // QGENERICUNIXFONTDATABASE_H diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro index 8d4b6d7..216b899 100644 --- a/src/plugins/platforms/linuxfb/linuxfb.pro +++ b/src/plugins/platforms/linuxfb/linuxfb.pro @@ -7,6 +7,7 @@ SOURCES = main.cpp qlinuxfbintegration.cpp HEADERS = qlinuxfbintegration.h include(../fb_base/fb_base.pri) +include(../fontdatabases/genericunix/genericunix.pri) target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index 437af81..aa1d401 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -41,6 +41,7 @@ #include "qlinuxfbintegration.h" #include "../fb_base/fb_base.h" +#include "qgenericunixfontdatabase.h" #include <QtGui/private/qpixmap_raster_p.h> #include <private/qcore_unix_p.h> // overrides QT_OPEN #include <qimage.h> @@ -156,6 +157,7 @@ void QLinuxFbIntegrationPrivate::closeTty() } QLinuxFbIntegration::QLinuxFbIntegration() + :fontDb(new QGenericUnixFontDatabase()) { d_ptr = new QLinuxFbIntegrationPrivate(); @@ -799,6 +801,11 @@ QPlatformWindow *QLinuxFbIntegration::createPlatformWindow(QWidget *widget, WId return w; } +QPlatformFontDatabase *QLinuxFbIntegration::fontDatabase() const +{ + return fontDb; +} + QLinuxFbScreen::QLinuxFbScreen(uchar * d, int w, int h, int lstep, QImage::Format screenFormat) : compositePainter(0) { diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h index dc61df5..a5d7abd 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h @@ -82,6 +82,8 @@ public: QList<QPlatformScreen *> screens() const { return mScreens; } + QPlatformFontDatabase *fontDatabase() const; + private: QLinuxFbScreen *mPrimaryScreen; QList<QPlatformScreen *> mScreens; @@ -122,6 +124,7 @@ private: void setPixelFormat(struct fb_var_screeninfo); void createPalette(fb_cmap &cmap, fb_var_screeninfo &vinfo, fb_fix_screeninfo &finfo); void blank(bool on); + QPlatformFontDatabase *fontDb; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index b68230c..3446e81 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -5,7 +5,15 @@ contains(QT_CONFIG, openvg):contains(QT_CONFIG, egl) { SUBDIRS += minimal -#this don't work. but leave it for now -qpa:x11 { +contains(QT_CONFIG, mitshm) { SUBDIRS += testlite } + +linux { + SUBDIRS += linuxfb +} + +unix { + SUBDIRS += vnc \ + qvfb +} diff --git a/src/plugins/platforms/qvfb/qvfb.pro b/src/plugins/platforms/qvfb/qvfb.pro index a560755..d2b332a 100644 --- a/src/plugins/platforms/qvfb/qvfb.pro +++ b/src/plugins/platforms/qvfb/qvfb.pro @@ -7,5 +7,7 @@ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms SOURCES = main.cpp qvfbintegration.cpp qvfbwindowsurface.cpp HEADERS = qvfbintegration.h qvfbwindowsurface.h +include(../fontdatabases/genericunix/genericunix.pri) + target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/qvfb/qvfbintegration.cpp b/src/plugins/platforms/qvfb/qvfbintegration.cpp index a50763a..0cc3938 100644 --- a/src/plugins/platforms/qvfb/qvfbintegration.cpp +++ b/src/plugins/platforms/qvfb/qvfbintegration.cpp @@ -62,6 +62,8 @@ #include <QApplication> #include <QWindowSystemInterface> +#include "qgenericunixfontdatabase.h" + QT_BEGIN_NAMESPACE @@ -409,6 +411,7 @@ QImage *QVFbScreen::screenImage() } QVFbIntegration::QVFbIntegration(const QStringList ¶mList) + : mFontDb(new QGenericUnixFontDatabase()) { int displayId = 0; if (paramList.length() > 0) @@ -435,6 +438,11 @@ QPlatformWindow *QVFbIntegration::createPlatformWindow(QWidget *widget, WId) con return new QVFbWindow(mPrimaryScreen, widget); } +QPlatformFontDatabase *QVFbIntegration::fontDatabase() const +{ + return mFontDb; +} + QT_END_NAMESPACE #include "qvfbintegration.moc" diff --git a/src/plugins/platforms/qvfb/qvfbintegration.h b/src/plugins/platforms/qvfb/qvfbintegration.h index e46e0da..198a45c 100644 --- a/src/plugins/platforms/qvfb/qvfbintegration.h +++ b/src/plugins/platforms/qvfb/qvfbintegration.h @@ -84,9 +84,12 @@ public: QList<QPlatformScreen *> screens() const { return mScreens; } + QPlatformFontDatabase *fontDatabase() const; + private: QVFbScreen *mPrimaryScreen; QList<QPlatformScreen *> mScreens; + QPlatformFontDatabase *mFontDb; }; diff --git a/src/plugins/platforms/testlite/qtestliteintegration.cpp b/src/plugins/platforms/testlite/qtestliteintegration.cpp index a8e0fa7..68e9051 100644 --- a/src/plugins/platforms/testlite/qtestliteintegration.cpp +++ b/src/plugins/platforms/testlite/qtestliteintegration.cpp @@ -49,6 +49,7 @@ #include <QPlatformCursor> #include "qtestlitewindow.h" +#include "qgenericunixfontdatabase.h" #ifndef QT_NO_OPENGL #include <GL/glx.h> @@ -84,8 +85,8 @@ public: QTestLiteIntegration::QTestLiteIntegration(bool useOpenGL) : mUseOpenGL(useOpenGL) + , mFontDb(new QGenericUnixFontDatabase()) { - xd = new MyDisplay; mPrimaryScreen = new QTestLiteScreen(); @@ -136,6 +137,11 @@ QPixmap QTestLiteIntegration::grabWindow(WId window, int x, int y, int width, in return QPixmap::fromImage(img); } +QPlatformFontDatabase *QTestLiteIntegration::fontDatabase() const +{ + return mFontDb; +} + bool QTestLiteIntegration::hasOpenGL() const { #ifndef QT_NO_OPENGL diff --git a/src/plugins/platforms/testlite/qtestliteintegration.h b/src/plugins/platforms/testlite/qtestliteintegration.h index ac10841..8286ef0 100644 --- a/src/plugins/platforms/testlite/qtestliteintegration.h +++ b/src/plugins/platforms/testlite/qtestliteintegration.h @@ -84,6 +84,8 @@ public: QList<QPlatformScreen *> screens() const { return mScreens; } + QPlatformFontDatabase *fontDatabase() const; + bool hasOpenGL() const; MyDisplay *xd; @@ -92,6 +94,7 @@ private: bool mUseOpenGL; QTestLiteScreen *mPrimaryScreen; QList<QPlatformScreen *> mScreens; + QPlatformFontDatabase *mFontDb; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/testlite/qtestlitewindow.cpp b/src/plugins/platforms/testlite/qtestlitewindow.cpp index 1f477db..1de4b9d 100644 --- a/src/plugins/platforms/testlite/qtestlitewindow.cpp +++ b/src/plugins/platforms/testlite/qtestlitewindow.cpp @@ -622,7 +622,7 @@ void QTestLiteWindow::handleKeyEvent(QEvent::Type type, void *ev) int qtcode = chars.toUpper()[0]; //Not exactly right... if (modifiers & Qt::ControlModifier && qtcode < ' ') qtcode = chars[0] + '@'; - QWindowSystemInterface::handleKeyEvent(widget(), e->time, type, qtcode, modifiers, QString::fromLatin1(chars)); + QWindowSystemInterface::handleKeyEvent(0, e->time, type, qtcode, modifiers, QString::fromLatin1(chars)); } else { qWarning() << "unknown X keycode" << hex << e->keycode << keySym; } @@ -647,9 +647,9 @@ WId QTestLiteWindow::winId() const void QTestLiteWindow::setParent(const QPlatformWindow *window) { - QPoint point = widget()->mapTo(widget()->nativeParentWidget(),QPoint()); - XReparentWindow(xd->display,x_window,window->winId(),point.x(),point.y()); - XMapWindow(xd->display, x_window); + QPoint point = widget()->mapTo(widget()->nativeParentWidget(),QPoint()); + XReparentWindow(xd->display,x_window,window->winId(),point.x(),point.y()); + XMapWindow(xd->display, x_window); } void QTestLiteWindow::raise() @@ -1441,7 +1441,7 @@ bool MyDisplay::handleEvent(XEvent *xe) xw->handleMouseEvent(QEvent::MouseMove, &xe->xbutton); break; - case XKeyPress: + case XKeyPress: xw->handleKeyEvent(QEvent::KeyPress, &xe->xkey); break; diff --git a/src/plugins/platforms/testlite/testlite.pro b/src/plugins/platforms/testlite/testlite.pro index 0a5ebb2..05bd384 100644 --- a/src/plugins/platforms/testlite/testlite.pro +++ b/src/plugins/platforms/testlite/testlite.pro @@ -1,18 +1,29 @@ -TARGET = qtestlitegraphicssystem -include(../../qpluginbase.pri) +TARGET = qtestlite +include(../../qpluginbase.pri) QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms -SOURCES = main.cpp qtestliteintegration.cpp qtestlitewindowsurface.cpp qtestlitewindow.cpp -HEADERS = qtestliteintegration.h qtestlitewindowsurface.h qtestlitewindow.h +SOURCES = \ + main.cpp \ + qtestliteintegration.cpp \ + qtestlitewindowsurface.cpp \ + qtestlitewindow.cpp + +HEADERS = \ + qtestliteintegration.h \ + qtestlitewindowsurface.h \ + qtestlitewindow.h + LIBS += -lX11 -lXext +include (../fontdatabases/genericunix/genericunix.pri) + contains(QT_CONFIG, opengl) { QT += opengl HEADERS += qglxintegration.h SOURCES += qglxintegration.cpp } -target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/vnc/qvncintegration.cpp b/src/plugins/platforms/vnc/qvncintegration.cpp index 331c16a..b36ff33 100644 --- a/src/plugins/platforms/vnc/qvncintegration.cpp +++ b/src/plugins/platforms/vnc/qvncintegration.cpp @@ -49,6 +49,7 @@ #include <QtGui/QPainter> #include <QtCore/QTimer> +#include "qgenericunixfontdatabase.h" QVNCScreen::QVNCScreen(QRect screenSize, int screenId) : QFbScreen::QFbScreen() @@ -100,7 +101,7 @@ static void usage() } QVNCIntegration::QVNCIntegration(const QStringList& paramList) - : virtualDesktop(false) + : virtualDesktop(false), fontDb(new QGenericUnixFontDatabase()) { int sizeX = defaultWidth(); int sizeY = defaultHeight(); @@ -234,3 +235,8 @@ void QVNCIntegration::moveToScreen(QWidget *window, int screen) window->platformWindow()->setGeometry(window->geometry()); // this should be unified elsewhere newScreen->addWindow(static_cast<QFbWindow *>(window->platformWindow())); } + +QPlatformFontDatabase *QVNCIntegration::fontDatabase() const +{ + return fontDb; +} diff --git a/src/plugins/platforms/vnc/qvncintegration.h b/src/plugins/platforms/vnc/qvncintegration.h index 241993d..dfc0e6b 100644 --- a/src/plugins/platforms/vnc/qvncintegration.h +++ b/src/plugins/platforms/vnc/qvncintegration.h @@ -45,6 +45,7 @@ #include "qvnccursor.h" #include "../fb_base/fb_base.h" #include <QPlatformIntegration> +#include "qgenericunixfontdatabase.h" QT_BEGIN_NAMESPACE @@ -91,10 +92,13 @@ public: bool isVirtualDesktop() { return virtualDesktop; } void moveToScreen(QWidget *window, int screen); + QPlatformFontDatabase *fontDatabase() const; + private: QVNCScreen *mPrimaryScreen; QList<QPlatformScreen *> mScreens; bool virtualDesktop; + QPlatformFontDatabase *fontDb; }; diff --git a/src/plugins/platforms/vnc/vnc.pro b/src/plugins/platforms/vnc/vnc.pro index 65824a2..6c448f5 100644 --- a/src/plugins/platforms/vnc/vnc.pro +++ b/src/plugins/platforms/vnc/vnc.pro @@ -13,6 +13,7 @@ HEADERS += qvnccursor.h SOURCES += qvnccursor.cpp include(../fb_base/fb_base.pri) +include(../fontdatabases/genericunix/genericunix.pri) target.path += $$[QT_INSTALL_PLUGINS]/platforms |