summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/gui/text
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qabstractfontengine_p.h110
-rw-r--r--src/gui/text/qabstractfontengine_qws.cpp776
-rw-r--r--src/gui/text/qabstractfontengine_qws.h221
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.cpp623
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.h150
-rw-r--r--src/gui/text/qabstracttextdocumentlayout_p.h100
-rw-r--r--src/gui/text/qcssparser.cpp2768
-rw-r--r--src/gui/text/qcssparser_p.h847
-rw-r--r--src/gui/text/qcssscanner.cpp1146
-rw-r--r--src/gui/text/qfont.cpp3188
-rw-r--r--src/gui/text/qfont.h378
-rw-r--r--src/gui/text/qfont_mac.cpp165
-rw-r--r--src/gui/text/qfont_p.h290
-rw-r--r--src/gui/text/qfont_qpa.cpp114
-rw-r--r--src/gui/text/qfont_qws.cpp135
-rw-r--r--src/gui/text/qfont_s60.cpp136
-rw-r--r--src/gui/text/qfont_win.cpp166
-rw-r--r--src/gui/text/qfont_x11.cpp368
-rw-r--r--src/gui/text/qfontdatabase.cpp2715
-rw-r--r--src/gui/text/qfontdatabase.h180
-rw-r--r--src/gui/text/qfontdatabase_mac.cpp466
-rw-r--r--src/gui/text/qfontdatabase_qpa.cpp394
-rw-r--r--src/gui/text/qfontdatabase_qws.cpp975
-rw-r--r--src/gui/text/qfontdatabase_s60.cpp1091
-rw-r--r--src/gui/text/qfontdatabase_win.cpp1348
-rw-r--r--src/gui/text/qfontdatabase_x11.cpp2146
-rw-r--r--src/gui/text/qfontengine.cpp1684
-rw-r--r--src/gui/text/qfontengine_coretext.mm843
-rw-r--r--src/gui/text/qfontengine_coretext_p.h141
-rw-r--r--src/gui/text/qfontengine_ft.cpp2074
-rw-r--r--src/gui/text/qfontengine_ft_p.h380
-rw-r--r--src/gui/text/qfontengine_mac.mm1236
-rw-r--r--src/gui/text/qfontengine_mac_p.h165
-rw-r--r--src/gui/text/qfontengine_p.h452
-rw-r--r--src/gui/text/qfontengine_qpa.cpp691
-rw-r--r--src/gui/text/qfontengine_qpa_p.h262
-rw-r--r--src/gui/text/qfontengine_qpf.cpp1220
-rw-r--r--src/gui/text/qfontengine_qpf_p.h299
-rw-r--r--src/gui/text/qfontengine_qws.cpp665
-rw-r--r--src/gui/text/qfontengine_s60.cpp569
-rw-r--r--src/gui/text/qfontengine_s60_p.h167
-rw-r--r--src/gui/text/qfontengine_win.cpp1322
-rw-r--r--src/gui/text/qfontengine_win_p.h161
-rw-r--r--src/gui/text/qfontengine_x11.cpp1201
-rw-r--r--src/gui/text/qfontengine_x11_p.h178
-rw-r--r--src/gui/text/qfontenginedirectwrite.cpp635
-rw-r--r--src/gui/text/qfontenginedirectwrite_p.h130
-rw-r--r--src/gui/text/qfontengineglyphcache_p.h98
-rw-r--r--src/gui/text/qfontinfo.h88
-rw-r--r--src/gui/text/qfontmetrics.cpp1819
-rw-r--r--src/gui/text/qfontmetrics.h208
-rw-r--r--src/gui/text/qfontsubset.cpp1743
-rw-r--r--src/gui/text/qfontsubset_p.h99
-rw-r--r--src/gui/text/qfragmentmap.cpp46
-rw-r--r--src/gui/text/qfragmentmap_p.h888
-rw-r--r--src/gui/text/qglyphs.cpp323
-rw-r--r--src/gui/text/qglyphs.h107
-rw-r--r--src/gui/text/qglyphs_p.h103
-rw-r--r--src/gui/text/qpfutil.cpp66
-rw-r--r--src/gui/text/qplatformfontdatabase_qpa.cpp291
-rw-r--r--src/gui/text/qplatformfontdatabase_qpa.h108
-rw-r--r--src/gui/text/qrawfont.cpp612
-rw-r--r--src/gui/text/qrawfont.h140
-rw-r--r--src/gui/text/qrawfont_ft.cpp189
-rw-r--r--src/gui/text/qrawfont_mac.cpp105
-rw-r--r--src/gui/text/qrawfont_p.h132
-rw-r--r--src/gui/text/qrawfont_win.cpp750
-rw-r--r--src/gui/text/qstatictext.cpp733
-rw-r--r--src/gui/text/qstatictext.h109
-rw-r--r--src/gui/text/qstatictext_p.h203
-rw-r--r--src/gui/text/qsyntaxhighlighter.cpp665
-rw-r--r--src/gui/text/qsyntaxhighlighter.h112
-rw-r--r--src/gui/text/qtextcontrol.cpp3148
-rw-r--r--src/gui/text/qtextcontrol_p.h312
-rw-r--r--src/gui/text/qtextcontrol_p_p.h238
-rw-r--r--src/gui/text/qtextcursor.cpp2561
-rw-r--r--src/gui/text/qtextcursor.h240
-rw-r--r--src/gui/text/qtextcursor_p.h122
-rw-r--r--src/gui/text/qtextdocument.cpp3044
-rw-r--r--src/gui/text/qtextdocument.h309
-rw-r--r--src/gui/text/qtextdocument_p.cpp1724
-rw-r--r--src/gui/text/qtextdocument_p.h408
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp1224
-rw-r--r--src/gui/text/qtextdocumentfragment.h92
-rw-r--r--src/gui/text/qtextdocumentfragment_p.h236
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp3263
-rw-r--r--src/gui/text/qtextdocumentlayout_p.h119
-rw-r--r--src/gui/text/qtextdocumentwriter.cpp372
-rw-r--r--src/gui/text/qtextdocumentwriter.h93
-rw-r--r--src/gui/text/qtextengine.cpp2845
-rw-r--r--src/gui/text/qtextengine_mac.cpp656
-rw-r--r--src/gui/text/qtextengine_p.h643
-rw-r--r--src/gui/text/qtextformat.cpp3297
-rw-r--r--src/gui/text/qtextformat.h976
-rw-r--r--src/gui/text/qtextformat_p.h111
-rw-r--r--src/gui/text/qtexthtmlparser.cpp1905
-rw-r--r--src/gui/text/qtexthtmlparser_p.h344
-rw-r--r--src/gui/text/qtextimagehandler.cpp232
-rw-r--r--src/gui/text/qtextimagehandler_p.h80
-rw-r--r--src/gui/text/qtextlayout.cpp2929
-rw-r--r--src/gui/text/qtextlayout.h259
-rw-r--r--src/gui/text/qtextlist.cpp321
-rw-r--r--src/gui/text/qtextlist.h94
-rw-r--r--src/gui/text/qtextobject.cpp1785
-rw-r--r--src/gui/text/qtextobject.h335
-rw-r--r--src/gui/text/qtextobject_p.h114
-rw-r--r--src/gui/text/qtextodfwriter.cpp837
-rw-r--r--src/gui/text/qtextodfwriter_p.h115
-rw-r--r--src/gui/text/qtextoption.cpp434
-rw-r--r--src/gui/text/qtextoption.h163
-rw-r--r--src/gui/text/qtexttable.cpp1323
-rw-r--r--src/gui/text/qtexttable.h145
-rw-r--r--src/gui/text/qtexttable_p.h89
-rw-r--r--src/gui/text/qzip.cpp1263
-rw-r--r--src/gui/text/qzipreader_p.h124
-rw-r--r--src/gui/text/qzipwriter_p.h116
-rw-r--r--src/gui/text/text.pri245
117 files changed, 84493 insertions, 0 deletions
diff --git a/src/gui/text/qabstractfontengine_p.h b/src/gui/text/qabstractfontengine_p.h
new file mode 100644
index 0000000000..7a430b93bd
--- /dev/null
+++ b/src/gui/text/qabstractfontengine_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QABSTRACTFONTENGINE_P_H
+#define QABSTRACTFONTENGINE_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 "qfontengine_p.h"
+#include "qabstractfontengine_qws.h"
+
+QT_BEGIN_NAMESPACE
+
+class QCustomFontEngine;
+
+class QProxyFontEngine : public QFontEngine
+{
+ Q_OBJECT
+public:
+ QProxyFontEngine(QAbstractFontEngine *engine, const QFontDef &def);
+ virtual ~QProxyFontEngine();
+
+ virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const;
+ virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const;
+ virtual QImage alphaMapForGlyph(glyph_t);
+ virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags);
+ virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs);
+ virtual glyph_metrics_t boundingBox(glyph_t glyph);
+
+ virtual QFixed ascent() const;
+ virtual QFixed descent() const;
+ virtual QFixed leading() const;
+ virtual QFixed xHeight() const;
+ virtual QFixed averageCharWidth() const;
+ virtual QFixed lineThickness() const;
+ virtual QFixed underlinePosition() const;
+ virtual qreal maxCharWidth() const;
+ virtual qreal minLeftBearing() const;
+ virtual qreal minRightBearing() const;
+ virtual int glyphCount() const;
+
+ virtual bool canRender(const QChar *string, int len);
+
+ virtual Type type() const { return Proxy; }
+ virtual const char *name() const { return "proxy engine"; }
+
+#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_OS_SYMBIAN)
+ virtual void draw(QPaintEngine *, qreal, qreal, const QTextItemInt &);
+#endif
+
+ inline QAbstractFontEngine::Capabilities capabilities() const
+ { return engineCapabilities; }
+
+ bool drawAsOutline() const;
+
+private:
+ QAbstractFontEngine *engine;
+ QAbstractFontEngine::Capabilities engineCapabilities;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/text/qabstractfontengine_qws.cpp b/src/gui/text/qabstractfontengine_qws.cpp
new file mode 100644
index 0000000000..7cb868f655
--- /dev/null
+++ b/src/gui/text/qabstractfontengine_qws.cpp
@@ -0,0 +1,776 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qabstractfontengine_qws.h"
+#include "qabstractfontengine_p.h"
+
+#include <private/qtextengine_p.h>
+#include <private/qpaintengine_raster_p.h>
+
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFontEngineInfoPrivate
+{
+public:
+ inline QFontEngineInfoPrivate()
+ : pixelSize(0), weight(QFont::Normal), style(QFont::StyleNormal)
+ {}
+
+ QString family;
+ qreal pixelSize;
+ int weight;
+ QFont::Style style;
+ QList<QFontDatabase::WritingSystem> writingSystems;
+};
+
+/*!
+ \class QFontEngineInfo
+ \preliminary
+ \brief The QFontEngineInfo class describes a specific font provided by a font engine plugin.
+ \since 4.3
+ \ingroup qws
+
+ \tableofcontents
+
+ QFontEngineInfo is used to describe a request of a font to a font engine plugin as well as to
+ describe the actual fonts a plugin provides.
+
+ \sa QAbstractFontEngine, QFontEnginePlugin
+*/
+
+/*!
+ Constructs a new empty QFontEngineInfo.
+*/
+QFontEngineInfo::QFontEngineInfo()
+{
+ d = new QFontEngineInfoPrivate;
+}
+
+/*!
+ Constructs a new QFontEngineInfo with the specified \a family.
+ The resulting object represents a freely scalable font with normal
+ weight and style.
+*/
+QFontEngineInfo::QFontEngineInfo(const QString &family)
+{
+ d = new QFontEngineInfoPrivate;
+ d->family = family;
+}
+
+/*!
+ Creates a new font engine info object with the same attributes as \a other.
+*/
+QFontEngineInfo::QFontEngineInfo(const QFontEngineInfo &other)
+ : d(new QFontEngineInfoPrivate(*other.d))
+{
+}
+
+/*!
+ Assigns \a other to this font engine info object, and returns a reference
+ to this.
+*/
+QFontEngineInfo &QFontEngineInfo::operator=(const QFontEngineInfo &other)
+{
+ *d = *other.d;
+ return *this;
+}
+
+/*!
+ Destroys this QFontEngineInfo object.
+*/
+QFontEngineInfo::~QFontEngineInfo()
+{
+ delete d;
+}
+
+/*!
+ \property QFontEngineInfo::family
+ the family name of the font
+*/
+
+void QFontEngineInfo::setFamily(const QString &family)
+{
+ d->family = family;
+}
+
+QString QFontEngineInfo::family() const
+{
+ return d->family;
+}
+
+/*!
+ \property QFontEngineInfo::pixelSize
+ the pixel size of the font
+
+ A pixel size of 0 represents a freely scalable font.
+*/
+
+void QFontEngineInfo::setPixelSize(qreal size)
+{
+ d->pixelSize = size;
+}
+
+qreal QFontEngineInfo::pixelSize() const
+{
+ return d->pixelSize;
+}
+
+/*!
+ \property QFontEngineInfo::weight
+ the weight of the font
+
+ The value should be from the \l{QFont::Weight} enumeration.
+*/
+
+void QFontEngineInfo::setWeight(int weight)
+{
+ d->weight = weight;
+}
+
+int QFontEngineInfo::weight() const
+{
+ return d->weight;
+}
+
+/*!
+ \property QFontEngineInfo::style
+ the style of the font
+*/
+
+void QFontEngineInfo::setStyle(QFont::Style style)
+{
+ d->style = style;
+}
+
+QFont::Style QFontEngineInfo::style() const
+{
+ return d->style;
+}
+
+/*!
+ \property QFontEngineInfo::writingSystems
+ the writing systems supported by the font
+
+ An empty list means that any writing system is supported.
+*/
+
+QList<QFontDatabase::WritingSystem> QFontEngineInfo::writingSystems() const
+{
+ return d->writingSystems;
+}
+
+void QFontEngineInfo::setWritingSystems(const QList<QFontDatabase::WritingSystem> &writingSystems)
+{
+ d->writingSystems = writingSystems;
+}
+
+class QFontEnginePluginPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QFontEnginePlugin)
+
+ QString foundry;
+};
+
+/*!
+ \class QFontEnginePlugin
+ \preliminary
+ \brief The QFontEnginePlugin class is the base class for font engine factory plugins in Qt for Embedded Linux.
+ \since 4.3
+ \ingroup qws
+ \ingroup plugins
+
+ \tableofcontents
+
+ QFontEnginePlugin is provided by font engine plugins to create
+ instances of subclasses of QAbstractFontEngine.
+
+ The member functions create() and availableFontEngines() must be
+ implemented.
+
+ \sa QAbstractFontEngine, QFontEngineInfo
+*/
+
+/*!
+ Creates a font engine plugin that creates font engines with the
+ specified \a foundry and \a parent.
+*/
+QFontEnginePlugin::QFontEnginePlugin(const QString &foundry, QObject *parent)
+ : QObject(*new QFontEnginePluginPrivate, parent)
+{
+ Q_D(QFontEnginePlugin);
+ d->foundry = foundry;
+}
+
+/*!
+ Destroys this font engine plugin.
+*/
+QFontEnginePlugin::~QFontEnginePlugin()
+{
+}
+
+/*!
+ Returns a list of foundries the font engine plugin provides.
+ The default implementation returns the foundry specified with the constructor.
+*/
+QStringList QFontEnginePlugin::keys() const
+{
+ Q_D(const QFontEnginePlugin);
+ return QStringList(d->foundry);
+}
+
+/*!
+ \fn QAbstractFontEngine *QFontEnginePlugin::create(const QFontEngineInfo &info)
+
+ Implemented in subclasses to create a new font engine that provides a font that
+ matches \a info.
+*/
+
+/*!
+ \fn QList<QFontEngineInfo> QFontEnginePlugin::availableFontEngines() const
+
+ Implemented in subclasses to return a list of QFontEngineInfo objects that represents all font
+ engines the plugin can create.
+*/
+
+class QAbstractFontEnginePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractFontEngine)
+public:
+};
+
+//The <classname> class is|provides|contains|specifies...
+/*!
+ \class QAbstractFontEngine
+ \preliminary
+ \brief The QAbstractFontEngine class is the base class for font engine plugins in Qt for Embedded Linux.
+ \since 4.3
+ \ingroup qws
+
+ \tableofcontents
+
+ QAbstractFontEngine is implemented by font engine plugins through QFontEnginePlugin.
+
+ \sa QFontEnginePlugin, QFontEngineInfo
+*/
+
+/*!
+ \enum QAbstractFontEngine::Capability
+
+ This enum describes the capabilities of a font engine.
+
+ \value CanRenderGlyphs_Gray The font engine can render individual glyphs into 8 bpp images.
+ \value CanRenderGlyphs_Mono The font engine can render individual glyphs into 1 bpp images.
+ \value CanRenderGlyphs The font engine can render individual glyphs into images.
+ \value CanOutlineGlyphs The font engine can convert glyphs to painter paths.
+*/
+
+/*!
+ \enum QAbstractFontEngine::FontProperty
+
+ This enum describes the properties of a font provided by a font engine.
+
+ \value Ascent The ascent of the font, specified as a 26.6 fixed point value.
+ \value Descent The descent of the font, specified as a 26.6 fixed point value.
+ \value Leading The leading of the font, specified as a 26.6 fixed point value.
+ \value XHeight The 'x' height of the font, specified as a 26.6 fixed point value.
+ \value AverageCharWidth The average character width of the font, specified as a 26.6 fixed point value.
+ \value LineThickness The thickness of the underline and strikeout lines for the font, specified as a 26.6 fixed point value.
+ \value UnderlinePosition The distance from the base line to the underline position for the font, specified as a 26.6 fixed point value.
+ \value MaxCharWidth The width of the widest character in the font, specified as a 26.6 fixed point value.
+ \value MinLeftBearing The minimum left bearing of the font, specified as a 26.6 fixed point value.
+ \value MinRightBearing The maximum right bearing of the font, specified as a 26.6 fixed point value.
+ \value GlyphCount The number of glyphs in the font, specified as an integer value.
+ \value CacheGlyphsHint A boolean value specifying whether rendered glyphs should be cached by Qt.
+ \value OutlineGlyphsHint A boolean value specifying whether the font engine prefers outline drawing over image rendering for uncached glyphs.
+*/
+
+/*!
+ \enum QAbstractFontEngine::TextShapingFlag
+
+ This enum describes flags controlling conversion of characters to glyphs and their metrics.
+
+ \value RightToLeft The text is used in a right-to-left context.
+ \value ReturnDesignMetrics Return font design metrics instead of pixel metrics.
+*/
+
+/*!
+ \typedef QAbstractFontEngine::Fixed
+
+ This type is \c int, interpreted as a 26.6 fixed point value.
+*/
+
+/*!
+ \class QAbstractFontEngine::GlyphMetrics
+ \brief QAbstractFontEngine::GlyphMetrics defines the metrics of a single glyph.
+ \preliminary
+ \since 4.3
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::x
+
+ The horizontal offset from the origin.
+*/
+
+/*!
+ \fn QAbstractFontEngine::GlyphMetrics::GlyphMetrics()
+
+ Constructs an empty glyph metrics object with all values
+ set to zero.
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::y
+
+ The vertical offset from the origin (baseline).
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::width
+
+ The width of the glyph.
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::height
+
+ The height of the glyph.
+*/
+
+/*!
+ \variable QAbstractFontEngine::GlyphMetrics::advance
+
+ The advance of the glyph.
+*/
+
+/*!
+ \class QAbstractFontEngine::FixedPoint
+ \brief QAbstractFontEngine::FixedPoint defines a point in the place using 26.6 fixed point precision.
+ \preliminary
+ \since 4.3
+*/
+
+/*!
+ \variable QAbstractFontEngine::FixedPoint::x
+
+ The x coordinate of this point.
+*/
+
+/*!
+ \variable QAbstractFontEngine::FixedPoint::y
+
+ The y coordinate of this point.
+*/
+
+/*!
+ Constructs a new QAbstractFontEngine with the given \a parent.
+*/
+QAbstractFontEngine::QAbstractFontEngine(QObject *parent)
+ : QObject(*new QAbstractFontEnginePrivate, parent)
+{
+}
+
+/*!
+ Destroys this QAbstractFontEngine object.
+*/
+QAbstractFontEngine::~QAbstractFontEngine()
+{
+}
+
+/*!
+ \fn QAbstractFontEngine::Capabilities QAbstractFontEngine::capabilities() const
+
+ Implemented in subclasses to specify the font engine's capabilities. The return value
+ may be cached by the caller and is expected not to change during the lifetime of the
+ font engine.
+*/
+
+/*!
+ \fn QVariant QAbstractFontEngine::fontProperty(FontProperty property) const
+
+ Implemented in subclasses to return the value of the font attribute \a property. The return
+ value may be cached by the caller and is expected not to change during the lifetime of the font
+ engine.
+*/
+
+/*!
+ \fn bool QAbstractFontEngine::convertStringToGlyphIndices(const QChar *string, int length, uint *glyphs, int *numGlyphs, TextShapingFlags flags) const
+
+ Implemented in subclasses to convert the characters specified by \a string and \a length to
+ glyph indicies, using \a flags. The glyph indicies should be returned in the \a glyphs array
+ provided by the caller. The maximum size of \a glyphs is specified by the value pointed to by \a
+ numGlyphs. If successful, the subclass implementation sets the value pointed to by \a numGlyphs
+ to the actual number of glyph indices generated, and returns true. Otherwise, e.g. if there is
+ not enough space in the provided \a glyphs array, it should set \a numGlyphs to the number of
+ glyphs needed for the conversion and return false.
+*/
+
+/*!
+ \fn void QAbstractFontEngine::getGlyphAdvances(const uint *glyphs, int numGlyphs, Fixed *advances, TextShapingFlags flags) const
+
+ Implemented in subclasses to retrieve the advances of the array specified by \a glyphs and \a
+ numGlyphs, using \a flags. The result is returned in \a advances, which is allocated by the
+ caller and contains \a numGlyphs elements.
+*/
+
+/*!
+ \fn QAbstractFontEngine::GlyphMetrics QAbstractFontEngine::glyphMetrics(uint glyph) const
+
+ Implemented in subclass to return the metrics for \a glyph.
+*/
+
+/*!
+ Implemented in subclasses to render the specified \a glyph into a \a buffer with the given \a depth ,
+ \a bytesPerLine and \a height.
+
+ Returns true if rendering succeeded, false otherwise.
+*/
+bool QAbstractFontEngine::renderGlyph(uint glyph, int depth, int bytesPerLine, int height, uchar *buffer)
+{
+ Q_UNUSED(glyph)
+ Q_UNUSED(depth)
+ Q_UNUSED(bytesPerLine)
+ Q_UNUSED(height)
+ Q_UNUSED(buffer)
+ qWarning("QAbstractFontEngine: renderGlyph is not implemented in font plugin!");
+ return false;
+}
+
+/*!
+ Implemented in subclasses to add the outline of the glyphs specified by \a glyphs and \a
+ numGlyphs at the specified \a positions to the painter path \a path.
+*/
+void QAbstractFontEngine::addGlyphOutlinesToPath(uint *glyphs, int numGlyphs, FixedPoint *positions, QPainterPath *path)
+{
+ Q_UNUSED(glyphs)
+ Q_UNUSED(numGlyphs)
+ Q_UNUSED(positions)
+ Q_UNUSED(path)
+ qWarning("QAbstractFontEngine: addGlyphOutlinesToPath is not implemented in font plugin!");
+}
+
+/*
+bool QAbstractFontEngine::supportsExtension(Extension extension) const
+{
+ Q_UNUSED(extension)
+ return false;
+}
+
+QVariant QAbstractFontEngine::extension(Extension extension, const QVariant &argument)
+{
+ Q_UNUSED(argument)
+ Q_UNUSED(extension)
+ return QVariant();
+}
+*/
+
+QProxyFontEngine::QProxyFontEngine(QAbstractFontEngine *customEngine, const QFontDef &def)
+ : engine(customEngine)
+{
+ fontDef = def;
+ engineCapabilities = engine->capabilities();
+}
+
+QProxyFontEngine::~QProxyFontEngine()
+{
+ delete engine;
+}
+
+bool QProxyFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
+{
+ if (*nglyphs < len) {
+ *nglyphs = len;
+ return false;
+ }
+
+ QVarLengthArray<uint> glyphIndicies(*nglyphs);
+ if (!engine->convertStringToGlyphIndices(str, len, glyphIndicies.data(), nglyphs, QAbstractFontEngine::TextShapingFlags(int(flags))))
+ return false;
+
+ // ### use memcopy instead
+ for (int i = 0; i < *nglyphs; ++i) {
+ glyphs->glyphs[i] = glyphIndicies[i];
+ }
+ glyphs->numGlyphs = *nglyphs;
+
+ recalcAdvances(glyphs, flags);
+ return true;
+}
+
+void QProxyFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
+{
+ const int nglyphs = glyphs->numGlyphs;
+
+ QVarLengthArray<QAbstractFontEngine::Fixed> advances(nglyphs);
+ engine->getGlyphAdvances(glyphs->glyphs, nglyphs, advances.data(), QAbstractFontEngine::TextShapingFlags(int(flags)));
+
+
+ // ### use memcopy instead
+ for (int i = 0; i < nglyphs; ++i) {
+ glyphs->advances_x[i] = QFixed::fromFixed(advances[i]);
+ glyphs->advances_y[i] = 0;
+ }
+}
+
+
+static QImage alphaMapFromPath(QFontEngine *fe, glyph_t glyph)
+{
+ glyph_metrics_t gm = fe->boundingBox(glyph);
+ int glyph_x = qFloor(gm.x.toReal());
+ int glyph_y = qFloor(gm.y.toReal());
+ int glyph_width = qCeil((gm.x + gm.width).toReal()) - glyph_x;
+ int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y;
+
+ if (glyph_width <= 0 || glyph_height <= 0)
+ return QImage();
+ QFixedPoint pt;
+ pt.x = 0;
+ pt.y = -glyph_y; // the baseline
+ QPainterPath path;
+ QImage im(glyph_width + qAbs(glyph_x) + 4, glyph_height, QImage::Format_ARGB32_Premultiplied);
+ im.fill(Qt::transparent);
+ QPainter p(&im);
+ p.setRenderHint(QPainter::Antialiasing);
+ fe->addGlyphsToPath(&glyph, &pt, 1, &path, 0);
+ p.setPen(Qt::NoPen);
+ p.setBrush(Qt::black);
+ p.drawPath(path);
+ p.end();
+
+ QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
+ QVector<QRgb> colors(256);
+ for (int i=0; i<256; ++i)
+ colors[i] = qRgba(0, 0, 0, i);
+ indexed.setColorTable(colors);
+
+ for (int y=0; y<im.height(); ++y) {
+ uchar *dst = (uchar *) indexed.scanLine(y);
+ uint *src = (uint *) im.scanLine(y);
+ for (int x=0; x<im.width(); ++x)
+ dst[x] = qAlpha(src[x]);
+ }
+
+ return indexed;
+}
+
+
+QImage QProxyFontEngine::alphaMapForGlyph(glyph_t glyph)
+{
+ if (!(engineCapabilities & QAbstractFontEngine::CanRenderGlyphs_Gray))
+ return alphaMapFromPath(this, glyph);
+
+ QAbstractFontEngine::GlyphMetrics metrics = engine->glyphMetrics(glyph);
+ if (metrics.width <= 0 || metrics.height <= 0)
+ return QImage();
+
+ QImage img(metrics.width >> 6, metrics.height >> 6, QImage::Format_Indexed8);
+
+ // ### we should have QImage::Format_GrayScale8
+ static QVector<QRgb> colorMap;
+ if (colorMap.isEmpty()) {
+ colorMap.resize(256);
+ for (int i=0; i<256; ++i)
+ colorMap[i] = qRgba(0, 0, 0, i);
+ }
+
+ img.setColorTable(colorMap);
+
+ engine->renderGlyph(glyph, /*depth*/8, img.bytesPerLine(), img.height(), img.bits());
+
+ return img;
+}
+
+void QProxyFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags)
+{
+ if (engineCapabilities & QAbstractFontEngine::CanOutlineGlyphs)
+ engine->addGlyphOutlinesToPath(glyphs, nglyphs, reinterpret_cast<QAbstractFontEngine::FixedPoint *>(positions), path);
+ else
+ QFontEngine::addGlyphsToPath(glyphs, positions, nglyphs, path, flags);
+}
+
+glyph_metrics_t QProxyFontEngine::boundingBox(const QGlyphLayout &glyphs)
+{
+ if (glyphs.numGlyphs == 0)
+ return glyph_metrics_t();
+
+ QFixed w = 0;
+ for (int i = 0; i < glyphs.numGlyphs; ++i)
+ w += glyphs.effectiveAdvance(i);
+
+ return glyph_metrics_t(0, -ascent(), w, ascent() + descent(), w, 0);
+}
+
+glyph_metrics_t QProxyFontEngine::boundingBox(glyph_t glyph)
+{
+ glyph_metrics_t m;
+
+ QAbstractFontEngine::GlyphMetrics metrics = engine->glyphMetrics(glyph);
+ m.x = QFixed::fromFixed(metrics.x);
+ m.y = QFixed::fromFixed(metrics.y);
+ m.width = QFixed::fromFixed(metrics.width);
+ m.height = QFixed::fromFixed(metrics.height);
+ m.xoff = QFixed::fromFixed(metrics.advance);
+
+ return m;
+}
+
+QFixed QProxyFontEngine::ascent() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::Ascent).toInt());
+}
+
+QFixed QProxyFontEngine::descent() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::Descent).toInt());
+}
+
+QFixed QProxyFontEngine::leading() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::Leading).toInt());
+}
+
+QFixed QProxyFontEngine::xHeight() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::XHeight).toInt());
+}
+
+QFixed QProxyFontEngine::averageCharWidth() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::AverageCharWidth).toInt());
+}
+
+QFixed QProxyFontEngine::lineThickness() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::LineThickness).toInt());
+}
+
+QFixed QProxyFontEngine::underlinePosition() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::UnderlinePosition).toInt());
+}
+
+qreal QProxyFontEngine::maxCharWidth() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::MaxCharWidth).toInt()).toReal();
+}
+
+qreal QProxyFontEngine::minLeftBearing() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::MinLeftBearing).toInt()).toReal();
+}
+
+qreal QProxyFontEngine::minRightBearing() const
+{
+ return QFixed::fromFixed(engine->fontProperty(QAbstractFontEngine::MinRightBearing).toInt()).toReal();
+}
+
+int QProxyFontEngine::glyphCount() const
+{
+ return engine->fontProperty(QAbstractFontEngine::GlyphCount).toInt();
+}
+
+bool QProxyFontEngine::canRender(const QChar *string, int len)
+{
+ QVarLengthArray<uint> glyphs(len);
+ int numGlyphs = len;
+
+ if (!engine->convertStringToGlyphIndices(string, len, glyphs.data(), &numGlyphs, /*flags*/0))
+ return false;
+
+ for (int i = 0; i < numGlyphs; ++i)
+ if (!glyphs[i])
+ return false;
+
+ return true;
+}
+
+void QProxyFontEngine::draw(QPaintEngine *p, qreal _x, qreal _y, const QTextItemInt &si)
+{
+ QPaintEngineState *pState = p->state;
+ QRasterPaintEngine *paintEngine = static_cast<QRasterPaintEngine*>(p);
+
+ QTransform matrix = pState->transform();
+ matrix.translate(_x, _y);
+ QFixed x = QFixed::fromReal(matrix.dx());
+ QFixed y = QFixed::fromReal(matrix.dy());
+
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> glyphs;
+ getGlyphPositions(si.glyphs, matrix, si.flags, glyphs, positions);
+ if (glyphs.size() == 0)
+ return;
+
+ for(int i = 0; i < glyphs.size(); i++) {
+ QImage glyph = alphaMapForGlyph(glyphs[i]);
+ if (glyph.isNull())
+ continue;
+
+ if (glyph.format() != QImage::Format_Indexed8
+ && glyph.format() != QImage::Format_Mono)
+ continue;
+
+ QAbstractFontEngine::GlyphMetrics metrics = engine->glyphMetrics(glyphs[i]);
+
+ int depth = glyph.format() == QImage::Format_Mono ? 1 : 8;
+ paintEngine->alphaPenBlt(glyph.bits(), glyph.bytesPerLine(), depth,
+ qRound(positions[i].x + QFixed::fromFixed(metrics.x)),
+ qRound(positions[i].y + QFixed::fromFixed(metrics.y)),
+ glyph.width(), glyph.height());
+ }
+}
+
+/*
+ * This is only called when we use the proxy fontengine directly (without sharing the rendered
+ * glyphs). So we prefer outline rendering over rendering of unshared glyphs. That decision is
+ * done in qfontdatabase_qws.cpp by looking at the ShareGlyphsHint and the pixel size of the font.
+ */
+bool QProxyFontEngine::drawAsOutline() const
+{
+ if (!(engineCapabilities & QAbstractFontEngine::CanOutlineGlyphs))
+ return false;
+
+ QVariant outlineHint = engine->fontProperty(QAbstractFontEngine::OutlineGlyphsHint);
+ return !outlineHint.isValid() || outlineHint.toBool();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qabstractfontengine_qws.h b/src/gui/text/qabstractfontengine_qws.h
new file mode 100644
index 0000000000..dfc15dcf5d
--- /dev/null
+++ b/src/gui/text/qabstractfontengine_qws.h
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QABSTRACTFONTENGINE_QWS_H
+#define QABSTRACTFONTENGINE_QWS_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qfactoryinterface.h>
+#include <QtGui/qpaintengine.h>
+#include <QtGui/qfontdatabase.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QFontEngineInfoPrivate;
+
+class Q_GUI_EXPORT QFontEngineInfo
+{
+public:
+ QDOC_PROPERTY(QString family READ family WRITE setFamily)
+ QDOC_PROPERTY(qreal pixelSize READ pixelSize WRITE setPixelSize)
+ QDOC_PROPERTY(int weight READ weight WRITE setWeight)
+ QDOC_PROPERTY(QFont::Style style READ style WRITE setStyle)
+ QDOC_PROPERTY(QList<QFontDatabase::WritingSystem> writingSystems READ writingSystems WRITE setWritingSystems)
+
+ QFontEngineInfo();
+ explicit QFontEngineInfo(const QString &family);
+ QFontEngineInfo(const QFontEngineInfo &other);
+ QFontEngineInfo &operator=(const QFontEngineInfo &other);
+ ~QFontEngineInfo();
+
+ void setFamily(const QString &name);
+ QString family() const;
+
+ void setPixelSize(qreal size);
+ qreal pixelSize() const;
+
+ void setWeight(int weight);
+ int weight() const;
+
+ void setStyle(QFont::Style style);
+ QFont::Style style() const;
+
+ QList<QFontDatabase::WritingSystem> writingSystems() const;
+ void setWritingSystems(const QList<QFontDatabase::WritingSystem> &writingSystems);
+
+private:
+ QFontEngineInfoPrivate *d;
+};
+
+class QAbstractFontEngine;
+
+struct Q_GUI_EXPORT QFontEngineFactoryInterface : public QFactoryInterface
+{
+ virtual QAbstractFontEngine *create(const QFontEngineInfo &info) = 0;
+ virtual QList<QFontEngineInfo> availableFontEngines() const = 0;
+};
+
+#define QFontEngineFactoryInterface_iid "com.trolltech.Qt.QFontEngineFactoryInterface"
+Q_DECLARE_INTERFACE(QFontEngineFactoryInterface, QFontEngineFactoryInterface_iid)
+
+class QFontEnginePluginPrivate;
+
+class Q_GUI_EXPORT QFontEnginePlugin : public QObject, public QFontEngineFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QFontEngineFactoryInterface:QFactoryInterface)
+public:
+ QFontEnginePlugin(const QString &foundry, QObject *parent = 0);
+ ~QFontEnginePlugin();
+
+ virtual QStringList keys() const;
+
+ virtual QAbstractFontEngine *create(const QFontEngineInfo &info) = 0;
+ virtual QList<QFontEngineInfo> availableFontEngines() const = 0;
+
+private:
+ Q_DECLARE_PRIVATE(QFontEnginePlugin)
+ Q_DISABLE_COPY(QFontEnginePlugin)
+};
+
+class QAbstractFontEnginePrivate;
+
+class Q_GUI_EXPORT QAbstractFontEngine : public QObject
+{
+ Q_OBJECT
+public:
+ enum Capability {
+ CanOutlineGlyphs = 1,
+ CanRenderGlyphs_Mono = 2,
+ CanRenderGlyphs_Gray = 4,
+ CanRenderGlyphs = CanRenderGlyphs_Mono | CanRenderGlyphs_Gray
+ };
+ Q_DECLARE_FLAGS(Capabilities, Capability)
+
+ explicit QAbstractFontEngine(QObject *parent = 0);
+ ~QAbstractFontEngine();
+
+ typedef int Fixed; // 26.6
+
+ struct FixedPoint
+ {
+ Fixed x;
+ Fixed y;
+ };
+
+ struct GlyphMetrics
+ {
+ inline GlyphMetrics()
+ : x(0), y(0), width(0), height(0),
+ advance(0) {}
+ Fixed x;
+ Fixed y;
+ Fixed width;
+ Fixed height;
+ Fixed advance;
+ };
+
+ enum FontProperty {
+ Ascent,
+ Descent,
+ Leading,
+ XHeight,
+ AverageCharWidth,
+ LineThickness,
+ UnderlinePosition,
+ MaxCharWidth,
+ MinLeftBearing,
+ MinRightBearing,
+ GlyphCount,
+
+ // hints
+ CacheGlyphsHint,
+ OutlineGlyphsHint
+ };
+
+ // keep in sync with QTextEngine::ShaperFlag!!
+ enum TextShapingFlag {
+ RightToLeft = 0x0001,
+ ReturnDesignMetrics = 0x0002
+ };
+ Q_DECLARE_FLAGS(TextShapingFlags, TextShapingFlag)
+
+ virtual Capabilities capabilities() const = 0;
+ virtual QVariant fontProperty(FontProperty property) const = 0;
+
+ virtual bool convertStringToGlyphIndices(const QChar *string, int length, uint *glyphs, int *numGlyphs, TextShapingFlags flags) const = 0;
+
+ virtual void getGlyphAdvances(const uint *glyphs, int numGlyphs, Fixed *advances, TextShapingFlags flags) const = 0;
+
+ virtual GlyphMetrics glyphMetrics(uint glyph) const = 0;
+
+ virtual bool renderGlyph(uint glyph, int depth, int bytesPerLine, int height, uchar *buffer);
+
+ virtual void addGlyphOutlinesToPath(uint *glyphs, int numGlyphs, FixedPoint *positions, QPainterPath *path);
+
+ /*
+ enum Extension {
+ GetTrueTypeTable
+ };
+
+ virtual bool supportsExtension(Extension extension) const;
+ virtual QVariant extension(Extension extension, const QVariant &argument = QVariant());
+ */
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractFontEngine)
+ Q_DISABLE_COPY(QAbstractFontEngine)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractFontEngine::Capabilities)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractFontEngine::TextShapingFlags)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp
new file mode 100644
index 0000000000..53ffaa4c6d
--- /dev/null
+++ b/src/gui/text/qabstracttextdocumentlayout.cpp
@@ -0,0 +1,623 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 <qabstracttextdocumentlayout.h>
+#include <qtextformat.h>
+#include "qtextdocument_p.h"
+#include "qtextengine_p.h"
+
+#include "qabstracttextdocumentlayout_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractTextDocumentLayout
+ \reentrant
+
+ \brief The QAbstractTextDocumentLayout class is an abstract base
+ class used to implement custom layouts for QTextDocuments.
+
+ \ingroup richtext-processing
+
+ The standard layout provided by Qt can handle simple word processing
+ including inline images, lists and tables.
+
+ Some applications, e.g., a word processor or a DTP application might need
+ more features than the ones provided by Qt's layout engine, in which case
+ you can subclass QAbstractTextDocumentLayout to provide custom layout
+ behavior for your text documents.
+
+ An instance of the QAbstractTextDocumentLayout subclass can be installed
+ on a QTextDocument object with the
+ \l{QTextDocument::}{setDocumentLayout()} function.
+
+ You can insert custom objects into a QTextDocument; see the
+ QTextObjectInterface class description for details.
+
+ \sa QTextObjectInterface
+*/
+
+/*!
+ \class QTextObjectInterface
+ \brief The QTextObjectInterface class allows drawing of
+ custom text objects in \l{QTextDocument}s.
+ \since 4.5
+
+ A text object describes the structure of one or more elements in a
+ text document; for instance, images imported from HTML are
+ implemented using text objects. A text object knows how to lay out
+ and draw its elements when a document is being rendered.
+
+ Qt allows custom text objects to be inserted into a document by
+ registering a custom \l{QTextCharFormat::objectType()}{object
+ type} with QTextCharFormat. A QTextObjectInterface must also be
+ implemented for this type and be
+ \l{QAbstractTextDocumentLayout::registerHandler()}{registered}
+ with the QAbstractTextDocumentLayout of the document. When the
+ object type is encountered while rendering a QTextDocument, the
+ intrinsicSize() and drawObject() functions of the interface are
+ called.
+
+ The following list explains the required steps of inserting a
+ custom text object into a document:
+
+ \list
+ \o Choose an \a objectType. The \a objectType is an integer with a
+ value greater or equal to QTextFormat::UserObject.
+ \o Create a QTextCharFormat object and set the object type to the
+ chosen type using the setObjectType() function.
+ \o Implement the QTextObjectInterface class.
+ \o Call QAbstractTextDocumentLayout::registerHandler() with an instance of your
+ QTextObjectInterface subclass to register your object type.
+ \o Insert QChar::ObjectReplacementCharacter with the aforementioned
+ QTextCharFormat of the chosen object type into the document.
+ As mentioned, the functions of QTextObjectInterface
+ \l{QTextObjectInterface::}{intrinsicSize()} and
+ \l{QTextObjectInterface::}{drawObject()} will then be called with the
+ QTextFormat as parameter whenever the replacement character is
+ encountered.
+ \endlist
+
+ A class implementing a text object needs to inherit both QObject
+ and QTextObjectInterface. QObject must be the first class
+ inherited. For instance:
+
+ \snippet examples/richtext/textobject/svgtextobject.h 1
+
+ The data of a text object is usually stored in the QTextCharFormat
+ using QTextCharFormat::setProperty(), and then retrieved with
+ QTextCharFormat::property().
+
+ \warning Copy and Paste operations ignore custom text objects.
+
+ \sa {Text Object Example}, QTextCharFormat, QTextLayout
+*/
+
+/*!
+ \fn QTextObjectInterface::~QTextObjectInterface()
+
+ Destroys this QTextObjectInterface.
+*/
+
+/*!
+ \fn virtual QSizeF QTextObjectInterface::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0
+
+ The intrinsicSize() function returns the size of the text object
+ represented by \a format in the given document (\a doc) at the
+ given position (\a posInDocument).
+
+ The size calculated will be used for subsequent calls to
+ drawObject() for this \a format.
+
+ \sa drawObject()
+*/
+
+/*!
+ \fn virtual void QTextObjectInterface::drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0
+
+ Draws this text object using the specified \a painter.
+
+ The size of the rectangle, \a rect, to draw in is the size
+ previously calculated by intrinsicSize(). The rectangles position
+ is relative to the \a painter.
+
+ You also get the document (\a doc) and the position (\a
+ posInDocument) of the \a format in that document.
+
+ \sa intrinsicSize()
+*/
+
+/*!
+ \fn void QAbstractTextDocumentLayout::update(const QRectF &rect)
+
+ This signal is emitted when the rectangle \a rect has been updated.
+
+ Subclasses of QAbstractTextDocumentLayout should emit this signal when
+ the layout of the contents change in order to repaint.
+*/
+
+/*!
+ \fn void QAbstractTextDocumentLayout::updateBlock(const QTextBlock &block)
+ \since 4.4
+
+ This signal is emitted when the specified \a block has been updated.
+
+ Subclasses of QAbstractTextDocumentLayout should emit this signal when
+ the layout of \a block has changed in order to repaint.
+*/
+
+/*!
+ \fn void QAbstractTextDocumentLayout::documentSizeChanged(const QSizeF &newSize)
+
+ This signal is emitted when the size of the document layout changes to
+ \a newSize.
+
+ Subclasses of QAbstractTextDocumentLayout should emit this signal when the
+ document's entire layout size changes. This signal is useful for widgets
+ that display text documents since it enables them to update their scroll
+ bars correctly.
+
+ \sa documentSize()
+*/
+
+/*!
+ \fn void QAbstractTextDocumentLayout::pageCountChanged(int newPages)
+
+ This signal is emitted when the number of pages in the layout changes;
+ \a newPages is the updated page count.
+
+ Subclasses of QAbstractTextDocumentLayout should emit this signal when
+ the number of pages in the layout has changed. Changes to the page count
+ are caused by changes to the layout or the document content itself.
+
+ \sa pageCount()
+*/
+
+/*!
+ \fn int QAbstractTextDocumentLayout::pageCount() const
+
+ Returns the number of pages contained in the layout.
+
+ \sa pageCountChanged()
+*/
+
+/*!
+ \fn QSizeF QAbstractTextDocumentLayout::documentSize() const
+
+ Returns the total size of the document's layout.
+
+ This information can be used by display widgets to update their scroll bars
+ correctly.
+
+ \sa documentSizeChanged(), QTextDocument::pageSize
+*/
+
+/*!
+ \fn void QAbstractTextDocumentLayout::draw(QPainter *painter, const PaintContext &context)
+
+ Draws the layout with the given \a painter using the given \a context.
+*/
+
+/*!
+ \fn int QAbstractTextDocumentLayout::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
+
+ Returns the cursor postion for the given \a point with the specified
+ \a accuracy. Returns -1 if no valid cursor position was found.
+*/
+
+/*!
+ \fn void QAbstractTextDocumentLayout::documentChanged(int position, int charsRemoved, int charsAdded)
+
+ This function is called whenever the contents of the document change. A
+ change occurs when text is inserted, removed, or a combination of these
+ two. The change is specified by \a position, \a charsRemoved, and
+ \a charsAdded corresponding to the starting character position of the
+ change, the number of characters removed from the document, and the
+ number of characters added.
+
+ For example, when inserting the text "Hello" into an empty document,
+ \a charsRemoved would be 0 and \a charsAdded would be 5 (the length of
+ the string).
+
+ Replacing text is a combination of removing and inserting. For example, if
+ the text "Hello" gets replaced by "Hi", \a charsRemoved would be 5 and
+ \a charsAdded would be 2.
+
+ For subclasses of QAbstractTextDocumentLayout, this is the central function
+ where a large portion of the work to lay out and position document contents
+ is done.
+
+ For example, in a subclass that only arranges blocks of text, an
+ implementation of this function would have to do the following:
+
+ \list
+ \o Determine the list of changed \l{QTextBlock}(s) using the parameters
+ provided.
+ \o Each QTextBlock object's corresponding QTextLayout object needs to
+ be processed. You can access the \l{QTextBlock}'s layout using the
+ QTextBlock::layout() function. This processing should take the
+ document's page size into consideration.
+ \o If the total number of pages changed, the pageCountChanged() signal
+ should be emitted.
+ \o If the total size changed, the documentSizeChanged() signal should
+ be emitted.
+ \o The update() signal should be emitted to schedule a repaint of areas
+ in the layout that require repainting.
+ \endlist
+
+ \sa QTextLayout
+*/
+
+/*!
+ \class QAbstractTextDocumentLayout::PaintContext
+ \reentrant
+
+ \brief The QAbstractTextDocumentLayout::PaintContext class is a convenience
+ class defining the parameters used when painting a document's layout.
+
+ A paint context is used when rendering custom layouts for QTextDocuments
+ with the QAbstractTextDocumentLayout::draw() function. It is specified by
+ a \l {cursorPosition}{cursor position}, \l {palette}{default text color},
+ \l clip rectangle and a collection of \l selections.
+
+ \sa QAbstractTextDocumentLayout
+*/
+
+/*!
+ \fn QAbstractTextDocumentLayout::PaintContext::PaintContext()
+ \internal
+*/
+
+/*!
+ \variable QAbstractTextDocumentLayout::PaintContext::cursorPosition
+
+ \brief the position within the document, where the cursor line should be
+ drawn.
+
+ The default value is -1.
+*/
+
+/*!
+ \variable QAbstractTextDocumentLayout::PaintContext::palette
+
+ \brief the default color that is used for the text, when no color is
+ specified.
+
+ The default value is the application's default palette.
+*/
+
+/*!
+ \variable QAbstractTextDocumentLayout::PaintContext::clip
+
+ \brief a hint to the layout specifying the area around paragraphs, frames
+ or text require painting.
+
+ Everything outside of this rectangle does not need to be painted.
+
+ Specifying a clip rectangle can speed up drawing of large documents
+ significantly. Note that the clip rectangle is in document coordinates (not
+ in viewport coordinates). It is not a substitute for a clip region set on
+ the painter but merely a hint.
+
+ The default value is a null rectangle indicating everything needs to be
+ painted.
+*/
+
+/*!
+ \variable QAbstractTextDocumentLayout::PaintContext::selections
+
+ \brief the collection of selections that will be rendered when passing this
+ paint context to QAbstractTextDocumentLayout's draw() function.
+
+ The default value is an empty vector indicating no selection.
+*/
+
+/*!
+ \class QAbstractTextDocumentLayout::Selection
+ \reentrant
+
+ \brief The QAbstractTextDocumentLayout::Selection class is a convenience
+ class defining the parameters of a selection.
+
+ A selection can be used to specify a part of a document that should be
+ highlighted when drawing custom layouts for QTextDocuments with the
+ QAbstractTextDocumentLayout::draw() function. It is specified using
+ \l cursor and a \l format.
+
+ \sa QAbstractTextDocumentLayout, PaintContext
+*/
+
+/*!
+ \variable QAbstractTextDocumentLayout::Selection::format
+
+ \brief the format of the selection
+
+ The default value is QTextFormat::InvalidFormat.
+*/
+
+/*!
+ \variable QAbstractTextDocumentLayout::Selection::cursor
+ \brief the selection's cursor
+
+ The default value is a null cursor.
+*/
+
+/*!
+ Creates a new text document layout for the given \a document.
+*/
+QAbstractTextDocumentLayout::QAbstractTextDocumentLayout(QTextDocument *document)
+ : QObject(*new QAbstractTextDocumentLayoutPrivate, document)
+{
+ Q_D(QAbstractTextDocumentLayout);
+ d->setDocument(document);
+}
+
+/*!
+ \internal
+*/
+QAbstractTextDocumentLayout::QAbstractTextDocumentLayout(QAbstractTextDocumentLayoutPrivate &p, QTextDocument *document)
+ :QObject(p, document)
+{
+ Q_D(QAbstractTextDocumentLayout);
+ d->setDocument(document);
+}
+
+/*!
+ \internal
+*/
+QAbstractTextDocumentLayout::~QAbstractTextDocumentLayout()
+{
+}
+
+/*!
+ \fn void QAbstractTextDocumentLayout::registerHandler(int objectType, QObject *component)
+
+ Registers the given \a component as a handler for items of the given \a objectType.
+
+ \note registerHandler() has to be called once for each object type. This
+ means that there is only one handler for multiple replacement characters
+ of the same object type.
+*/
+void QAbstractTextDocumentLayout::registerHandler(int formatType, QObject *component)
+{
+ Q_D(QAbstractTextDocumentLayout);
+
+ QTextObjectInterface *iface = qobject_cast<QTextObjectInterface *>(component);
+ if (!iface)
+ return; // ### print error message on terminal?
+
+ connect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*)));
+
+ QTextObjectHandler h;
+ h.iface = iface;
+ h.component = component;
+ d->handlers.insert(formatType, h);
+}
+
+/*!
+ Returns a handler for objects of the given \a objectType.
+*/
+QTextObjectInterface *QAbstractTextDocumentLayout::handlerForObject(int objectType) const
+{
+ Q_D(const QAbstractTextDocumentLayout);
+
+ QTextObjectHandler handler = d->handlers.value(objectType);
+ if (!handler.component)
+ return 0;
+
+ return handler.iface;
+}
+
+/*!
+ Sets the size of the inline object \a item corresponding to the text
+ \a format.
+
+ \a posInDocument specifies the position of the object within the document.
+
+ The default implementation resizes the \a item to the size returned by
+ the object handler's intrinsicSize() function. This function is called only
+ within Qt. Subclasses can reimplement this function to customize the
+ resizing of inline objects.
+*/
+void QAbstractTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
+{
+ Q_D(QAbstractTextDocumentLayout);
+
+ QTextCharFormat f = format.toCharFormat();
+ Q_ASSERT(f.isValid());
+ QTextObjectHandler handler = d->handlers.value(f.objectType());
+ if (!handler.component)
+ return;
+
+ QSizeF s = handler.iface->intrinsicSize(document(), posInDocument, format);
+ item.setWidth(s.width());
+ item.setAscent(s.height() - 1);
+ item.setDescent(0);
+}
+
+/*!
+ Lays out the inline object \a item using the given text \a format.
+
+ \a posInDocument specifies the position of the object within the document.
+
+ The default implementation does nothing. This function is called only
+ within Qt. Subclasses can reimplement this function to customize the
+ position of inline objects.
+
+ \sa drawInlineObject()
+*/
+void QAbstractTextDocumentLayout::positionInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
+{
+ Q_UNUSED(item);
+ Q_UNUSED(posInDocument);
+ Q_UNUSED(format);
+}
+
+/*!
+ \fn void QAbstractTextDocumentLayout::drawInlineObject(QPainter *painter, const QRectF &rect, QTextInlineObject object, int posInDocument, const QTextFormat &format)
+
+ This function is called to draw the inline object, \a object, with the
+ given \a painter within the rectangle specified by \a rect using the
+ specified text \a format.
+
+ \a posInDocument specifies the position of the object within the document.
+
+ The default implementation calls drawObject() on the object handlers. This
+ function is called only within Qt. Subclasses can reimplement this function
+ to customize the drawing of inline objects.
+
+ \sa draw()
+*/
+void QAbstractTextDocumentLayout::drawInlineObject(QPainter *p, const QRectF &rect, QTextInlineObject item,
+ int posInDocument, const QTextFormat &format)
+{
+ Q_UNUSED(item);
+ Q_D(QAbstractTextDocumentLayout);
+
+ QTextCharFormat f = format.toCharFormat();
+ Q_ASSERT(f.isValid());
+ QTextObjectHandler handler = d->handlers.value(f.objectType());
+ if (!handler.component)
+ return;
+
+ handler.iface->drawObject(p, rect, document(), posInDocument, format);
+}
+
+void QAbstractTextDocumentLayoutPrivate::_q_handlerDestroyed(QObject *obj)
+{
+ HandlerHash::Iterator it = handlers.begin();
+ while (it != handlers.end())
+ if ((*it).component == obj)
+ it = handlers.erase(it);
+ else
+ ++it;
+}
+
+/*!
+ \internal
+
+ Returns the index of the format at position \a pos.
+*/
+int QAbstractTextDocumentLayout::formatIndex(int pos)
+{
+ QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle();
+ return pieceTable->find(pos).value()->format;
+}
+
+/*!
+ \fn QTextCharFormat QAbstractTextDocumentLayout::format(int position)
+
+ Returns the character format that is applicable at the given \a position.
+*/
+QTextCharFormat QAbstractTextDocumentLayout::format(int pos)
+{
+ QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle();
+ int idx = pieceTable->find(pos).value()->format;
+ return pieceTable->formatCollection()->charFormat(idx);
+}
+
+
+
+/*!
+ Returns the text document that this layout is operating on.
+*/
+QTextDocument *QAbstractTextDocumentLayout::document() const
+{
+ Q_D(const QAbstractTextDocumentLayout);
+ return d->document;
+}
+
+/*!
+ \fn QString QAbstractTextDocumentLayout::anchorAt(const QPointF &position) const
+
+ Returns the reference of the anchor the given \a position, or an empty
+ string if no anchor exists at that point.
+*/
+QString QAbstractTextDocumentLayout::anchorAt(const QPointF& pos) const
+{
+ int cursorPos = hitTest(pos, Qt::ExactHit);
+ if (cursorPos == -1)
+ return QString();
+
+ QTextDocumentPrivate *pieceTable = qobject_cast<const QTextDocument *>(parent())->docHandle();
+ QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos);
+ QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format);
+ return fmt.anchorHref();
+}
+
+/*!
+ \fn QRectF QAbstractTextDocumentLayout::frameBoundingRect(QTextFrame *frame) const
+
+ Returns the bounding rectangle of \a frame.
+*/
+
+/*!
+ \fn QRectF QAbstractTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
+
+ Returns the bounding rectangle of \a block.
+*/
+
+/*!
+ Sets the paint device used for rendering the document's layout to the given
+ \a device.
+
+ \sa paintDevice()
+*/
+void QAbstractTextDocumentLayout::setPaintDevice(QPaintDevice *device)
+{
+ Q_D(QAbstractTextDocumentLayout);
+ d->paintDevice = device;
+}
+
+/*!
+ Returns the paint device used to render the document's layout.
+
+ \sa setPaintDevice()
+*/
+QPaintDevice *QAbstractTextDocumentLayout::paintDevice() const
+{
+ Q_D(const QAbstractTextDocumentLayout);
+ return d->paintDevice;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qabstracttextdocumentlayout.cpp"
diff --git a/src/gui/text/qabstracttextdocumentlayout.h b/src/gui/text/qabstracttextdocumentlayout.h
new file mode 100644
index 0000000000..a3cd27cb31
--- /dev/null
+++ b/src/gui/text/qabstracttextdocumentlayout.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QABSTRACTTEXTDOCUMENTLAYOUT_H
+#define QABSTRACTTEXTDOCUMENTLAYOUT_H
+
+#include <QtCore/qobject.h>
+#include <QtGui/qtextlayout.h>
+#include <QtGui/qtextdocument.h>
+#include <QtGui/qtextcursor.h>
+#include <QtGui/qpalette.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QAbstractTextDocumentLayoutPrivate;
+class QTextBlock;
+class QTextObjectInterface;
+class QTextFrame;
+
+class Q_GUI_EXPORT QAbstractTextDocumentLayout : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QAbstractTextDocumentLayout)
+
+public:
+ explicit QAbstractTextDocumentLayout(QTextDocument *doc);
+ ~QAbstractTextDocumentLayout();
+
+ struct Selection
+ {
+ QTextCursor cursor;
+ QTextCharFormat format;
+ };
+
+ struct PaintContext
+ {
+ PaintContext()
+ : cursorPosition(-1)
+ {}
+ int cursorPosition;
+ QPalette palette;
+ QRectF clip;
+ QVector<Selection> selections;
+ };
+
+ virtual void draw(QPainter *painter, const PaintContext &context) = 0;
+ virtual int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const = 0;
+ QString anchorAt(const QPointF& pos) const;
+
+ virtual int pageCount() const = 0;
+ virtual QSizeF documentSize() const = 0;
+
+ virtual QRectF frameBoundingRect(QTextFrame *frame) const = 0;
+ virtual QRectF blockBoundingRect(const QTextBlock &block) const = 0;
+
+ void setPaintDevice(QPaintDevice *device);
+ QPaintDevice *paintDevice() const;
+
+ QTextDocument *document() const;
+
+ void registerHandler(int objectType, QObject *component);
+ QTextObjectInterface *handlerForObject(int objectType) const;
+
+Q_SIGNALS:
+ void update(const QRectF & = QRectF(0., 0., 1000000000., 1000000000.));
+ void updateBlock(const QTextBlock &block);
+ void documentSizeChanged(const QSizeF &newSize);
+ void pageCountChanged(int newPages);
+
+protected:
+ QAbstractTextDocumentLayout(QAbstractTextDocumentLayoutPrivate &, QTextDocument *);
+
+ virtual void documentChanged(int from, int charsRemoved, int charsAdded) = 0;
+
+ virtual void resizeInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format);
+ virtual void positionInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format);
+ virtual void drawInlineObject(QPainter *painter, const QRectF &rect, QTextInlineObject object, int posInDocument, const QTextFormat &format);
+
+ int formatIndex(int pos);
+ QTextCharFormat format(int pos);
+
+private:
+ friend class QTextControl;
+ friend class QTextDocument;
+ friend class QTextDocumentPrivate;
+ friend class QTextEngine;
+ friend class QTextLayout;
+ friend class QTextLine;
+ Q_PRIVATE_SLOT(d_func(), void _q_handlerDestroyed(QObject *obj))
+ Q_PRIVATE_SLOT(d_func(), int _q_dynamicPageCountSlot())
+ Q_PRIVATE_SLOT(d_func(), QSizeF _q_dynamicDocumentSizeSlot())
+};
+
+class Q_GUI_EXPORT QTextObjectInterface
+{
+public:
+ virtual ~QTextObjectInterface() {}
+ virtual QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0;
+ virtual void drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0;
+};
+
+Q_DECLARE_INTERFACE(QTextObjectInterface, "com.trolltech.Qt.QTextObjectInterface")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTTEXTDOCUMENTLAYOUT_H
diff --git a/src/gui/text/qabstracttextdocumentlayout_p.h b/src/gui/text/qabstracttextdocumentlayout_p.h
new file mode 100644
index 0000000000..e1f236d4ee
--- /dev/null
+++ b/src/gui/text/qabstracttextdocumentlayout_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QABSTRACTTEXTDOCUMENTLAYOUT_P_H
+#define QABSTRACTTEXTDOCUMENTLAYOUT_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 "private/qobject_p.h"
+#include "QtCore/qhash.h"
+
+QT_BEGIN_NAMESPACE
+
+struct QTextObjectHandler
+{
+ QTextObjectHandler() : iface(0) {}
+ QTextObjectInterface *iface;
+ QPointer<QObject> component;
+};
+typedef QHash<int, QTextObjectHandler> HandlerHash;
+
+class QAbstractTextDocumentLayoutPrivate : public QObjectPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QAbstractTextDocumentLayout)
+
+ inline QAbstractTextDocumentLayoutPrivate()
+ : paintDevice(0) {}
+
+ inline void setDocument(QTextDocument *doc) {
+ document = doc;
+ docPrivate = 0;
+ if (doc)
+ docPrivate = doc->docHandle();
+ }
+
+ inline int _q_dynamicPageCountSlot() const
+ { return q_func()->pageCount(); }
+ inline QSizeF _q_dynamicDocumentSizeSlot() const
+ { return q_func()->documentSize(); }
+
+ HandlerHash handlers;
+
+ void _q_handlerDestroyed(QObject *obj);
+ QPaintDevice *paintDevice;
+
+ QTextDocument *document;
+ QTextDocumentPrivate *docPrivate;
+};
+
+QT_END_NAMESPACE
+
+#endif // QABSTRACTTEXTDOCUMENTLAYOUT_P_H
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
new file mode 100644
index 0000000000..052dc72b63
--- /dev/null
+++ b/src/gui/text/qcssparser.cpp
@@ -0,0 +1,2768 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qcssparser_p.h"
+
+#include <qdebug.h>
+#include <qcolor.h>
+#include <qfont.h>
+#include <qfileinfo.h>
+#include <qfontmetrics.h>
+#include <qbrush.h>
+#include <qimagereader.h>
+#include "private/qfunctions_p.h"
+
+#ifndef QT_NO_CSSPARSER
+
+QT_BEGIN_NAMESPACE
+
+#include "qcssscanner.cpp"
+
+using namespace QCss;
+
+struct QCssKnownValue
+{
+ const char *name;
+ quint64 id;
+};
+
+static const QCssKnownValue properties[NumProperties - 1] = {
+ { "-qt-background-role", QtBackgroundRole },
+ { "-qt-block-indent", QtBlockIndent },
+ { "-qt-list-indent", QtListIndent },
+ { "-qt-list-number-prefix", QtListNumberPrefix },
+ { "-qt-list-number-suffix", QtListNumberSuffix },
+ { "-qt-paragraph-type", QtParagraphType },
+ { "-qt-style-features", QtStyleFeatures },
+ { "-qt-table-type", QtTableType },
+ { "-qt-user-state", QtUserState },
+ { "alternate-background-color", QtAlternateBackground },
+ { "background", Background },
+ { "background-attachment", BackgroundAttachment },
+ { "background-clip", BackgroundClip },
+ { "background-color", BackgroundColor },
+ { "background-image", BackgroundImage },
+ { "background-origin", BackgroundOrigin },
+ { "background-position", BackgroundPosition },
+ { "background-repeat", BackgroundRepeat },
+ { "border", Border },
+ { "border-bottom", BorderBottom },
+ { "border-bottom-color", BorderBottomColor },
+ { "border-bottom-left-radius", BorderBottomLeftRadius },
+ { "border-bottom-right-radius", BorderBottomRightRadius },
+ { "border-bottom-style", BorderBottomStyle },
+ { "border-bottom-width", BorderBottomWidth },
+ { "border-color", BorderColor },
+ { "border-image", BorderImage },
+ { "border-left", BorderLeft },
+ { "border-left-color", BorderLeftColor },
+ { "border-left-style", BorderLeftStyle },
+ { "border-left-width", BorderLeftWidth },
+ { "border-radius", BorderRadius },
+ { "border-right", BorderRight },
+ { "border-right-color", BorderRightColor },
+ { "border-right-style", BorderRightStyle },
+ { "border-right-width", BorderRightWidth },
+ { "border-style", BorderStyles },
+ { "border-top", BorderTop },
+ { "border-top-color", BorderTopColor },
+ { "border-top-left-radius", BorderTopLeftRadius },
+ { "border-top-right-radius", BorderTopRightRadius },
+ { "border-top-style", BorderTopStyle },
+ { "border-top-width", BorderTopWidth },
+ { "border-width", BorderWidth },
+ { "bottom", Bottom },
+ { "color", Color },
+ { "float", Float },
+ { "font", Font },
+ { "font-family", FontFamily },
+ { "font-size", FontSize },
+ { "font-style", FontStyle },
+ { "font-variant", FontVariant },
+ { "font-weight", FontWeight },
+ { "height", Height },
+ { "image", QtImage },
+ { "image-position", QtImageAlignment },
+ { "left", Left },
+ { "line-height", LineHeight },
+ { "list-style", ListStyle },
+ { "list-style-type", ListStyleType },
+ { "margin" , Margin },
+ { "margin-bottom", MarginBottom },
+ { "margin-left", MarginLeft },
+ { "margin-right", MarginRight },
+ { "margin-top", MarginTop },
+ { "max-height", MaximumHeight },
+ { "max-width", MaximumWidth },
+ { "min-height", MinimumHeight },
+ { "min-width", MinimumWidth },
+ { "outline", Outline },
+ { "outline-bottom-left-radius", OutlineBottomLeftRadius },
+ { "outline-bottom-right-radius", OutlineBottomRightRadius },
+ { "outline-color", OutlineColor },
+ { "outline-offset", OutlineOffset },
+ { "outline-radius", OutlineRadius },
+ { "outline-style", OutlineStyle },
+ { "outline-top-left-radius", OutlineTopLeftRadius },
+ { "outline-top-right-radius", OutlineTopRightRadius },
+ { "outline-width", OutlineWidth },
+ { "padding", Padding },
+ { "padding-bottom", PaddingBottom },
+ { "padding-left", PaddingLeft },
+ { "padding-right", PaddingRight },
+ { "padding-top", PaddingTop },
+ { "page-break-after", PageBreakAfter },
+ { "page-break-before", PageBreakBefore },
+ { "position", Position },
+ { "right", Right },
+ { "selection-background-color", QtSelectionBackground },
+ { "selection-color", QtSelectionForeground },
+ { "spacing", QtSpacing },
+ { "subcontrol-origin", QtOrigin },
+ { "subcontrol-position", QtPosition },
+ { "text-align", TextAlignment },
+ { "text-decoration", TextDecoration },
+ { "text-indent", TextIndent },
+ { "text-transform", TextTransform },
+ { "text-underline-style", TextUnderlineStyle },
+ { "top", Top },
+ { "vertical-align", VerticalAlignment },
+ { "white-space", Whitespace },
+ { "width", Width }
+};
+
+static const QCssKnownValue values[NumKnownValues - 1] = {
+ { "active", Value_Active },
+ { "alternate-base", Value_AlternateBase },
+ { "always", Value_Always },
+ { "auto", Value_Auto },
+ { "base", Value_Base },
+ { "bold", Value_Bold },
+ { "bottom", Value_Bottom },
+ { "bright-text", Value_BrightText },
+ { "button", Value_Button },
+ { "button-text", Value_ButtonText },
+ { "center", Value_Center },
+ { "circle", Value_Circle },
+ { "dark", Value_Dark },
+ { "dashed", Value_Dashed },
+ { "decimal", Value_Decimal },
+ { "disabled", Value_Disabled },
+ { "disc", Value_Disc },
+ { "dot-dash", Value_DotDash },
+ { "dot-dot-dash", Value_DotDotDash },
+ { "dotted", Value_Dotted },
+ { "double", Value_Double },
+ { "groove", Value_Groove },
+ { "highlight", Value_Highlight },
+ { "highlighted-text", Value_HighlightedText },
+ { "inset", Value_Inset },
+ { "italic", Value_Italic },
+ { "large", Value_Large },
+ { "left", Value_Left },
+ { "light", Value_Light },
+ { "line-through", Value_LineThrough },
+ { "link", Value_Link },
+ { "link-visited", Value_LinkVisited },
+ { "lower-alpha", Value_LowerAlpha },
+ { "lower-roman", Value_LowerRoman },
+ { "lowercase", Value_Lowercase },
+ { "medium", Value_Medium },
+ { "mid", Value_Mid },
+ { "middle", Value_Middle },
+ { "midlight", Value_Midlight },
+ { "native", Value_Native },
+ { "none", Value_None },
+ { "normal", Value_Normal },
+ { "nowrap", Value_NoWrap },
+ { "oblique", Value_Oblique },
+ { "off", Value_Off },
+ { "on", Value_On },
+ { "outset", Value_Outset },
+ { "overline", Value_Overline },
+ { "pre", Value_Pre },
+ { "pre-wrap", Value_PreWrap },
+ { "ridge", Value_Ridge },
+ { "right", Value_Right },
+ { "selected", Value_Selected },
+ { "shadow", Value_Shadow },
+ { "small" , Value_Small },
+ { "small-caps", Value_SmallCaps },
+ { "solid", Value_Solid },
+ { "square", Value_Square },
+ { "sub", Value_Sub },
+ { "super", Value_Super },
+ { "text", Value_Text },
+ { "top", Value_Top },
+ { "transparent", Value_Transparent },
+ { "underline", Value_Underline },
+ { "upper-alpha", Value_UpperAlpha },
+ { "upper-roman", Value_UpperRoman },
+ { "uppercase", Value_Uppercase },
+ { "wave", Value_Wave },
+ { "window", Value_Window },
+ { "window-text", Value_WindowText },
+ { "x-large", Value_XLarge },
+ { "xx-large", Value_XXLarge }
+};
+
+//Map id to strings as they appears in the 'values' array above
+static const short indexOfId[NumKnownValues] = { 0, 41, 48, 42, 49, 54, 35, 26, 70, 71, 25, 43, 5, 63, 47,
+ 29, 58, 59, 27, 51, 61, 6, 10, 39, 56, 19, 13, 17, 18, 20, 21, 50, 24, 46, 67, 37, 3, 2, 40, 62, 16,
+ 11, 57, 14, 32, 64, 33, 65, 55, 66, 34, 69, 8, 28, 38, 12, 36, 60, 7, 9, 4, 68, 53, 22, 23, 30, 31,
+ 1, 15, 0, 52, 45, 44 };
+
+QString Value::toString() const
+{
+ if (type == KnownIdentifier) {
+ return QLatin1String(values[indexOfId[variant.toInt()]].name);
+ } else {
+ return variant.toString();
+ }
+}
+
+static const QCssKnownValue pseudos[NumPseudos - 1] = {
+ { "active", PseudoClass_Active },
+ { "adjoins-item", PseudoClass_Item },
+ { "alternate", PseudoClass_Alternate },
+ { "bottom", PseudoClass_Bottom },
+ { "checked", PseudoClass_Checked },
+ { "closable", PseudoClass_Closable },
+ { "closed", PseudoClass_Closed },
+ { "default", PseudoClass_Default },
+ { "disabled", PseudoClass_Disabled },
+ { "edit-focus", PseudoClass_EditFocus },
+ { "editable", PseudoClass_Editable },
+ { "enabled", PseudoClass_Enabled },
+ { "exclusive", PseudoClass_Exclusive },
+ { "first", PseudoClass_First },
+ { "flat", PseudoClass_Flat },
+ { "floatable", PseudoClass_Floatable },
+ { "focus", PseudoClass_Focus },
+ { "has-children", PseudoClass_Children },
+ { "has-siblings", PseudoClass_Sibling },
+ { "horizontal", PseudoClass_Horizontal },
+ { "hover", PseudoClass_Hover },
+ { "indeterminate" , PseudoClass_Indeterminate },
+ { "last", PseudoClass_Last },
+ { "left", PseudoClass_Left },
+ { "maximized", PseudoClass_Maximized },
+ { "middle", PseudoClass_Middle },
+ { "minimized", PseudoClass_Minimized },
+ { "movable", PseudoClass_Movable },
+ { "next-selected", PseudoClass_NextSelected },
+ { "no-frame", PseudoClass_Frameless },
+ { "non-exclusive", PseudoClass_NonExclusive },
+ { "off", PseudoClass_Unchecked },
+ { "on", PseudoClass_Checked },
+ { "only-one", PseudoClass_OnlyOne },
+ { "open", PseudoClass_Open },
+ { "pressed", PseudoClass_Pressed },
+ { "previous-selected", PseudoClass_PreviousSelected },
+ { "read-only", PseudoClass_ReadOnly },
+ { "right", PseudoClass_Right },
+ { "selected", PseudoClass_Selected },
+ { "top", PseudoClass_Top },
+ { "unchecked" , PseudoClass_Unchecked },
+ { "vertical", PseudoClass_Vertical },
+ { "window", PseudoClass_Window }
+};
+
+static const QCssKnownValue origins[NumKnownOrigins - 1] = {
+ { "border", Origin_Border },
+ { "content", Origin_Content },
+ { "margin", Origin_Margin }, // not in css
+ { "padding", Origin_Padding }
+};
+
+static const QCssKnownValue repeats[NumKnownRepeats - 1] = {
+ { "no-repeat", Repeat_None },
+ { "repeat-x", Repeat_X },
+ { "repeat-xy", Repeat_XY },
+ { "repeat-y", Repeat_Y }
+};
+
+static const QCssKnownValue tileModes[NumKnownTileModes - 1] = {
+ { "repeat", TileMode_Repeat },
+ { "round", TileMode_Round },
+ { "stretch", TileMode_Stretch },
+};
+
+static const QCssKnownValue positions[NumKnownPositionModes - 1] = {
+ { "absolute", PositionMode_Absolute },
+ { "fixed", PositionMode_Fixed },
+ { "relative", PositionMode_Relative },
+ { "static", PositionMode_Static }
+};
+
+static const QCssKnownValue attachments[NumKnownAttachments - 1] = {
+ { "fixed", Attachment_Fixed },
+ { "scroll", Attachment_Scroll }
+};
+
+static const QCssKnownValue styleFeatures[NumKnownStyleFeatures - 1] = {
+ { "background-color", StyleFeature_BackgroundColor },
+ { "background-gradient", StyleFeature_BackgroundGradient },
+ { "none", StyleFeature_None }
+};
+
+Q_STATIC_GLOBAL_OPERATOR bool operator<(const QString &name, const QCssKnownValue &prop)
+{
+ return QString::compare(name, QLatin1String(prop.name), Qt::CaseInsensitive) < 0;
+}
+
+Q_STATIC_GLOBAL_OPERATOR bool operator<(const QCssKnownValue &prop, const QString &name)
+{
+ return QString::compare(QLatin1String(prop.name), name, Qt::CaseInsensitive) < 0;
+}
+
+static quint64 findKnownValue(const QString &name, const QCssKnownValue *start, int numValues)
+{
+ const QCssKnownValue *end = &start[numValues - 1];
+ const QCssKnownValue *prop = qBinaryFind(start, end, name);
+ if (prop == end)
+ return 0;
+ return prop->id;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Value Extractor
+ValueExtractor::ValueExtractor(const QVector<Declaration> &decls, const QPalette &pal)
+: declarations(decls), adjustment(0), fontExtracted(false), pal(pal)
+{
+}
+
+LengthData ValueExtractor::lengthValue(const Value& v)
+{
+ QString s = v.variant.toString();
+ s.reserve(s.length());
+ LengthData data;
+ data.unit = LengthData::None;
+ if (s.endsWith(QLatin1String("px"), Qt::CaseInsensitive))
+ data.unit = LengthData::Px;
+ else if (s.endsWith(QLatin1String("ex"), Qt::CaseInsensitive))
+ data.unit = LengthData::Ex;
+ else if (s.endsWith(QLatin1String("em"), Qt::CaseInsensitive))
+ data.unit = LengthData::Em;
+
+ if (data.unit != LengthData::None)
+ s.chop(2);
+
+ data.number = s.toDouble();
+ return data;
+}
+
+static int lengthValueFromData(const LengthData& data, const QFont& f)
+{
+ if (data.unit == LengthData::Ex)
+ return qRound(QFontMetrics(f).xHeight() * data.number);
+ else if (data.unit == LengthData::Em)
+ return qRound(QFontMetrics(f).height() * data.number);
+ return qRound(data.number);
+}
+
+int ValueExtractor::lengthValue(const Declaration &decl)
+{
+ if (decl.d->parsed.isValid())
+ return lengthValueFromData(qvariant_cast<LengthData>(decl.d->parsed), f);
+ if (decl.d->values.count() < 1)
+ return 0;
+ LengthData data = lengthValue(decl.d->values.at(0));
+ decl.d->parsed = QVariant::fromValue<LengthData>(data);
+ return lengthValueFromData(data,f);
+}
+
+void ValueExtractor::lengthValues(const Declaration &decl, int *m)
+{
+ if (decl.d->parsed.isValid()) {
+ QList<QVariant> v = decl.d->parsed.toList();
+ for (int i = 0; i < 4; i++)
+ m[i] = lengthValueFromData(qvariant_cast<LengthData>(v.at(i)), f);
+ return;
+ }
+
+ LengthData datas[4];
+ int i;
+ for (i = 0; i < qMin(decl.d->values.count(), 4); i++)
+ datas[i] = lengthValue(decl.d->values[i]);
+
+ if (i == 0) {
+ LengthData zero = {0.0, LengthData::None};
+ datas[0] = datas[1] = datas[2] = datas[3] = zero;
+ } else if (i == 1) {
+ datas[3] = datas[2] = datas[1] = datas[0];
+ } else if (i == 2) {
+ datas[2] = datas[0];
+ datas[3] = datas[1];
+ } else if (i == 3) {
+ datas[3] = datas[1];
+ }
+
+ QList<QVariant> v;
+ for (i = 0; i < 4; i++) {
+ v += QVariant::fromValue<LengthData>(datas[i]);
+ m[i] = lengthValueFromData(datas[i], f);
+ }
+ decl.d->parsed = v;
+}
+
+bool ValueExtractor::extractGeometry(int *w, int *h, int *minw, int *minh, int *maxw, int *maxh)
+{
+ extractFont();
+ bool hit = false;
+ for (int i = 0; i < declarations.count(); i++) {
+ const Declaration &decl = declarations.at(i);
+ switch (decl.d->propertyId) {
+ case Width: *w = lengthValue(decl); break;
+ case Height: *h = lengthValue(decl); break;
+ case MinimumWidth: *minw = lengthValue(decl); break;
+ case MinimumHeight: *minh = lengthValue(decl); break;
+ case MaximumWidth: *maxw = lengthValue(decl); break;
+ case MaximumHeight: *maxh = lengthValue(decl); break;
+ default: continue;
+ }
+ hit = true;
+ }
+
+ return hit;
+}
+
+bool ValueExtractor::extractPosition(int *left, int *top, int *right, int *bottom, QCss::Origin *origin,
+ Qt::Alignment *position, QCss::PositionMode *mode, Qt::Alignment *textAlignment)
+{
+ extractFont();
+ bool hit = false;
+ for (int i = 0; i < declarations.count(); i++) {
+ const Declaration &decl = declarations.at(i);
+ switch (decl.d->propertyId) {
+ case Left: *left = lengthValue(decl); break;
+ case Top: *top = lengthValue(decl); break;
+ case Right: *right = lengthValue(decl); break;
+ case Bottom: *bottom = lengthValue(decl); break;
+ case QtOrigin: *origin = decl.originValue(); break;
+ case QtPosition: *position = decl.alignmentValue(); break;
+ case TextAlignment: *textAlignment = decl.alignmentValue(); break;
+ case Position: *mode = decl.positionValue(); break;
+ default: continue;
+ }
+ hit = true;
+ }
+
+ return hit;
+}
+
+bool ValueExtractor::extractBox(int *margins, int *paddings, int *spacing)
+{
+ extractFont();
+ bool hit = false;
+ for (int i = 0; i < declarations.count(); i++) {
+ const Declaration &decl = declarations.at(i);
+ switch (decl.d->propertyId) {
+ case PaddingLeft: paddings[LeftEdge] = lengthValue(decl); break;
+ case PaddingRight: paddings[RightEdge] = lengthValue(decl); break;
+ case PaddingTop: paddings[TopEdge] = lengthValue(decl); break;
+ case PaddingBottom: paddings[BottomEdge] = lengthValue(decl); break;
+ case Padding: lengthValues(decl, paddings); break;
+
+ case MarginLeft: margins[LeftEdge] = lengthValue(decl); break;
+ case MarginRight: margins[RightEdge] = lengthValue(decl); break;
+ case MarginTop: margins[TopEdge] = lengthValue(decl); break;
+ case MarginBottom: margins[BottomEdge] = lengthValue(decl); break;
+ case Margin: lengthValues(decl, margins); break;
+ case QtSpacing: if (spacing) *spacing = lengthValue(decl); break;
+
+ default: continue;
+ }
+ hit = true;
+ }
+
+ return hit;
+}
+
+int ValueExtractor::extractStyleFeatures()
+{
+ int features = StyleFeature_None;
+ for (int i = 0; i < declarations.count(); i++) {
+ const Declaration &decl = declarations.at(i);
+ if (decl.d->propertyId == QtStyleFeatures)
+ features = decl.styleFeaturesValue();
+ }
+ return features;
+}
+
+QSize ValueExtractor::sizeValue(const Declaration &decl)
+{
+ if (decl.d->parsed.isValid()) {
+ QList<QVariant> v = decl.d->parsed.toList();
+ return QSize(lengthValueFromData(qvariant_cast<LengthData>(v.at(0)), f),
+ lengthValueFromData(qvariant_cast<LengthData>(v.at(1)), f));
+ }
+
+ LengthData x[2] = { {0, LengthData::None }, {0, LengthData::None} };
+ if (decl.d->values.count() > 0)
+ x[0] = lengthValue(decl.d->values.at(0));
+ if (decl.d->values.count() > 1)
+ x[1] = lengthValue(decl.d->values.at(1));
+ else
+ x[1] = x[0];
+ QList<QVariant> v;
+ v << QVariant::fromValue<LengthData>(x[0]) << qVariantFromValue<LengthData>(x[1]);
+ decl.d->parsed = v;
+ return QSize(lengthValueFromData(x[0], f), lengthValueFromData(x[1], f));
+}
+
+void ValueExtractor::sizeValues(const Declaration &decl, QSize *radii)
+{
+ radii[0] = sizeValue(decl);
+ for (int i = 1; i < 4; i++)
+ radii[i] = radii[0];
+}
+
+bool ValueExtractor::extractBorder(int *borders, QBrush *colors, BorderStyle *styles,
+ QSize *radii)
+{
+ extractFont();
+ bool hit = false;
+ for (int i = 0; i < declarations.count(); i++) {
+ const Declaration &decl = declarations.at(i);
+ switch (decl.d->propertyId) {
+ case BorderLeftWidth: borders[LeftEdge] = lengthValue(decl); break;
+ case BorderRightWidth: borders[RightEdge] = lengthValue(decl); break;
+ case BorderTopWidth: borders[TopEdge] = lengthValue(decl); break;
+ case BorderBottomWidth: borders[BottomEdge] = lengthValue(decl); break;
+ case BorderWidth: lengthValues(decl, borders); break;
+
+ case BorderLeftColor: colors[LeftEdge] = decl.brushValue(pal); break;
+ case BorderRightColor: colors[RightEdge] = decl.brushValue(pal); break;
+ case BorderTopColor: colors[TopEdge] = decl.brushValue(pal); break;
+ case BorderBottomColor: colors[BottomEdge] = decl.brushValue(pal); break;
+ case BorderColor: decl.brushValues(colors, pal); break;
+
+ case BorderTopStyle: styles[TopEdge] = decl.styleValue(); break;
+ case BorderBottomStyle: styles[BottomEdge] = decl.styleValue(); break;
+ case BorderLeftStyle: styles[LeftEdge] = decl.styleValue(); break;
+ case BorderRightStyle: styles[RightEdge] = decl.styleValue(); break;
+ case BorderStyles: decl.styleValues(styles); break;
+
+ case BorderTopLeftRadius: radii[0] = sizeValue(decl); break;
+ case BorderTopRightRadius: radii[1] = sizeValue(decl); break;
+ case BorderBottomLeftRadius: radii[2] = sizeValue(decl); break;
+ case BorderBottomRightRadius: radii[3] = sizeValue(decl); break;
+ case BorderRadius: sizeValues(decl, radii); break;
+
+ case BorderLeft:
+ borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
+ break;
+ case BorderTop:
+ borderValue(decl, &borders[TopEdge], &styles[TopEdge], &colors[TopEdge]);
+ break;
+ case BorderRight:
+ borderValue(decl, &borders[RightEdge], &styles[RightEdge], &colors[RightEdge]);
+ break;
+ case BorderBottom:
+ borderValue(decl, &borders[BottomEdge], &styles[BottomEdge], &colors[BottomEdge]);
+ break;
+ case Border:
+ borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
+ borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
+ styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
+ colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
+ break;
+
+ default: continue;
+ }
+ hit = true;
+ }
+
+ return hit;
+}
+
+bool ValueExtractor::extractOutline(int *borders, QBrush *colors, BorderStyle *styles,
+ QSize *radii, int *offsets)
+{
+ extractFont();
+ bool hit = false;
+ for (int i = 0; i < declarations.count(); i++) {
+ const Declaration &decl = declarations.at(i);
+ switch (decl.d->propertyId) {
+ case OutlineWidth: lengthValues(decl, borders); break;
+ case OutlineColor: decl.brushValues(colors, pal); break;
+ case OutlineStyle: decl.styleValues(styles); break;
+
+ case OutlineTopLeftRadius: radii[0] = sizeValue(decl); break;
+ case OutlineTopRightRadius: radii[1] = sizeValue(decl); break;
+ case OutlineBottomLeftRadius: radii[2] = sizeValue(decl); break;
+ case OutlineBottomRightRadius: radii[3] = sizeValue(decl); break;
+ case OutlineRadius: sizeValues(decl, radii); break;
+ case OutlineOffset: lengthValues(decl, offsets); break;
+
+ case Outline:
+ borderValue(decl, &borders[LeftEdge], &styles[LeftEdge], &colors[LeftEdge]);
+ borders[TopEdge] = borders[RightEdge] = borders[BottomEdge] = borders[LeftEdge];
+ styles[TopEdge] = styles[RightEdge] = styles[BottomEdge] = styles[LeftEdge];
+ colors[TopEdge] = colors[RightEdge] = colors[BottomEdge] = colors[LeftEdge];
+ break;
+
+ default: continue;
+ }
+ hit = true;
+ }
+
+ return hit;
+}
+
+static Qt::Alignment parseAlignment(const QCss::Value *values, int count)
+{
+ Qt::Alignment a[2] = { 0, 0 };
+ for (int i = 0; i < qMin(2, count); i++) {
+ if (values[i].type != Value::KnownIdentifier)
+ break;
+ switch (values[i].variant.toInt()) {
+ case Value_Left: a[i] = Qt::AlignLeft; break;
+ case Value_Right: a[i] = Qt::AlignRight; break;
+ case Value_Top: a[i] = Qt::AlignTop; break;
+ case Value_Bottom: a[i] = Qt::AlignBottom; break;
+ case Value_Center: a[i] = Qt::AlignCenter; break;
+ default: break;
+ }
+ }
+
+ if (a[0] == Qt::AlignCenter && a[1] != 0 && a[1] != Qt::AlignCenter)
+ a[0] = (a[1] == Qt::AlignLeft || a[1] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
+ if ((a[1] == 0 || a[1] == Qt::AlignCenter) && a[0] != Qt::AlignCenter)
+ a[1] = (a[0] == Qt::AlignLeft || a[0] == Qt::AlignRight) ? Qt::AlignVCenter : Qt::AlignHCenter;
+ return a[0] | a[1];
+}
+
+static ColorData parseColorValue(QCss::Value v)
+{
+ if (v.type == Value::Identifier || v.type == Value::String) {
+ v.variant.convert(QVariant::Color);
+ v.type = Value::Color;
+ }
+
+ if (v.type == Value::Color)
+ return qvariant_cast<QColor>(v.variant);
+
+ if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_Transparent)
+ return QColor(Qt::transparent);
+
+ if (v.type != Value::Function)
+ return ColorData();
+
+ QStringList lst = v.variant.toStringList();
+ if (lst.count() != 2)
+ return ColorData();
+
+ if ((lst.at(0).compare(QLatin1String("palette"), Qt::CaseInsensitive)) == 0) {
+ int role = findKnownValue(lst.at(1).trimmed(), values, NumKnownValues);
+ if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
+ return (QPalette::ColorRole)(role-Value_FirstColorRole);
+
+ return ColorData();
+ }
+
+ bool rgb = lst.at(0).startsWith(QLatin1String("rgb"));
+
+ Parser p(lst.at(1));
+ if (!p.testExpr())
+ return ColorData();
+
+ QVector<QCss::Value> colorDigits;
+ if (!p.parseExpr(&colorDigits))
+ return ColorData();
+
+ for (int i = 0; i < qMin(colorDigits.count(), 7); i += 2) {
+ if (colorDigits.at(i).type == Value::Percentage) {
+ colorDigits[i].variant = colorDigits.at(i).variant.toReal() * (255. / 100.);
+ colorDigits[i].type = Value::Number;
+ } else if (colorDigits.at(i).type != Value::Number) {
+ return ColorData();
+ }
+ }
+
+ int v1 = colorDigits.at(0).variant.toInt();
+ int v2 = colorDigits.at(2).variant.toInt();
+ int v3 = colorDigits.at(4).variant.toInt();
+ int alpha = colorDigits.count() >= 7 ? colorDigits.at(6).variant.toInt() : 255;
+
+ return rgb ? QColor::fromRgb(v1, v2, v3, alpha)
+ : QColor::fromHsv(v1, v2, v3, alpha);
+}
+
+static QColor colorFromData(const ColorData& c, const QPalette &pal)
+{
+ if (c.type == ColorData::Color) {
+ return c.color;
+ } else if (c.type == ColorData::Role) {
+ return pal.color(c.role);
+ }
+ return QColor();
+}
+
+static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal)
+{
+ ColorData c = parseColorValue(v);
+ if (c.type == ColorData::Color) {
+ return QBrush(c.color);
+ } else if (c.type == ColorData::Role) {
+ return c.role;
+ }
+
+ if (v.type != Value::Function)
+ return BrushData();
+
+ QStringList lst = v.variant.toStringList();
+ if (lst.count() != 2)
+ return BrushData();
+
+ QStringList gradFuncs;
+ gradFuncs << QLatin1String("qlineargradient") << QLatin1String("qradialgradient") << QLatin1String("qconicalgradient") << QLatin1String("qgradient");
+ int gradType = -1;
+
+ if ((gradType = gradFuncs.indexOf(lst.at(0).toLower())) == -1)
+ return BrushData();
+
+ QHash<QString, qreal> vars;
+ QVector<QGradientStop> stops;
+
+ int spread = -1;
+ QStringList spreads;
+ spreads << QLatin1String("pad") << QLatin1String("reflect") << QLatin1String("repeat");
+
+ bool dependsOnThePalette = false;
+ Parser parser(lst.at(1));
+ while (parser.hasNext()) {
+ parser.skipSpace();
+ if (!parser.test(IDENT))
+ return BrushData();
+ QString attr = parser.lexem();
+ parser.skipSpace();
+ if (!parser.test(COLON))
+ return BrushData();
+ parser.skipSpace();
+ if (attr.compare(QLatin1String("stop"), Qt::CaseInsensitive) == 0) {
+ QCss::Value stop, color;
+ parser.next();
+ if (!parser.parseTerm(&stop)) return BrushData();
+ parser.skipSpace();
+ parser.next();
+ if (!parser.parseTerm(&color)) return BrushData();
+ ColorData cd = parseColorValue(color);
+ if(cd.type == ColorData::Role)
+ dependsOnThePalette = true;
+ stops.append(QGradientStop(stop.variant.toReal(), colorFromData(cd, pal)));
+ } else {
+ parser.next();
+ QCss::Value value;
+ (void)parser.parseTerm(&value);
+ if (attr.compare(QLatin1String("spread"), Qt::CaseInsensitive) == 0) {
+ spread = spreads.indexOf(value.variant.toString());
+ } else {
+ vars[attr] = value.variant.toReal();
+ }
+ }
+ parser.skipSpace();
+ (void)parser.test(COMMA);
+ }
+
+ if (gradType == 0) {
+ QLinearGradient lg(vars.value(QLatin1String("x1")), vars.value(QLatin1String("y1")),
+ vars.value(QLatin1String("x2")), vars.value(QLatin1String("y2")));
+ lg.setCoordinateMode(QGradient::ObjectBoundingMode);
+ lg.setStops(stops);
+ if (spread != -1)
+ lg.setSpread(QGradient::Spread(spread));
+ BrushData bd = QBrush(lg);
+ if (dependsOnThePalette)
+ bd.type = BrushData::DependsOnThePalette;
+ return bd;
+ }
+
+ if (gradType == 1) {
+ QRadialGradient rg(vars.value(QLatin1String("cx")), vars.value(QLatin1String("cy")),
+ vars.value(QLatin1String("radius")), vars.value(QLatin1String("fx")),
+ vars.value(QLatin1String("fy")));
+ rg.setCoordinateMode(QGradient::ObjectBoundingMode);
+ rg.setStops(stops);
+ if (spread != -1)
+ rg.setSpread(QGradient::Spread(spread));
+ BrushData bd = QBrush(rg);
+ if (dependsOnThePalette)
+ bd.type = BrushData::DependsOnThePalette;
+ return bd;
+ }
+
+ if (gradType == 2) {
+ QConicalGradient cg(vars.value(QLatin1String("cx")), vars.value(QLatin1String("cy")),
+ vars.value(QLatin1String("angle")));
+ cg.setCoordinateMode(QGradient::ObjectBoundingMode);
+ cg.setStops(stops);
+ if (spread != -1)
+ cg.setSpread(QGradient::Spread(spread));
+ BrushData bd = QBrush(cg);
+ if (dependsOnThePalette)
+ bd.type = BrushData::DependsOnThePalette;
+ return bd;
+ }
+
+ return BrushData();
+}
+
+static QBrush brushFromData(const BrushData& c, const QPalette &pal)
+{
+ if (c.type == BrushData::Role) {
+ return pal.color(c.role);
+ } else {
+ return c.brush;
+ }
+}
+
+static BorderStyle parseStyleValue(QCss::Value v)
+{
+ if (v.type == Value::KnownIdentifier) {
+ switch (v.variant.toInt()) {
+ case Value_None:
+ return BorderStyle_None;
+ case Value_Dotted:
+ return BorderStyle_Dotted;
+ case Value_Dashed:
+ return BorderStyle_Dashed;
+ case Value_Solid:
+ return BorderStyle_Solid;
+ case Value_Double:
+ return BorderStyle_Double;
+ case Value_DotDash:
+ return BorderStyle_DotDash;
+ case Value_DotDotDash:
+ return BorderStyle_DotDotDash;
+ case Value_Groove:
+ return BorderStyle_Groove;
+ case Value_Ridge:
+ return BorderStyle_Ridge;
+ case Value_Inset:
+ return BorderStyle_Inset;
+ case Value_Outset:
+ return BorderStyle_Outset;
+ case Value_Native:
+ return BorderStyle_Native;
+ default:
+ break;
+ }
+ }
+
+ return BorderStyle_Unknown;
+}
+
+void ValueExtractor::borderValue(const Declaration &decl, int *width, QCss::BorderStyle *style, QBrush *color)
+{
+ if (decl.d->parsed.isValid()) {
+ BorderData data = qvariant_cast<BorderData>(decl.d->parsed);
+ *width = lengthValueFromData(data.width, f);
+ *style = data.style;
+ *color = data.color.type != BrushData::Invalid ? brushFromData(data.color, pal) : QBrush(QColor());
+ return;
+ }
+
+ *width = 0;
+ *style = BorderStyle_None;
+ *color = QColor();
+
+ if (decl.d->values.isEmpty())
+ return;
+
+ BorderData data;
+ data.width.number = 0;
+ data.width.unit = LengthData::None;
+ data.style = BorderStyle_None;
+
+ int i = 0;
+ if (decl.d->values.at(i).type == Value::Length || decl.d->values.at(i).type == Value::Number) {
+ data.width = lengthValue(decl.d->values.at(i));
+ *width = lengthValueFromData(data.width, f);
+ if (++i >= decl.d->values.count()) {
+ decl.d->parsed = QVariant::fromValue<BorderData>(data);
+ return;
+ }
+ }
+
+ data.style = parseStyleValue(decl.d->values.at(i));
+ if (data.style != BorderStyle_Unknown) {
+ *style = data.style;
+ if (++i >= decl.d->values.count()) {
+ decl.d->parsed = QVariant::fromValue<BorderData>(data);
+ return;
+ }
+ } else {
+ data.style = BorderStyle_None;
+ }
+
+ data.color = parseBrushValue(decl.d->values.at(i), pal);
+ *color = brushFromData(data.color, pal);
+ if (data.color.type != BrushData::DependsOnThePalette)
+ decl.d->parsed = QVariant::fromValue<BorderData>(data);
+}
+
+static void parseShorthandBackgroundProperty(const QVector<QCss::Value> &values, BrushData *brush, QString *image, Repeat *repeat, Qt::Alignment *alignment, const QPalette &pal)
+{
+ *brush = BrushData();
+ *image = QString();
+ *repeat = Repeat_XY;
+ *alignment = Qt::AlignTop | Qt::AlignLeft;
+
+ for (int i = 0; i < values.count(); ++i) {
+ const QCss::Value &v = values.at(i);
+ if (v.type == Value::Uri) {
+ *image = v.variant.toString();
+ continue;
+ } else if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_None) {
+ *image = QString();
+ continue;
+ } else if (v.type == Value::KnownIdentifier && v.variant.toInt() == Value_Transparent) {
+ *brush = QBrush(Qt::transparent);
+ }
+
+ Repeat repeatAttempt = static_cast<Repeat>(findKnownValue(v.variant.toString(),
+ repeats, NumKnownRepeats));
+ if (repeatAttempt != Repeat_Unknown) {
+ *repeat = repeatAttempt;
+ continue;
+ }
+
+ if (v.type == Value::KnownIdentifier) {
+ const int start = i;
+ int count = 1;
+ if (i < values.count() - 1
+ && values.at(i + 1).type == Value::KnownIdentifier) {
+ ++i;
+ ++count;
+ }
+ Qt::Alignment a = parseAlignment(values.constData() + start, count);
+ if (int(a) != 0) {
+ *alignment = a;
+ continue;
+ }
+ i -= count - 1;
+ }
+
+ *brush = parseBrushValue(v, pal);
+ }
+}
+
+bool ValueExtractor::extractBackground(QBrush *brush, QString *image, Repeat *repeat,
+ Qt::Alignment *alignment, Origin *origin, Attachment *attachment,
+ Origin *clip)
+{
+ bool hit = false;
+ for (int i = 0; i < declarations.count(); ++i) {
+ const Declaration &decl = declarations.at(i);
+ if (decl.d->values.isEmpty())
+ continue;
+ const QCss::Value &val = decl.d->values.at(0);
+ switch (decl.d->propertyId) {
+ case BackgroundColor:
+ *brush = decl.brushValue();
+ break;
+ case BackgroundImage:
+ if (val.type == Value::Uri)
+ *image = val.variant.toString();
+ break;
+ case BackgroundRepeat:
+ if (decl.d->parsed.isValid()) {
+ *repeat = static_cast<Repeat>(decl.d->parsed.toInt());
+ } else {
+ *repeat = static_cast<Repeat>(findKnownValue(val.variant.toString(),
+ repeats, NumKnownRepeats));
+ decl.d->parsed = *repeat;
+ }
+ break;
+ case BackgroundPosition:
+ *alignment = decl.alignmentValue();
+ break;
+ case BackgroundOrigin:
+ *origin = decl.originValue();
+ break;
+ case BackgroundClip:
+ *clip = decl.originValue();
+ break;
+ case Background:
+ if (decl.d->parsed.isValid()) {
+ BackgroundData data = qvariant_cast<BackgroundData>(decl.d->parsed);
+ *brush = brushFromData(data.brush, pal);
+ *image = data.image;
+ *repeat = data.repeat;
+ *alignment = data.alignment;
+ } else {
+ BrushData brushData;
+ parseShorthandBackgroundProperty(decl.d->values, &brushData, image, repeat, alignment, pal);
+ *brush = brushFromData(brushData, pal);
+ if (brushData.type != BrushData::DependsOnThePalette) {
+ BackgroundData data = { brushData, *image, *repeat, *alignment };
+ decl.d->parsed = QVariant::fromValue<BackgroundData>(data);
+ }
+ }
+ break;
+ case BackgroundAttachment:
+ *attachment = decl.attachmentValue();
+ break;
+ default: continue;
+ }
+ hit = true;
+ }
+ return hit;
+}
+
+static bool setFontSizeFromValue(QCss::Value value, QFont *font, int *fontSizeAdjustment)
+{
+ if (value.type == Value::KnownIdentifier) {
+ bool valid = true;
+ switch (value.variant.toInt()) {
+ case Value_Small: *fontSizeAdjustment = -1; break;
+ case Value_Medium: *fontSizeAdjustment = 0; break;
+ case Value_Large: *fontSizeAdjustment = 1; break;
+ case Value_XLarge: *fontSizeAdjustment = 2; break;
+ case Value_XXLarge: *fontSizeAdjustment = 3; break;
+ default: valid = false; break;
+ }
+ return valid;
+ }
+ if (value.type != Value::Length)
+ return false;
+
+ bool valid = false;
+ QString s = value.variant.toString();
+ if (s.endsWith(QLatin1String("pt"), Qt::CaseInsensitive)) {
+ s.chop(2);
+ value.variant = s;
+ if (value.variant.convert((QVariant::Type)qMetaTypeId<qreal>())) {
+ font->setPointSizeF(value.variant.toReal());
+ valid = true;
+ }
+ } else if (s.endsWith(QLatin1String("px"), Qt::CaseInsensitive)) {
+ s.chop(2);
+ value.variant = s;
+ if (value.variant.convert(QVariant::Int)) {
+ font->setPixelSize(value.variant.toInt());
+ valid = true;
+ }
+ }
+ return valid;
+}
+
+static bool setFontStyleFromValue(const QCss::Value &value, QFont *font)
+{
+ if (value.type != Value::KnownIdentifier)
+ return false ;
+ switch (value.variant.toInt()) {
+ case Value_Normal: font->setStyle(QFont::StyleNormal); return true;
+ case Value_Italic: font->setStyle(QFont::StyleItalic); return true;
+ case Value_Oblique: font->setStyle(QFont::StyleOblique); return true;
+ default: break;
+ }
+ return false;
+}
+
+static bool setFontWeightFromValue(const QCss::Value &value, QFont *font)
+{
+ if (value.type == Value::KnownIdentifier) {
+ switch (value.variant.toInt()) {
+ case Value_Normal: font->setWeight(QFont::Normal); return true;
+ case Value_Bold: font->setWeight(QFont::Bold); return true;
+ default: break;
+ }
+ return false;
+ }
+ if (value.type != Value::Number)
+ return false;
+ font->setWeight(qMin(value.variant.toInt() / 8, 99));
+ return true;
+}
+
+/** \internal
+ * parse the font family from the values (starting from index \a start)
+ * and set it the \a font
+ * \returns true if a family was extracted.
+ */
+static bool setFontFamilyFromValues(const QVector<QCss::Value> &values, QFont *font, int start = 0)
+{
+ QString family;
+ bool shouldAddSpace = false;
+ for (int i = start; i < values.count(); ++i) {
+ const QCss::Value &v = values.at(i);
+ if (v.type == Value::TermOperatorComma) {
+ family += QLatin1Char(',');
+ shouldAddSpace = false;
+ continue;
+ }
+ const QString str = v.variant.toString();
+ if (str.isEmpty())
+ break;
+ if (shouldAddSpace)
+ family += QLatin1Char(' ');
+ family += str;
+ shouldAddSpace = true;
+ }
+ if (family.isEmpty())
+ return false;
+ font->setFamily(family);
+ return true;
+}
+
+static void setTextDecorationFromValues(const QVector<QCss::Value> &values, QFont *font)
+{
+ for (int i = 0; i < values.count(); ++i) {
+ if (values.at(i).type != Value::KnownIdentifier)
+ continue;
+ switch (values.at(i).variant.toInt()) {
+ case Value_Underline: font->setUnderline(true); break;
+ case Value_Overline: font->setOverline(true); break;
+ case Value_LineThrough: font->setStrikeOut(true); break;
+ case Value_None:
+ font->setUnderline(false);
+ font->setOverline(false);
+ font->setStrikeOut(false);
+ break;
+ default: break;
+ }
+ }
+}
+
+static void parseShorthandFontProperty(const QVector<QCss::Value> &values, QFont *font, int *fontSizeAdjustment)
+{
+ font->setStyle(QFont::StyleNormal);
+ font->setWeight(QFont::Normal);
+ *fontSizeAdjustment = -255;
+
+ int i = 0;
+ while (i < values.count()) {
+ if (setFontStyleFromValue(values.at(i), font)
+ || setFontWeightFromValue(values.at(i), font))
+ ++i;
+ else
+ break;
+ }
+
+ if (i < values.count()) {
+ setFontSizeFromValue(values.at(i), font, fontSizeAdjustment);
+ ++i;
+ }
+
+ if (i < values.count()) {
+ setFontFamilyFromValues(values, font, i);
+ }
+}
+
+static void setFontVariantFromValue(const QCss::Value &value, QFont *font)
+{
+ if (value.type == Value::KnownIdentifier) {
+ switch (value.variant.toInt()) {
+ case Value_Normal: font->setCapitalization(QFont::MixedCase); break;
+ case Value_SmallCaps: font->setCapitalization(QFont::SmallCaps); break;
+ default: break;
+ }
+ }
+}
+
+static void setTextTransformFromValue(const QCss::Value &value, QFont *font)
+{
+ if (value.type == Value::KnownIdentifier) {
+ switch (value.variant.toInt()) {
+ case Value_None: font->setCapitalization(QFont::MixedCase); break;
+ case Value_Uppercase: font->setCapitalization(QFont::AllUppercase); break;
+ case Value_Lowercase: font->setCapitalization(QFont::AllLowercase); break;
+ default: break;
+ }
+ }
+}
+
+bool ValueExtractor::extractFont(QFont *font, int *fontSizeAdjustment)
+{
+ if (fontExtracted) {
+ *font = f;
+ *fontSizeAdjustment = adjustment;
+ return fontExtracted == 1;
+ }
+
+ bool hit = false;
+ for (int i = 0; i < declarations.count(); ++i) {
+ const Declaration &decl = declarations.at(i);
+ if (decl.d->values.isEmpty())
+ continue;
+ const QCss::Value &val = decl.d->values.at(0);
+ switch (decl.d->propertyId) {
+ case FontSize: setFontSizeFromValue(val, font, fontSizeAdjustment); break;
+ case FontStyle: setFontStyleFromValue(val, font); break;
+ case FontWeight: setFontWeightFromValue(val, font); break;
+ case FontFamily: setFontFamilyFromValues(decl.d->values, font); break;
+ case TextDecoration: setTextDecorationFromValues(decl.d->values, font); break;
+ case Font: parseShorthandFontProperty(decl.d->values, font, fontSizeAdjustment); break;
+ case FontVariant: setFontVariantFromValue(val, font); break;
+ case TextTransform: setTextTransformFromValue(val, font); break;
+ default: continue;
+ }
+ hit = true;
+ }
+
+ f = *font;
+ adjustment = *fontSizeAdjustment;
+ fontExtracted = hit ? 1 : 2;
+ return hit;
+}
+
+bool ValueExtractor::extractPalette(QBrush *fg, QBrush *sfg, QBrush *sbg, QBrush *abg)
+{
+ bool hit = false;
+ for (int i = 0; i < declarations.count(); ++i) {
+ const Declaration &decl = declarations.at(i);
+ switch (decl.d->propertyId) {
+ case Color: *fg = decl.brushValue(pal); break;
+ case QtSelectionForeground: *sfg = decl.brushValue(pal); break;
+ case QtSelectionBackground: *sbg = decl.brushValue(pal); break;
+ case QtAlternateBackground: *abg = decl.brushValue(pal); break;
+ default: continue;
+ }
+ hit = true;
+ }
+ return hit;
+}
+
+void ValueExtractor::extractFont()
+{
+ if (fontExtracted)
+ return;
+ int dummy = -255;
+ extractFont(&f, &dummy);
+}
+
+bool ValueExtractor::extractImage(QIcon *icon, Qt::Alignment *a, QSize *size)
+{
+ bool hit = false;
+ for (int i = 0; i < declarations.count(); ++i) {
+ const Declaration &decl = declarations.at(i);
+ switch (decl.d->propertyId) {
+ case QtImage:
+ *icon = decl.iconValue();
+ if (decl.d->values.count() > 0 && decl.d->values.at(0).type == Value::Uri) {
+ // try to pull just the size from the image...
+ QImageReader imageReader(decl.d->values.at(0).variant.toString());
+ if ((*size = imageReader.size()).isNull()) {
+ // but we'll have to load the whole image if the
+ // format doesn't support just reading the size
+ *size = imageReader.read().size();
+ }
+ }
+ break;
+ case QtImageAlignment: *a = decl.alignmentValue(); break;
+ default: continue;
+ }
+ hit = true;
+ }
+ return hit;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Declaration
+QColor Declaration::colorValue(const QPalette &pal) const
+{
+ if (d->values.count() != 1)
+ return QColor();
+
+ if (d->parsed.isValid()) {
+ if (d->parsed.type() == QVariant::Color)
+ return qvariant_cast<QColor>(d->parsed);
+ if (d->parsed.type() == QVariant::Int)
+ return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
+ }
+
+ ColorData color = parseColorValue(d->values.at(0));
+ if(color.type == ColorData::Role) {
+ d->parsed = QVariant::fromValue<int>(color.role);
+ return pal.color((QPalette::ColorRole)(color.role));
+ } else {
+ d->parsed = QVariant::fromValue<QColor>(color.color);
+ return color.color;
+ }
+}
+
+QBrush Declaration::brushValue(const QPalette &pal) const
+{
+ if (d->values.count() != 1)
+ return QBrush();
+
+ if (d->parsed.isValid()) {
+ if (d->parsed.type() == QVariant::Brush)
+ return qvariant_cast<QBrush>(d->parsed);
+ if (d->parsed.type() == QVariant::Int)
+ return pal.color((QPalette::ColorRole)(d->parsed.toInt()));
+ }
+
+ BrushData data = parseBrushValue(d->values.at(0), pal);
+
+ if(data.type == BrushData::Role) {
+ d->parsed = QVariant::fromValue<int>(data.role);
+ return pal.color((QPalette::ColorRole)(data.role));
+ } else {
+ if (data.type != BrushData::DependsOnThePalette)
+ d->parsed = QVariant::fromValue<QBrush>(data.brush);
+ return data.brush;
+ }
+}
+
+void Declaration::brushValues(QBrush *c, const QPalette &pal) const
+{
+ int needParse = 0x1f; // bits 0..3 say if we should parse the corresponding value.
+ // the bit 4 say we need to update d->parsed
+ int i = 0;
+ if (d->parsed.isValid()) {
+ needParse = 0;
+ QList<QVariant> v = d->parsed.toList();
+ for (i = 0; i < qMin(v.count(), 4); i++) {
+ if (v.at(i).type() == QVariant::Brush) {
+ c[i] = qvariant_cast<QBrush>(v.at(i));
+ } else if (v.at(i).type() == QVariant::Int) {
+ c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
+ } else {
+ needParse |= (1<<i);
+ }
+ }
+ }
+ if (needParse != 0) {
+ QList<QVariant> v;
+ for (i = 0; i < qMin(d->values.count(), 4); i++) {
+ if (!(needParse & (1<<i)))
+ continue;
+ BrushData data = parseBrushValue(d->values.at(i), pal);
+ if(data.type == BrushData::Role) {
+ v += QVariant::fromValue<int>(data.role);
+ c[i] = pal.color((QPalette::ColorRole)(data.role));
+ } else {
+ if (data.type != BrushData::DependsOnThePalette) {
+ v += QVariant::fromValue<QBrush>(data.brush);
+ } else {
+ v += QVariant();
+ }
+ c[i] = data.brush;
+ }
+ }
+ if (needParse & 0x10)
+ d->parsed = v;
+ }
+ if (i == 0) c[0] = c[1] = c[2] = c[3] = QBrush();
+ else if (i == 1) c[3] = c[2] = c[1] = c[0];
+ else if (i == 2) c[2] = c[0], c[3] = c[1];
+ else if (i == 3) c[3] = c[1];
+}
+
+bool Declaration::realValue(qreal *real, const char *unit) const
+{
+ if (d->values.count() != 1)
+ return false;
+ const Value &v = d->values.at(0);
+ if (unit && v.type != Value::Length)
+ return false;
+ QString s = v.variant.toString();
+ if (unit) {
+ if (!s.endsWith(QLatin1String(unit), Qt::CaseInsensitive))
+ return false;
+ s.chop(qstrlen(unit));
+ }
+ bool ok = false;
+ qreal val = s.toDouble(&ok);
+ if (ok)
+ *real = val;
+ return ok;
+}
+
+static bool intValueHelper(const QCss::Value &v, int *i, const char *unit)
+{
+ if (unit && v.type != Value::Length)
+ return false;
+ QString s = v.variant.toString();
+ if (unit) {
+ if (!s.endsWith(QLatin1String(unit), Qt::CaseInsensitive))
+ return false;
+ s.chop(qstrlen(unit));
+ }
+ bool ok = false;
+ int val = s.toInt(&ok);
+ if (ok)
+ *i = val;
+ return ok;
+}
+
+bool Declaration::intValue(int *i, const char *unit) const
+{
+ if (d->values.count() != 1)
+ return false;
+ return intValueHelper(d->values.at(0), i, unit);
+}
+
+QSize Declaration::sizeValue() const
+{
+ if (d->parsed.isValid())
+ return qvariant_cast<QSize>(d->parsed);
+
+ int x[2] = { 0, 0 };
+ if (d->values.count() > 0)
+ intValueHelper(d->values.at(0), &x[0], "px");
+ if (d->values.count() > 1)
+ intValueHelper(d->values.at(1), &x[1], "px");
+ else
+ x[1] = x[0];
+ QSize size(x[0], x[1]);
+ d->parsed = QVariant::fromValue<QSize>(size);
+ return size;
+}
+
+QRect Declaration::rectValue() const
+{
+ if (d->values.count() != 1)
+ return QRect();
+
+ if (d->parsed.isValid())
+ return qvariant_cast<QRect>(d->parsed);
+
+ const QCss::Value &v = d->values.at(0);
+ if (v.type != Value::Function)
+ return QRect();
+ QStringList func = v.variant.toStringList();
+ if (func.count() != 2 || func.at(0).compare(QLatin1String("rect")) != 0)
+ return QRect();
+ QStringList args = func[1].split(QLatin1Char(' '), QString::SkipEmptyParts);
+ if (args.count() != 4)
+ return QRect();
+ QRect rect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt());
+ d->parsed = QVariant::fromValue<QRect>(rect);
+ return rect;
+}
+
+void Declaration::colorValues(QColor *c, const QPalette &pal) const
+{
+ int i;
+ if (d->parsed.isValid()) {
+ QList<QVariant> v = d->parsed.toList();
+ for (i = 0; i < qMin(d->values.count(), 4); i++) {
+ if (v.at(i).type() == QVariant::Color) {
+ c[i] = qvariant_cast<QColor>(v.at(i));
+ } else {
+ c[i] = pal.color((QPalette::ColorRole)(v.at(i).toInt()));
+ }
+ }
+ } else {
+ QList<QVariant> v;
+ for (i = 0; i < qMin(d->values.count(), 4); i++) {
+ ColorData color = parseColorValue(d->values.at(i));
+ if(color.type == ColorData::Role) {
+ v += QVariant::fromValue<int>(color.role);
+ c[i] = pal.color((QPalette::ColorRole)(color.role));
+ } else {
+ v += QVariant::fromValue<QColor>(color.color);
+ c[i] = color.color;
+ }
+ }
+ d->parsed = v;
+ }
+
+ if (i == 0) c[0] = c[1] = c[2] = c[3] = QColor();
+ else if (i == 1) c[3] = c[2] = c[1] = c[0];
+ else if (i == 2) c[2] = c[0], c[3] = c[1];
+ else if (i == 3) c[3] = c[1];
+}
+
+BorderStyle Declaration::styleValue() const
+{
+ if (d->values.count() != 1)
+ return BorderStyle_None;
+ return parseStyleValue(d->values.at(0));
+}
+
+void Declaration::styleValues(BorderStyle *s) const
+{
+ int i;
+ for (i = 0; i < qMin(d->values.count(), 4); i++)
+ s[i] = parseStyleValue(d->values.at(i));
+ if (i == 0) s[0] = s[1] = s[2] = s[3] = BorderStyle_None;
+ else if (i == 1) s[3] = s[2] = s[1] = s[0];
+ else if (i == 2) s[2] = s[0], s[3] = s[1];
+ else if (i == 3) s[3] = s[1];
+}
+
+Repeat Declaration::repeatValue() const
+{
+ if (d->parsed.isValid())
+ return static_cast<Repeat>(d->parsed.toInt());
+ if (d->values.count() != 1)
+ return Repeat_Unknown;
+ int v = findKnownValue(d->values.at(0).variant.toString(),
+ repeats, NumKnownRepeats);
+ d->parsed = v;
+ return static_cast<Repeat>(v);
+}
+
+Origin Declaration::originValue() const
+{
+ if (d->parsed.isValid())
+ return static_cast<Origin>(d->parsed.toInt());
+ if (d->values.count() != 1)
+ return Origin_Unknown;
+ int v = findKnownValue(d->values.at(0).variant.toString(),
+ origins, NumKnownOrigins);
+ d->parsed = v;
+ return static_cast<Origin>(v);
+}
+
+PositionMode Declaration::positionValue() const
+{
+ if (d->parsed.isValid())
+ return static_cast<PositionMode>(d->parsed.toInt());
+ if (d->values.count() != 1)
+ return PositionMode_Unknown;
+ int v = findKnownValue(d->values.at(0).variant.toString(),
+ positions, NumKnownPositionModes);
+ d->parsed = v;
+ return static_cast<PositionMode>(v);
+}
+
+Attachment Declaration::attachmentValue() const
+{
+ if (d->parsed.isValid())
+ return static_cast<Attachment>(d->parsed.toInt());
+ if (d->values.count() != 1)
+ return Attachment_Unknown;
+ int v = findKnownValue(d->values.at(0).variant.toString(),
+ attachments, NumKnownAttachments);
+ d->parsed = v;
+ return static_cast<Attachment>(v);
+}
+
+int Declaration::styleFeaturesValue() const
+{
+ Q_ASSERT(d->propertyId == QtStyleFeatures);
+ if (d->parsed.isValid())
+ return d->parsed.toInt();
+ int features = StyleFeature_None;
+ for (int i = 0; i < d->values.count(); i++) {
+ features |= static_cast<int>(findKnownValue(d->values.value(i).variant.toString(),
+ styleFeatures, NumKnownStyleFeatures));
+ }
+ d->parsed = features;
+ return features;
+}
+
+QString Declaration::uriValue() const
+{
+ if (d->values.isEmpty() || d->values.at(0).type != Value::Uri)
+ return QString();
+ return d->values.at(0).variant.toString();
+}
+
+Qt::Alignment Declaration::alignmentValue() const
+{
+ if (d->parsed.isValid())
+ return Qt::Alignment(d->parsed.toInt());
+ if (d->values.isEmpty() || d->values.count() > 2)
+ return Qt::AlignLeft | Qt::AlignTop;
+
+ Qt::Alignment v = parseAlignment(d->values.constData(), d->values.count());
+ d->parsed = int(v);
+ return v;
+}
+
+void Declaration::borderImageValue(QString *image, int *cuts,
+ TileMode *h, TileMode *v) const
+{
+ *image = uriValue();
+ for (int i = 0; i < 4; i++)
+ cuts[i] = -1;
+ *h = *v = TileMode_Stretch;
+
+ if (d->values.count() < 2)
+ return;
+
+ if (d->values.at(1).type == Value::Number) { // cuts!
+ int i;
+ for (i = 0; i < qMin(d->values.count()-1, 4); i++) {
+ const Value& v = d->values.at(i+1);
+ if (v.type != Value::Number)
+ break;
+ cuts[i] = v.variant.toString().toInt();
+ }
+ if (i == 0) cuts[0] = cuts[1] = cuts[2] = cuts[3] = 0;
+ else if (i == 1) cuts[3] = cuts[2] = cuts[1] = cuts[0];
+ else if (i == 2) cuts[2] = cuts[0], cuts[3] = cuts[1];
+ else if (i == 3) cuts[3] = cuts[1];
+ }
+
+ if (d->values.last().type == Value::Identifier) {
+ *v = static_cast<TileMode>(findKnownValue(d->values.last().variant.toString(),
+ tileModes, NumKnownTileModes));
+ }
+ if (d->values[d->values.count() - 2].type == Value::Identifier) {
+ *h = static_cast<TileMode>
+ (findKnownValue(d->values[d->values.count()-2].variant.toString(),
+ tileModes, NumKnownTileModes));
+ } else
+ *h = *v;
+}
+
+QIcon Declaration::iconValue() const
+{
+ if (d->parsed.isValid())
+ return qvariant_cast<QIcon>(d->parsed);
+
+ QIcon icon;
+ for (int i = 0; i < d->values.count();) {
+ const Value &value = d->values.at(i++);
+ if (value.type != Value::Uri)
+ break;
+ QString uri = value.variant.toString();
+ QIcon::Mode mode = QIcon::Normal;
+ QIcon::State state = QIcon::Off;
+ for (int j = 0; j < 2; j++) {
+ if (i != d->values.count() && d->values.at(i).type == Value::KnownIdentifier) {
+ switch (d->values.at(i).variant.toInt()) {
+ case Value_Disabled: mode = QIcon::Disabled; break;
+ case Value_Active: mode = QIcon::Active; break;
+ case Value_Selected: mode = QIcon::Selected; break;
+ case Value_Normal: mode = QIcon::Normal; break;
+ case Value_On: state = QIcon::On; break;
+ case Value_Off: state = QIcon::Off; break;
+ default: break;
+ }
+ ++i;
+ } else {
+ break;
+ }
+ }
+
+ // QIcon is soo broken
+ if (icon.isNull())
+ icon = QIcon(uri);
+ else
+ icon.addPixmap(uri, mode, state);
+
+ if (i == d->values.count())
+ break;
+
+ if (d->values.at(i).type == Value::TermOperatorComma)
+ i++;
+ }
+
+ d->parsed = QVariant::fromValue<QIcon>(icon);
+ return icon;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Selector
+int Selector::specificity() const
+{
+ int val = 0;
+ for (int i = 0; i < basicSelectors.count(); ++i) {
+ const BasicSelector &sel = basicSelectors.at(i);
+ if (!sel.elementName.isEmpty())
+ val += 1;
+
+ val += (sel.pseudos.count() + sel.attributeSelectors.count()) * 0x10;
+ val += sel.ids.count() * 0x100;
+ }
+ return val;
+}
+
+QString Selector::pseudoElement() const
+{
+ const BasicSelector& bs = basicSelectors.last();
+ if (!bs.pseudos.isEmpty() && bs.pseudos.at(0).type == PseudoClass_Unknown)
+ return bs.pseudos.at(0).name;
+ return QString();
+}
+
+quint64 Selector::pseudoClass(quint64 *negated) const
+{
+ const BasicSelector& bs = basicSelectors.last();
+ if (bs.pseudos.isEmpty())
+ return PseudoClass_Unspecified;
+ quint64 pc = PseudoClass_Unknown;
+ for (int i = !pseudoElement().isEmpty(); i < bs.pseudos.count(); i++) {
+ const Pseudo &pseudo = bs.pseudos.at(i);
+ if (pseudo.type == PseudoClass_Unknown)
+ return PseudoClass_Unknown;
+ if (!pseudo.negated)
+ pc |= pseudo.type;
+ else if (negated)
+ *negated |= pseudo.type;
+ }
+ return pc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StyleSheet
+void StyleSheet::buildIndexes(Qt::CaseSensitivity nameCaseSensitivity)
+{
+ QVector<StyleRule> universals;
+ for (int i = 0; i < styleRules.count(); ++i) {
+ const StyleRule &rule = styleRules.at(i);
+ QVector<Selector> universalsSelectors;
+ for (int j = 0; j < rule.selectors.count(); ++j) {
+ const Selector& selector = rule.selectors.at(j);
+
+ if (selector.basicSelectors.isEmpty())
+ continue;
+
+ if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
+ if (selector.basicSelectors.count() != 1)
+ continue;
+ } else if (selector.basicSelectors.count() <= 1) {
+ continue;
+ }
+
+ const BasicSelector &sel = selector.basicSelectors.at(selector.basicSelectors.count() - 1);
+
+ if (!sel.ids.isEmpty()) {
+ StyleRule nr;
+ nr.selectors += selector;
+ nr.declarations = rule.declarations;
+ nr.order = i;
+ idIndex.insert(sel.ids.at(0), nr);
+ } else if (!sel.elementName.isEmpty()) {
+ StyleRule nr;
+ nr.selectors += selector;
+ nr.declarations = rule.declarations;
+ nr.order = i;
+ QString name = sel.elementName;
+ if (nameCaseSensitivity == Qt::CaseInsensitive)
+ name=name.toLower();
+ nameIndex.insert(name, nr);
+ } else {
+ universalsSelectors += selector;
+ }
+ }
+ if (!universalsSelectors.isEmpty()) {
+ StyleRule nr;
+ nr.selectors = universalsSelectors;
+ nr.declarations = rule.declarations;
+ nr.order = i;
+ universals << nr;
+ }
+ }
+ styleRules = universals;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StyleSelector
+StyleSelector::~StyleSelector()
+{
+}
+
+bool StyleSelector::nodeNameEquals(NodePtr node, const QString& nodeName) const
+{
+ return nodeNames(node).contains(nodeName, nameCaseSensitivity);
+}
+
+QStringList StyleSelector::nodeIds(NodePtr node) const
+{
+ return QStringList(attribute(node, QLatin1String("id")));
+}
+
+bool StyleSelector::selectorMatches(const Selector &selector, NodePtr node)
+{
+ if (selector.basicSelectors.isEmpty())
+ return false;
+
+ if (selector.basicSelectors.at(0).relationToNext == BasicSelector::NoRelation) {
+ if (selector.basicSelectors.count() != 1)
+ return false;
+ return basicSelectorMatches(selector.basicSelectors.at(0), node);
+ }
+ if (selector.basicSelectors.count() <= 1)
+ return false;
+
+ int i = selector.basicSelectors.count() - 1;
+ node = duplicateNode(node);
+ bool match = true;
+
+ BasicSelector sel = selector.basicSelectors.at(i);
+ do {
+ match = basicSelectorMatches(sel, node);
+ if (!match) {
+ if (sel.relationToNext == BasicSelector::MatchNextSelectorIfParent
+ || i == selector.basicSelectors.count() - 1) // first element must always match!
+ break;
+ }
+
+ if (match || sel.relationToNext != BasicSelector::MatchNextSelectorIfAncestor)
+ --i;
+
+ if (i < 0)
+ break;
+
+ sel = selector.basicSelectors.at(i);
+ if (sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor
+ || sel.relationToNext == BasicSelector::MatchNextSelectorIfParent) {
+
+ NodePtr nextParent = parentNode(node);
+ freeNode(node);
+ node = nextParent;
+ } else if (sel.relationToNext == BasicSelector::MatchNextSelectorIfPreceeds) {
+ NodePtr previousSibling = previousSiblingNode(node);
+ freeNode(node);
+ node = previousSibling;
+ }
+ if (isNullNode(node)) {
+ match = false;
+ break;
+ }
+ } while (i >= 0 && (match || sel.relationToNext == BasicSelector::MatchNextSelectorIfAncestor));
+
+ freeNode(node);
+
+ return match;
+}
+
+bool StyleSelector::basicSelectorMatches(const BasicSelector &sel, NodePtr node)
+{
+ if (!sel.attributeSelectors.isEmpty()) {
+ if (!hasAttributes(node))
+ return false;
+
+ for (int i = 0; i < sel.attributeSelectors.count(); ++i) {
+ const QCss::AttributeSelector &a = sel.attributeSelectors.at(i);
+
+ const QString attrValue = attribute(node, a.name);
+ if (attrValue.isNull())
+ return false;
+
+ if (a.valueMatchCriterium == QCss::AttributeSelector::MatchContains) {
+
+ QStringList lst = attrValue.split(QLatin1Char(' '));
+ if (!lst.contains(a.value))
+ return false;
+ } else if (
+ (a.valueMatchCriterium == QCss::AttributeSelector::MatchEqual
+ && attrValue != a.value)
+ ||
+ (a.valueMatchCriterium == QCss::AttributeSelector::MatchBeginsWith
+ && !attrValue.startsWith(a.value))
+ )
+ return false;
+ }
+ }
+
+ if (!sel.elementName.isEmpty()
+ && !nodeNameEquals(node, sel.elementName))
+ return false;
+
+ if (!sel.ids.isEmpty()
+ && sel.ids != nodeIds(node))
+ return false;
+
+ return true;
+}
+
+void StyleSelector::matchRule(NodePtr node, const StyleRule &rule, StyleSheetOrigin origin,
+ int depth, QMap<uint, StyleRule> *weightedRules)
+{
+ for (int j = 0; j < rule.selectors.count(); ++j) {
+ const Selector& selector = rule.selectors.at(j);
+ if (selectorMatches(selector, node)) {
+ uint weight = rule.order
+ + selector.specificity() *0x100
+ + (uint(origin) + depth)*0x100000;
+ StyleRule newRule = rule;
+ if(rule.selectors.count() > 1) {
+ newRule.selectors.resize(1);
+ newRule.selectors[0] = selector;
+ }
+ //We might have rules with the same weight if they came from a rule with several selectors
+ weightedRules->insertMulti(weight, newRule);
+ }
+ }
+}
+
+// Returns style rules that are in ascending order of specificity
+// Each of the StyleRule returned will contain exactly one Selector
+QVector<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
+{
+ QVector<StyleRule> rules;
+ if (styleSheets.isEmpty())
+ return rules;
+
+ QMap<uint, StyleRule> weightedRules; // (spec, rule) that will be sorted below
+
+ //prune using indexed stylesheet
+ for (int sheetIdx = 0; sheetIdx < styleSheets.count(); ++sheetIdx) {
+ const StyleSheet &styleSheet = styleSheets.at(sheetIdx);
+ for (int i = 0; i < styleSheet.styleRules.count(); ++i) {
+ matchRule(node, styleSheet.styleRules.at(i), styleSheet.origin, styleSheet.depth, &weightedRules);
+ }
+
+ if (!styleSheet.idIndex.isEmpty()) {
+ QStringList ids = nodeIds(node);
+ for (int i = 0; i < ids.count(); i++) {
+ const QString &key = ids.at(i);
+ QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.idIndex.constFind(key);
+ while (it != styleSheet.idIndex.constEnd() && it.key() == key) {
+ matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
+ ++it;
+ }
+ }
+ }
+ if (!styleSheet.nameIndex.isEmpty()) {
+ QStringList names = nodeNames(node);
+ for (int i = 0; i < names.count(); i++) {
+ QString name = names.at(i);
+ if (nameCaseSensitivity == Qt::CaseInsensitive)
+ name = name.toLower();
+ QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.nameIndex.constFind(name);
+ while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
+ matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
+ ++it;
+ }
+ }
+ }
+ if (!medium.isEmpty()) {
+ for (int i = 0; i < styleSheet.mediaRules.count(); ++i) {
+ if (styleSheet.mediaRules.at(i).media.contains(medium, Qt::CaseInsensitive)) {
+ for (int j = 0; j < styleSheet.mediaRules.at(i).styleRules.count(); ++j) {
+ matchRule(node, styleSheet.mediaRules.at(i).styleRules.at(j), styleSheet.origin,
+ styleSheet.depth, &weightedRules);
+ }
+ }
+ }
+ }
+ }
+
+ rules.reserve(weightedRules.count());
+ QMap<uint, StyleRule>::const_iterator it = weightedRules.constBegin();
+ for ( ; it != weightedRules.constEnd() ; ++it)
+ rules += *it;
+
+ return rules;
+}
+
+// for qtexthtmlparser which requires just the declarations with Enabled state
+// and without pseudo elements
+QVector<Declaration> StyleSelector::declarationsForNode(NodePtr node, const char *extraPseudo)
+{
+ QVector<Declaration> decls;
+ QVector<StyleRule> rules = styleRulesForNode(node);
+ for (int i = 0; i < rules.count(); i++) {
+ const Selector& selector = rules.at(i).selectors.at(0);
+ const QString pseudoElement = selector.pseudoElement();
+
+ if (extraPseudo && pseudoElement == QLatin1String(extraPseudo)) {
+ decls += rules.at(i).declarations;
+ continue;
+ }
+
+ if (!pseudoElement.isEmpty()) // skip rules with pseudo elements
+ continue;
+ quint64 pseudoClass = selector.pseudoClass();
+ if (pseudoClass == PseudoClass_Enabled || pseudoClass == PseudoClass_Unspecified)
+ decls += rules.at(i).declarations;
+ }
+ return decls;
+}
+
+static inline bool isHexDigit(const char c)
+{
+ return (c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F')
+ ;
+}
+
+QString Scanner::preprocess(const QString &input, bool *hasEscapeSequences)
+{
+ QString output = input;
+
+ if (hasEscapeSequences)
+ *hasEscapeSequences = false;
+
+ int i = 0;
+ while (i < output.size()) {
+ if (output.at(i) == QLatin1Char('\\')) {
+
+ ++i;
+ // test for unicode hex escape
+ int hexCount = 0;
+ const int hexStart = i;
+ while (i < output.size()
+ && isHexDigit(output.at(i).toLatin1())
+ && hexCount < 7) {
+ ++hexCount;
+ ++i;
+ }
+ if (hexCount == 0) {
+ if (hasEscapeSequences)
+ *hasEscapeSequences = true;
+ continue;
+ }
+
+ hexCount = qMin(hexCount, 6);
+ bool ok = false;
+ ushort code = output.mid(hexStart, hexCount).toUShort(&ok, 16);
+ if (ok) {
+ output.replace(hexStart - 1, hexCount + 1, QChar(code));
+ i = hexStart;
+ } else {
+ i = hexStart;
+ }
+ } else {
+ ++i;
+ }
+ }
+ return output;
+}
+
+int QCssScanner_Generated::handleCommentStart()
+{
+ while (pos < input.size() - 1) {
+ if (input.at(pos) == QLatin1Char('*')
+ && input.at(pos + 1) == QLatin1Char('/')) {
+ pos += 2;
+ break;
+ }
+ ++pos;
+ }
+ return S;
+}
+
+void Scanner::scan(const QString &preprocessedInput, QVector<Symbol> *symbols)
+{
+ QCssScanner_Generated scanner(preprocessedInput);
+ Symbol sym;
+ int tok = scanner.lex();
+ while (tok != -1) {
+ sym.token = static_cast<QCss::TokenType>(tok);
+ sym.text = scanner.input;
+ sym.start = scanner.lexemStart;
+ sym.len = scanner.lexemLength;
+ symbols->append(sym);
+ tok = scanner.lex();
+ }
+}
+
+QString Symbol::lexem() const
+{
+ QString result;
+ if (len > 0)
+ result.reserve(len);
+ for (int i = 0; i < len; ++i) {
+ if (text.at(start + i) == QLatin1Char('\\') && i < len - 1)
+ ++i;
+ result += text.at(start + i);
+ }
+ return result;
+}
+
+Parser::Parser(const QString &css, bool isFile)
+{
+ init(css, isFile);
+}
+
+Parser::Parser()
+{
+ index = 0;
+ errorIndex = -1;
+ hasEscapeSequences = false;
+}
+
+void Parser::init(const QString &css, bool isFile)
+{
+ QString styleSheet = css;
+ if (isFile) {
+ QFile file(css);
+ if (file.open(QFile::ReadOnly)) {
+ sourcePath = QFileInfo(styleSheet).absolutePath() + QLatin1Char('/');
+ QTextStream stream(&file);
+ styleSheet = stream.readAll();
+ } else {
+ qWarning() << "QCss::Parser - Failed to load file " << css;
+ styleSheet.clear();
+ }
+ } else {
+ sourcePath.clear();
+ }
+
+ hasEscapeSequences = false;
+ symbols.resize(0);
+ symbols.reserve(8);
+ Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
+ index = 0;
+ errorIndex = -1;
+}
+
+bool Parser::parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity)
+{
+ if (testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("charset"))) {
+ if (!next(STRING)) return false;
+ if (!next(SEMICOLON)) return false;
+ }
+
+ while (test(S) || test(CDO) || test(CDC)) {}
+
+ while (testImport()) {
+ ImportRule rule;
+ if (!parseImport(&rule)) return false;
+ styleSheet->importRules.append(rule);
+ while (test(S) || test(CDO) || test(CDC)) {}
+ }
+
+ do {
+ if (testMedia()) {
+ MediaRule rule;
+ if (!parseMedia(&rule)) return false;
+ styleSheet->mediaRules.append(rule);
+ } else if (testPage()) {
+ PageRule rule;
+ if (!parsePage(&rule)) return false;
+ styleSheet->pageRules.append(rule);
+ } else if (testRuleset()) {
+ StyleRule rule;
+ if (!parseRuleset(&rule)) return false;
+ styleSheet->styleRules.append(rule);
+ } else if (test(ATKEYWORD_SYM)) {
+ if (!until(RBRACE)) return false;
+ } else if (hasNext()) {
+ return false;
+ }
+ while (test(S) || test(CDO) || test(CDC)) {}
+ } while (hasNext());
+ styleSheet->buildIndexes(nameCaseSensitivity);
+ return true;
+}
+
+Symbol Parser::errorSymbol()
+{
+ if (errorIndex == -1) return Symbol();
+ return symbols.at(errorIndex);
+}
+
+static inline void removeOptionalQuotes(QString *str)
+{
+ if (!str->startsWith(QLatin1Char('\''))
+ && !str->startsWith(QLatin1Char('\"')))
+ return;
+ str->remove(0, 1);
+ str->chop(1);
+}
+
+bool Parser::parseImport(ImportRule *importRule)
+{
+ skipSpace();
+
+ if (test(STRING)) {
+ importRule->href = lexem();
+ } else {
+ if (!testAndParseUri(&importRule->href)) return false;
+ }
+ removeOptionalQuotes(&importRule->href);
+
+ skipSpace();
+
+ if (testMedium()) {
+ if (!parseMedium(&importRule->media)) return false;
+
+ while (test(COMMA)) {
+ skipSpace();
+ if (!parseNextMedium(&importRule->media)) return false;
+ }
+ }
+
+ if (!next(SEMICOLON)) return false;
+
+ skipSpace();
+ return true;
+}
+
+bool Parser::parseMedia(MediaRule *mediaRule)
+{
+ do {
+ skipSpace();
+ if (!parseNextMedium(&mediaRule->media)) return false;
+ } while (test(COMMA));
+
+ if (!next(LBRACE)) return false;
+ skipSpace();
+
+ while (testRuleset()) {
+ StyleRule rule;
+ if (!parseRuleset(&rule)) return false;
+ mediaRule->styleRules.append(rule);
+ }
+
+ if (!next(RBRACE)) return false;
+ skipSpace();
+ return true;
+}
+
+bool Parser::parseMedium(QStringList *media)
+{
+ media->append(lexem());
+ skipSpace();
+ return true;
+}
+
+bool Parser::parsePage(PageRule *pageRule)
+{
+ skipSpace();
+
+ if (testPseudoPage())
+ if (!parsePseudoPage(&pageRule->selector)) return false;
+
+ skipSpace();
+ if (!next(LBRACE)) return false;
+
+ do {
+ skipSpace();
+ Declaration decl;
+ if (!parseNextDeclaration(&decl)) return false;
+ if (!decl.isEmpty())
+ pageRule->declarations.append(decl);
+ } while (test(SEMICOLON));
+
+ if (!next(RBRACE)) return false;
+ skipSpace();
+ return true;
+}
+
+bool Parser::parsePseudoPage(QString *selector)
+{
+ if (!next(IDENT)) return false;
+ *selector = lexem();
+ return true;
+}
+
+bool Parser::parseNextOperator(Value *value)
+{
+ if (!hasNext()) return true;
+ switch (next()) {
+ case SLASH: value->type = Value::TermOperatorSlash; skipSpace(); break;
+ case COMMA: value->type = Value::TermOperatorComma; skipSpace(); break;
+ default: prev(); break;
+ }
+ return true;
+}
+
+bool Parser::parseCombinator(BasicSelector::Relation *relation)
+{
+ *relation = BasicSelector::NoRelation;
+ if (lookup() == S) {
+ *relation = BasicSelector::MatchNextSelectorIfAncestor;
+ skipSpace();
+ } else {
+ prev();
+ }
+ if (test(PLUS)) {
+ *relation = BasicSelector::MatchNextSelectorIfPreceeds;
+ } else if (test(GREATER)) {
+ *relation = BasicSelector::MatchNextSelectorIfParent;
+ }
+ skipSpace();
+ return true;
+}
+
+bool Parser::parseProperty(Declaration *decl)
+{
+ decl->d->property = lexem();
+ decl->d->propertyId = static_cast<Property>(findKnownValue(decl->d->property, properties, NumProperties));
+ skipSpace();
+ return true;
+}
+
+bool Parser::parseRuleset(StyleRule *styleRule)
+{
+ Selector sel;
+ if (!parseSelector(&sel)) return false;
+ styleRule->selectors.append(sel);
+
+ while (test(COMMA)) {
+ skipSpace();
+ Selector sel;
+ if (!parseNextSelector(&sel)) return false;
+ styleRule->selectors.append(sel);
+ }
+
+ skipSpace();
+ if (!next(LBRACE)) return false;
+ const int declarationStart = index;
+
+ do {
+ skipSpace();
+ Declaration decl;
+ const int rewind = index;
+ if (!parseNextDeclaration(&decl)) {
+ index = rewind;
+ const bool foundSemicolon = until(SEMICOLON);
+ const int semicolonIndex = index;
+
+ index = declarationStart;
+ const bool foundRBrace = until(RBRACE);
+
+ if (foundSemicolon && semicolonIndex < index) {
+ decl = Declaration();
+ index = semicolonIndex - 1;
+ } else {
+ skipSpace();
+ return foundRBrace;
+ }
+ }
+ if (!decl.isEmpty())
+ styleRule->declarations.append(decl);
+ } while (test(SEMICOLON));
+
+ if (!next(RBRACE)) return false;
+ skipSpace();
+ return true;
+}
+
+bool Parser::parseSelector(Selector *sel)
+{
+ BasicSelector basicSel;
+ if (!parseSimpleSelector(&basicSel)) return false;
+ while (testCombinator()) {
+ if (!parseCombinator(&basicSel.relationToNext)) return false;
+
+ if (!testSimpleSelector()) break;
+ sel->basicSelectors.append(basicSel);
+
+ basicSel = BasicSelector();
+ if (!parseSimpleSelector(&basicSel)) return false;
+ }
+ sel->basicSelectors.append(basicSel);
+ return true;
+}
+
+bool Parser::parseSimpleSelector(BasicSelector *basicSel)
+{
+ int minCount = 0;
+ if (lookupElementName()) {
+ if (!parseElementName(&basicSel->elementName)) return false;
+ } else {
+ prev();
+ minCount = 1;
+ }
+ bool onceMore;
+ int count = 0;
+ do {
+ onceMore = false;
+ if (test(HASH)) {
+ QString theid = lexem();
+ // chop off leading #
+ theid.remove(0, 1);
+ basicSel->ids.append(theid);
+ onceMore = true;
+ } else if (testClass()) {
+ onceMore = true;
+ AttributeSelector a;
+ a.name = QLatin1String("class");
+ a.valueMatchCriterium = AttributeSelector::MatchContains;
+ if (!parseClass(&a.value)) return false;
+ basicSel->attributeSelectors.append(a);
+ } else if (testAttrib()) {
+ onceMore = true;
+ AttributeSelector a;
+ if (!parseAttrib(&a)) return false;
+ basicSel->attributeSelectors.append(a);
+ } else if (testPseudo()) {
+ onceMore = true;
+ Pseudo ps;
+ if (!parsePseudo(&ps)) return false;
+ basicSel->pseudos.append(ps);
+ }
+ if (onceMore) ++count;
+ } while (onceMore);
+ return count >= minCount;
+}
+
+bool Parser::parseClass(QString *name)
+{
+ if (!next(IDENT)) return false;
+ *name = lexem();
+ return true;
+}
+
+bool Parser::parseElementName(QString *name)
+{
+ switch (lookup()) {
+ case STAR: name->clear(); break;
+ case IDENT: *name = lexem(); break;
+ default: return false;
+ }
+ return true;
+}
+
+bool Parser::parseAttrib(AttributeSelector *attr)
+{
+ skipSpace();
+ if (!next(IDENT)) return false;
+ attr->name = lexem();
+ skipSpace();
+
+ if (test(EQUAL)) {
+ attr->valueMatchCriterium = AttributeSelector::MatchEqual;
+ } else if (test(INCLUDES)) {
+ attr->valueMatchCriterium = AttributeSelector::MatchContains;
+ } else if (test(DASHMATCH)) {
+ attr->valueMatchCriterium = AttributeSelector::MatchBeginsWith;
+ } else {
+ return next(RBRACKET);
+ }
+
+ skipSpace();
+
+ if (!test(IDENT) && !test(STRING)) return false;
+ attr->value = unquotedLexem();
+
+ skipSpace();
+ return next(RBRACKET);
+}
+
+bool Parser::parsePseudo(Pseudo *pseudo)
+{
+ (void)test(COLON);
+ pseudo->negated = test(EXCLAMATION_SYM);
+ if (test(IDENT)) {
+ pseudo->name = lexem();
+ pseudo->type = static_cast<quint64>(findKnownValue(pseudo->name, pseudos, NumPseudos));
+ return true;
+ }
+ if (!next(FUNCTION)) return false;
+ pseudo->function = lexem();
+ // chop off trailing parenthesis
+ pseudo->function.chop(1);
+ skipSpace();
+ if (!test(IDENT)) return false;
+ pseudo->name = lexem();
+ skipSpace();
+ return next(RPAREN);
+}
+
+bool Parser::parseNextDeclaration(Declaration *decl)
+{
+ if (!testProperty())
+ return true; // not an error!
+ if (!parseProperty(decl)) return false;
+ if (!next(COLON)) return false;
+ skipSpace();
+ if (!parseNextExpr(&decl->d->values)) return false;
+ if (testPrio())
+ if (!parsePrio(decl)) return false;
+ return true;
+}
+
+bool Parser::testPrio()
+{
+ const int rewind = index;
+ if (!test(EXCLAMATION_SYM)) return false;
+ skipSpace();
+ if (!test(IDENT)) {
+ index = rewind;
+ return false;
+ }
+ if (lexem().compare(QLatin1String("important"), Qt::CaseInsensitive) != 0) {
+ index = rewind;
+ return false;
+ }
+ return true;
+}
+
+bool Parser::parsePrio(Declaration *declaration)
+{
+ declaration->d->important = true;
+ skipSpace();
+ return true;
+}
+
+bool Parser::parseExpr(QVector<Value> *values)
+{
+ Value val;
+ if (!parseTerm(&val)) return false;
+ values->append(val);
+ bool onceMore;
+ do {
+ onceMore = false;
+ val = Value();
+ if (!parseNextOperator(&val)) return false;
+ if (val.type != QCss::Value::Unknown)
+ values->append(val);
+ if (testTerm()) {
+ onceMore = true;
+ val = Value();
+ if (!parseTerm(&val)) return false;
+ values->append(val);
+ }
+ } while (onceMore);
+ return true;
+}
+
+bool Parser::testTerm()
+{
+ return test(PLUS) || test(MINUS)
+ || test(NUMBER)
+ || test(PERCENTAGE)
+ || test(LENGTH)
+ || test(STRING)
+ || test(IDENT)
+ || testHexColor()
+ || testFunction();
+}
+
+bool Parser::parseTerm(Value *value)
+{
+ QString str = lexem();
+ bool haveUnary = false;
+ if (lookup() == PLUS || lookup() == MINUS) {
+ haveUnary = true;
+ if (!hasNext()) return false;
+ next();
+ str += lexem();
+ }
+
+ value->variant = str;
+ value->type = QCss::Value::String;
+ switch (lookup()) {
+ case NUMBER:
+ value->type = Value::Number;
+ value->variant.convert(QVariant::Double);
+ break;
+ case PERCENTAGE:
+ value->type = Value::Percentage;
+ str.chop(1); // strip off %
+ value->variant = str;
+ break;
+ case LENGTH:
+ value->type = Value::Length;
+ break;
+
+ case STRING:
+ if (haveUnary) return false;
+ value->type = Value::String;
+ str.chop(1);
+ str.remove(0, 1);
+ value->variant = str;
+ break;
+ case IDENT: {
+ if (haveUnary) return false;
+ value->type = Value::Identifier;
+ const int theid = findKnownValue(str, values, NumKnownValues);
+ if (theid != 0) {
+ value->type = Value::KnownIdentifier;
+ value->variant = theid;
+ }
+ break;
+ }
+ default: {
+ if (haveUnary) return false;
+ prev();
+ if (testHexColor()) {
+ QColor col;
+ if (!parseHexColor(&col)) return false;
+ value->type = Value::Color;
+ value->variant = col;
+ } else if (testFunction()) {
+ QString name, args;
+ if (!parseFunction(&name, &args)) return false;
+ if (name == QLatin1String("url")) {
+ value->type = Value::Uri;
+ removeOptionalQuotes(&args);
+ if (QFileInfo(args).isRelative() && !sourcePath.isEmpty()) {
+ args.prepend(sourcePath);
+ }
+ value->variant = args;
+ } else {
+ value->type = Value::Function;
+ value->variant = QStringList() << name << args;
+ }
+ } else {
+ return recordError();
+ }
+ return true;
+ }
+ }
+ skipSpace();
+ return true;
+}
+
+bool Parser::parseFunction(QString *name, QString *args)
+{
+ *name = lexem();
+ name->chop(1);
+ skipSpace();
+ const int start = index;
+ if (!until(RPAREN)) return false;
+ for (int i = start; i < index - 1; ++i)
+ args->append(symbols.at(i).lexem());
+ /*
+ if (!nextExpr(&arguments)) return false;
+ if (!next(RPAREN)) return false;
+ */
+ skipSpace();
+ return true;
+}
+
+bool Parser::parseHexColor(QColor *col)
+{
+ col->setNamedColor(lexem());
+ if (!col->isValid()) {
+ qWarning("QCssParser::parseHexColor: Unknown color name '%s'",lexem().toLatin1().constData());
+ return false;
+ }
+ skipSpace();
+ return true;
+}
+
+bool Parser::testAndParseUri(QString *uri)
+{
+ const int rewind = index;
+ if (!testFunction()) return false;
+
+ QString name, args;
+ if (!parseFunction(&name, &args)) {
+ index = rewind;
+ return false;
+ }
+ if (name.toLower() != QLatin1String("url")) {
+ index = rewind;
+ return false;
+ }
+ *uri = args;
+ removeOptionalQuotes(uri);
+ return true;
+}
+
+bool Parser::testSimpleSelector()
+{
+ return testElementName()
+ || (test(HASH))
+ || testClass()
+ || testAttrib()
+ || testPseudo();
+}
+
+bool Parser::next(QCss::TokenType t)
+{
+ if (hasNext() && next() == t)
+ return true;
+ return recordError();
+}
+
+bool Parser::test(QCss::TokenType t)
+{
+ if (index >= symbols.count())
+ return false;
+ if (symbols.at(index).token == t) {
+ ++index;
+ return true;
+ }
+ return false;
+}
+
+QString Parser::unquotedLexem() const
+{
+ QString s = lexem();
+ if (lookup() == STRING) {
+ s.chop(1);
+ s.remove(0, 1);
+ }
+ return s;
+}
+
+QString Parser::lexemUntil(QCss::TokenType t)
+{
+ QString lexem;
+ while (hasNext() && next() != t)
+ lexem += symbol().lexem();
+ return lexem;
+}
+
+bool Parser::until(QCss::TokenType target, QCss::TokenType target2)
+{
+ int braceCount = 0;
+ int brackCount = 0;
+ int parenCount = 0;
+ if (index) {
+ switch(symbols.at(index-1).token) {
+ case LBRACE: ++braceCount; break;
+ case LBRACKET: ++brackCount; break;
+ case FUNCTION:
+ case LPAREN: ++parenCount; break;
+ default: ;
+ }
+ }
+ while (index < symbols.size()) {
+ QCss::TokenType t = symbols.at(index++).token;
+ switch (t) {
+ case LBRACE: ++braceCount; break;
+ case RBRACE: --braceCount; break;
+ case LBRACKET: ++brackCount; break;
+ case RBRACKET: --brackCount; break;
+ case FUNCTION:
+ case LPAREN: ++parenCount; break;
+ case RPAREN: --parenCount; break;
+ default: break;
+ }
+ if ((t == target || (target2 != NONE && t == target2))
+ && braceCount <= 0
+ && brackCount <= 0
+ && parenCount <= 0)
+ return true;
+
+ if (braceCount < 0 || brackCount < 0 || parenCount < 0) {
+ --index;
+ break;
+ }
+ }
+ return false;
+}
+
+bool Parser::testTokenAndEndsWith(QCss::TokenType t, const QLatin1String &str)
+{
+ if (!test(t)) return false;
+ if (!lexem().endsWith(str, Qt::CaseInsensitive)) {
+ prev();
+ return false;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_CSSPARSER
diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h
new file mode 100644
index 0000000000..86bafc9215
--- /dev/null
+++ b/src/gui/text/qcssparser_p.h
@@ -0,0 +1,847 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QCSSPARSER_P_H
+#define QCSSPARSER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+#include <QtCore/QVariant>
+#include <QtCore/QPair>
+#include <QtCore/QSize>
+#include <QtCore/QMultiHash>
+#include <QtGui/QFont>
+#include <QtGui/QPalette>
+#include <QtGui/QIcon>
+#include <QtCore/QSharedData>
+
+
+#ifndef QT_NO_CSSPARSER
+
+// VxWorks defines NONE as (-1) "for times when NULL won't do"
+#if defined(Q_OS_VXWORKS) && defined(NONE)
+# undef NONE
+#endif
+#if defined(Q_OS_INTEGRITY)
+# undef Value
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QCss
+{
+
+enum Property {
+ UnknownProperty,
+ BackgroundColor,
+ Color,
+ Float,
+ Font,
+ FontFamily,
+ FontSize,
+ FontStyle,
+ FontWeight,
+ Margin,
+ MarginBottom,
+ MarginLeft,
+ MarginRight,
+ MarginTop,
+ QtBlockIndent,
+ QtListIndent,
+ QtParagraphType,
+ QtTableType,
+ QtUserState,
+ TextDecoration,
+ TextIndent,
+ TextUnderlineStyle,
+ VerticalAlignment,
+ Whitespace,
+ QtSelectionForeground,
+ QtSelectionBackground,
+ Border,
+ BorderLeft,
+ BorderRight,
+ BorderTop,
+ BorderBottom,
+ Padding,
+ PaddingLeft,
+ PaddingRight,
+ PaddingTop,
+ PaddingBottom,
+ PageBreakBefore,
+ PageBreakAfter,
+ QtAlternateBackground,
+ BorderLeftStyle,
+ BorderRightStyle,
+ BorderTopStyle,
+ BorderBottomStyle,
+ BorderStyles,
+ BorderLeftColor,
+ BorderRightColor,
+ BorderTopColor,
+ BorderBottomColor,
+ BorderColor,
+ BorderLeftWidth,
+ BorderRightWidth,
+ BorderTopWidth,
+ BorderBottomWidth,
+ BorderWidth,
+ BorderTopLeftRadius,
+ BorderTopRightRadius,
+ BorderBottomLeftRadius,
+ BorderBottomRightRadius,
+ BorderRadius,
+ Background,
+ BackgroundOrigin,
+ BackgroundClip,
+ BackgroundRepeat,
+ BackgroundPosition,
+ BackgroundAttachment,
+ BackgroundImage,
+ BorderImage,
+ QtSpacing,
+ Width,
+ Height,
+ MinimumWidth,
+ MinimumHeight,
+ MaximumWidth,
+ MaximumHeight,
+ QtImage,
+ Left,
+ Right,
+ Top,
+ Bottom,
+ QtOrigin,
+ QtPosition,
+ Position,
+ QtStyleFeatures,
+ QtBackgroundRole,
+ ListStyleType,
+ ListStyle,
+ QtImageAlignment,
+ TextAlignment,
+ Outline,
+ OutlineOffset,
+ OutlineWidth,
+ OutlineColor,
+ OutlineStyle,
+ OutlineRadius,
+ OutlineTopLeftRadius,
+ OutlineTopRightRadius,
+ OutlineBottomLeftRadius,
+ OutlineBottomRightRadius,
+ FontVariant,
+ TextTransform,
+ QtListNumberPrefix,
+ QtListNumberSuffix,
+ LineHeight,
+ NumProperties
+};
+
+enum KnownValue {
+ UnknownValue,
+ Value_Normal,
+ Value_Pre,
+ Value_NoWrap,
+ Value_PreWrap,
+ Value_Small,
+ Value_Medium,
+ Value_Large,
+ Value_XLarge,
+ Value_XXLarge,
+ Value_Italic,
+ Value_Oblique,
+ Value_Bold,
+ Value_Underline,
+ Value_Overline,
+ Value_LineThrough,
+ Value_Sub,
+ Value_Super,
+ Value_Left,
+ Value_Right,
+ Value_Top,
+ Value_Bottom,
+ Value_Center,
+ Value_Native,
+ Value_Solid,
+ Value_Dotted,
+ Value_Dashed,
+ Value_DotDash,
+ Value_DotDotDash,
+ Value_Double,
+ Value_Groove,
+ Value_Ridge,
+ Value_Inset,
+ Value_Outset,
+ Value_Wave,
+ Value_Middle,
+ Value_Auto,
+ Value_Always,
+ Value_None,
+ Value_Transparent,
+ Value_Disc,
+ Value_Circle,
+ Value_Square,
+ Value_Decimal,
+ Value_LowerAlpha,
+ Value_UpperAlpha,
+ Value_LowerRoman,
+ Value_UpperRoman,
+ Value_SmallCaps,
+ Value_Uppercase,
+ Value_Lowercase,
+
+ /* keep these in same order as QPalette::ColorRole */
+ Value_FirstColorRole,
+ Value_WindowText = Value_FirstColorRole,
+ Value_Button,
+ Value_Light,
+ Value_Midlight,
+ Value_Dark,
+ Value_Mid,
+ Value_Text,
+ Value_BrightText,
+ Value_ButtonText,
+ Value_Base,
+ Value_Window,
+ Value_Shadow,
+ Value_Highlight,
+ Value_HighlightedText,
+ Value_Link,
+ Value_LinkVisited,
+ Value_AlternateBase,
+ Value_LastColorRole = Value_AlternateBase,
+
+ Value_Disabled,
+ Value_Active,
+ Value_Selected,
+ Value_On,
+ Value_Off,
+
+ NumKnownValues
+};
+
+enum BorderStyle {
+ BorderStyle_Unknown,
+ BorderStyle_None,
+ BorderStyle_Dotted,
+ BorderStyle_Dashed,
+ BorderStyle_Solid,
+ BorderStyle_Double,
+ BorderStyle_DotDash,
+ BorderStyle_DotDotDash,
+ BorderStyle_Groove,
+ BorderStyle_Ridge,
+ BorderStyle_Inset,
+ BorderStyle_Outset,
+ BorderStyle_Native,
+ NumKnownBorderStyles
+};
+
+enum Edge {
+ TopEdge,
+ RightEdge,
+ BottomEdge,
+ LeftEdge,
+ NumEdges
+};
+
+enum Corner {
+ TopLeftCorner,
+ TopRightCorner,
+ BottomLeftCorner,
+ BottomRightCorner
+};
+
+enum TileMode {
+ TileMode_Unknown,
+ TileMode_Round,
+ TileMode_Stretch,
+ TileMode_Repeat,
+ NumKnownTileModes
+};
+
+enum Repeat {
+ Repeat_Unknown,
+ Repeat_None,
+ Repeat_X,
+ Repeat_Y,
+ Repeat_XY,
+ NumKnownRepeats
+};
+
+enum Origin {
+ Origin_Unknown,
+ Origin_Padding,
+ Origin_Border,
+ Origin_Content,
+ Origin_Margin,
+ NumKnownOrigins
+};
+
+enum PositionMode {
+ PositionMode_Unknown,
+ PositionMode_Static,
+ PositionMode_Relative,
+ PositionMode_Absolute,
+ PositionMode_Fixed,
+ NumKnownPositionModes
+};
+
+enum Attachment {
+ Attachment_Unknown,
+ Attachment_Fixed,
+ Attachment_Scroll,
+ NumKnownAttachments
+};
+
+enum StyleFeature {
+ StyleFeature_None = 0,
+ StyleFeature_BackgroundColor = 1,
+ StyleFeature_BackgroundGradient = 2,
+ NumKnownStyleFeatures = 4
+};
+
+struct Q_GUI_EXPORT Value
+{
+ enum Type {
+ Unknown,
+ Number,
+ Percentage,
+ Length,
+ String,
+ Identifier,
+ KnownIdentifier,
+ Uri,
+ Color,
+ Function,
+ TermOperatorSlash,
+ TermOperatorComma
+ };
+ inline Value() : type(Unknown) { }
+ Type type;
+ QVariant variant;
+ QString toString() const;
+};
+
+struct ColorData {
+ ColorData() : role(QPalette::NoRole), type(Invalid) {}
+ ColorData(const QColor &col) : color(col), role(QPalette::NoRole), type(Color) {}
+ ColorData(QPalette::ColorRole r) : role(r), type(Role) {}
+ QColor color;
+ QPalette::ColorRole role;
+ enum { Invalid, Color, Role} type;
+};
+
+struct BrushData {
+ BrushData() : role(QPalette::NoRole), type(Invalid) {}
+ BrushData(const QBrush &br) : brush(br), role(QPalette::NoRole), type(Brush) {}
+ BrushData(QPalette::ColorRole r) : role(r), type(Role) {}
+ QBrush brush;
+ QPalette::ColorRole role;
+ enum { Invalid, Brush, Role, DependsOnThePalette } type;
+};
+
+struct BackgroundData {
+ BrushData brush;
+ QString image;
+ Repeat repeat;
+ Qt::Alignment alignment;
+};
+
+struct LengthData {
+ qreal number;
+ enum { None, Px, Ex, Em } unit;
+};
+
+struct BorderData {
+ LengthData width;
+ BorderStyle style;
+ BrushData color;
+};
+
+
+// 1. StyleRule - x:hover, y:clicked > z:checked { prop1: value1; prop2: value2; }
+// 2. QVector<Selector> - x:hover, y:clicked z:checked
+// 3. QVector<BasicSelector> - y:clicked z:checked
+// 4. QVector<Declaration> - { prop1: value1; prop2: value2; }
+// 5. Declaration - prop1: value1;
+
+struct Q_AUTOTEST_EXPORT Declaration
+{
+ struct DeclarationData : public QSharedData
+ {
+ inline DeclarationData() : propertyId(UnknownProperty), important(false) {}
+ QString property;
+ Property propertyId;
+ QVector<Value> values;
+ QVariant parsed;
+ bool important;
+ };
+ QExplicitlySharedDataPointer<DeclarationData> d;
+ inline Declaration() : d(new DeclarationData()) {}
+ inline bool isEmpty() const { return d->property.isEmpty() && d->propertyId == UnknownProperty; }
+
+ // helper functions
+ QColor colorValue(const QPalette & = QPalette()) const;
+ void colorValues(QColor *c, const QPalette & = QPalette()) const;
+ QBrush brushValue(const QPalette & = QPalette()) const;
+ void brushValues(QBrush *c, const QPalette & = QPalette()) const;
+
+ BorderStyle styleValue() const;
+ void styleValues(BorderStyle *s) const;
+
+ Origin originValue() const;
+ Repeat repeatValue() const;
+ Qt::Alignment alignmentValue() const;
+ PositionMode positionValue() const;
+ Attachment attachmentValue() const;
+ int styleFeaturesValue() const;
+
+ bool intValue(int *i, const char *unit = 0) const;
+ bool realValue(qreal *r, const char *unit = 0) const;
+
+ QSize sizeValue() const;
+ QRect rectValue() const;
+ QString uriValue() const;
+ QIcon iconValue() const;
+
+ void borderImageValue(QString *image, int *cuts, TileMode *h, TileMode *v) const;
+};
+
+const quint64 PseudoClass_Unknown = Q_UINT64_C(0x0000000000000000);
+const quint64 PseudoClass_Enabled = Q_UINT64_C(0x0000000000000001);
+const quint64 PseudoClass_Disabled = Q_UINT64_C(0x0000000000000002);
+const quint64 PseudoClass_Pressed = Q_UINT64_C(0x0000000000000004);
+const quint64 PseudoClass_Focus = Q_UINT64_C(0x0000000000000008);
+const quint64 PseudoClass_Hover = Q_UINT64_C(0x0000000000000010);
+const quint64 PseudoClass_Checked = Q_UINT64_C(0x0000000000000020);
+const quint64 PseudoClass_Unchecked = Q_UINT64_C(0x0000000000000040);
+const quint64 PseudoClass_Indeterminate = Q_UINT64_C(0x0000000000000080);
+const quint64 PseudoClass_Unspecified = Q_UINT64_C(0x0000000000000100);
+const quint64 PseudoClass_Selected = Q_UINT64_C(0x0000000000000200);
+const quint64 PseudoClass_Horizontal = Q_UINT64_C(0x0000000000000400);
+const quint64 PseudoClass_Vertical = Q_UINT64_C(0x0000000000000800);
+const quint64 PseudoClass_Window = Q_UINT64_C(0x0000000000001000);
+const quint64 PseudoClass_Children = Q_UINT64_C(0x0000000000002000);
+const quint64 PseudoClass_Sibling = Q_UINT64_C(0x0000000000004000);
+const quint64 PseudoClass_Default = Q_UINT64_C(0x0000000000008000);
+const quint64 PseudoClass_First = Q_UINT64_C(0x0000000000010000);
+const quint64 PseudoClass_Last = Q_UINT64_C(0x0000000000020000);
+const quint64 PseudoClass_Middle = Q_UINT64_C(0x0000000000040000);
+const quint64 PseudoClass_OnlyOne = Q_UINT64_C(0x0000000000080000);
+const quint64 PseudoClass_PreviousSelected = Q_UINT64_C(0x0000000000100000);
+const quint64 PseudoClass_NextSelected = Q_UINT64_C(0x0000000000200000);
+const quint64 PseudoClass_Flat = Q_UINT64_C(0x0000000000400000);
+const quint64 PseudoClass_Left = Q_UINT64_C(0x0000000000800000);
+const quint64 PseudoClass_Right = Q_UINT64_C(0x0000000001000000);
+const quint64 PseudoClass_Top = Q_UINT64_C(0x0000000002000000);
+const quint64 PseudoClass_Bottom = Q_UINT64_C(0x0000000004000000);
+const quint64 PseudoClass_Exclusive = Q_UINT64_C(0x0000000008000000);
+const quint64 PseudoClass_NonExclusive = Q_UINT64_C(0x0000000010000000);
+const quint64 PseudoClass_Frameless = Q_UINT64_C(0x0000000020000000);
+const quint64 PseudoClass_ReadOnly = Q_UINT64_C(0x0000000040000000);
+const quint64 PseudoClass_Active = Q_UINT64_C(0x0000000080000000);
+const quint64 PseudoClass_Closable = Q_UINT64_C(0x0000000100000000);
+const quint64 PseudoClass_Movable = Q_UINT64_C(0x0000000200000000);
+const quint64 PseudoClass_Floatable = Q_UINT64_C(0x0000000400000000);
+const quint64 PseudoClass_Minimized = Q_UINT64_C(0x0000000800000000);
+const quint64 PseudoClass_Maximized = Q_UINT64_C(0x0000001000000000);
+const quint64 PseudoClass_On = Q_UINT64_C(0x0000002000000000);
+const quint64 PseudoClass_Off = Q_UINT64_C(0x0000004000000000);
+const quint64 PseudoClass_Editable = Q_UINT64_C(0x0000008000000000);
+const quint64 PseudoClass_Item = Q_UINT64_C(0x0000010000000000);
+const quint64 PseudoClass_Closed = Q_UINT64_C(0x0000020000000000);
+const quint64 PseudoClass_Open = Q_UINT64_C(0x0000040000000000);
+const quint64 PseudoClass_EditFocus = Q_UINT64_C(0x0000080000000000);
+const quint64 PseudoClass_Alternate = Q_UINT64_C(0x0000100000000000);
+// The Any specifier is never generated, but can be used as a wildcard in searches.
+const quint64 PseudoClass_Any = Q_UINT64_C(0x0000ffffffffffff);
+const int NumPseudos = 46;
+
+struct Pseudo
+{
+ Pseudo() : type(0), negated(false) { }
+ quint64 type;
+ QString name;
+ QString function;
+ bool negated;
+};
+
+struct AttributeSelector
+{
+ enum ValueMatchType {
+ NoMatch,
+ MatchEqual,
+ MatchContains,
+ MatchBeginsWith
+ };
+ inline AttributeSelector() : valueMatchCriterium(NoMatch) {}
+
+ QString name;
+ QString value;
+ ValueMatchType valueMatchCriterium;
+};
+
+struct BasicSelector
+{
+ inline BasicSelector() : relationToNext(NoRelation) {}
+
+ enum Relation {
+ NoRelation,
+ MatchNextSelectorIfAncestor,
+ MatchNextSelectorIfParent,
+ MatchNextSelectorIfPreceeds
+ };
+
+ QString elementName;
+
+ QStringList ids;
+ QVector<Pseudo> pseudos;
+ QVector<AttributeSelector> attributeSelectors;
+
+ Relation relationToNext;
+};
+
+struct Q_AUTOTEST_EXPORT Selector
+{
+ QVector<BasicSelector> basicSelectors;
+ int specificity() const;
+ quint64 pseudoClass(quint64 *negated = 0) const;
+ QString pseudoElement() const;
+};
+
+struct StyleRule;
+struct MediaRule;
+struct PageRule;
+struct ImportRule;
+
+struct Q_AUTOTEST_EXPORT ValueExtractor
+{
+ ValueExtractor(const QVector<Declaration> &declarations, const QPalette & = QPalette());
+
+ bool extractFont(QFont *font, int *fontSizeAdjustment);
+ bool extractBackground(QBrush *, QString *, Repeat *, Qt::Alignment *, QCss::Origin *, QCss::Attachment *,
+ QCss::Origin *);
+ bool extractGeometry(int *w, int *h, int *minw, int *minh, int *maxw, int *maxh);
+ bool extractPosition(int *l, int *t, int *r, int *b, QCss::Origin *, Qt::Alignment *,
+ QCss::PositionMode *, Qt::Alignment *);
+ bool extractBox(int *margins, int *paddings, int *spacing = 0);
+ bool extractBorder(int *borders, QBrush *colors, BorderStyle *Styles, QSize *radii);
+ bool extractOutline(int *borders, QBrush *colors, BorderStyle *Styles, QSize *radii, int *offsets);
+ bool extractPalette(QBrush *fg, QBrush *sfg, QBrush *sbg, QBrush *abg);
+ int extractStyleFeatures();
+ bool extractImage(QIcon *icon, Qt::Alignment *a, QSize *size);
+
+ int lengthValue(const Declaration &decl);
+
+private:
+ void extractFont();
+ void borderValue(const Declaration &decl, int *width, QCss::BorderStyle *style, QBrush *color);
+ LengthData lengthValue(const Value& v);
+ void lengthValues(const Declaration &decl, int *m);
+ QSize sizeValue(const Declaration &decl);
+ void sizeValues(const Declaration &decl, QSize *radii);
+
+ QVector<Declaration> declarations;
+ QFont f;
+ int adjustment;
+ int fontExtracted;
+ QPalette pal;
+};
+
+struct StyleRule
+{
+ StyleRule() : order(0) { }
+ QVector<Selector> selectors;
+ QVector<Declaration> declarations;
+ int order;
+};
+
+struct MediaRule
+{
+ QStringList media;
+ QVector<StyleRule> styleRules;
+};
+
+struct PageRule
+{
+ QString selector;
+ QVector<Declaration> declarations;
+};
+
+struct ImportRule
+{
+ QString href;
+ QStringList media;
+};
+
+enum StyleSheetOrigin {
+ StyleSheetOrigin_Unspecified,
+ StyleSheetOrigin_UserAgent,
+ StyleSheetOrigin_User,
+ StyleSheetOrigin_Author,
+ StyleSheetOrigin_Inline
+};
+
+struct StyleSheet
+{
+ StyleSheet() : origin(StyleSheetOrigin_Unspecified), depth(0) { }
+ QVector<StyleRule> styleRules; //only contains rules that are not indexed
+ QVector<MediaRule> mediaRules;
+ QVector<PageRule> pageRules;
+ QVector<ImportRule> importRules;
+ StyleSheetOrigin origin;
+ int depth; // applicable only for inline style sheets
+ QMultiHash<QString, StyleRule> nameIndex;
+ QMultiHash<QString, StyleRule> idIndex;
+ void buildIndexes(Qt::CaseSensitivity nameCaseSensitivity = Qt::CaseSensitive);
+};
+
+class Q_GUI_EXPORT StyleSelector
+{
+public:
+ StyleSelector() : nameCaseSensitivity(Qt::CaseSensitive) {}
+ virtual ~StyleSelector();
+
+ union NodePtr {
+ void *ptr;
+ int id;
+ };
+
+ QVector<StyleRule> styleRulesForNode(NodePtr node);
+ QVector<Declaration> declarationsForNode(NodePtr node, const char *extraPseudo = 0);
+
+ virtual bool nodeNameEquals(NodePtr node, const QString& nodeName) const;
+ virtual QString attribute(NodePtr node, const QString &name) const = 0;
+ virtual bool hasAttributes(NodePtr node) const = 0;
+ virtual QStringList nodeIds(NodePtr node) const;
+ virtual QStringList nodeNames(NodePtr node) const = 0;
+ virtual bool isNullNode(NodePtr node) const = 0;
+ virtual NodePtr parentNode(NodePtr node) const = 0;
+ virtual NodePtr previousSiblingNode(NodePtr node) const = 0;
+ virtual NodePtr duplicateNode(NodePtr node) const = 0;
+ virtual void freeNode(NodePtr node) const = 0;
+
+ QVector<StyleSheet> styleSheets;
+ QString medium;
+ Qt::CaseSensitivity nameCaseSensitivity;
+private:
+ void matchRule(NodePtr node, const StyleRule &rules, StyleSheetOrigin origin,
+ int depth, QMap<uint, StyleRule> *weightedRules);
+ bool selectorMatches(const Selector &rule, NodePtr node);
+ bool basicSelectorMatches(const BasicSelector &rule, NodePtr node);
+};
+
+enum TokenType {
+ NONE,
+
+ S,
+
+ CDO,
+ CDC,
+ INCLUDES,
+ DASHMATCH,
+
+ LBRACE,
+ PLUS,
+ GREATER,
+ COMMA,
+
+ STRING,
+ INVALID,
+
+ IDENT,
+
+ HASH,
+
+ ATKEYWORD_SYM,
+
+ EXCLAMATION_SYM,
+
+ LENGTH,
+
+ PERCENTAGE,
+ NUMBER,
+
+ FUNCTION,
+
+ COLON,
+ SEMICOLON,
+ RBRACE,
+ SLASH,
+ MINUS,
+ DOT,
+ STAR,
+ LBRACKET,
+ RBRACKET,
+ EQUAL,
+ LPAREN,
+ RPAREN,
+ OR
+};
+
+struct Q_GUI_EXPORT Symbol
+{
+ inline Symbol() : token(NONE), start(0), len(-1) {}
+ TokenType token;
+ QString text;
+ int start, len;
+ QString lexem() const;
+};
+
+class Q_AUTOTEST_EXPORT Scanner
+{
+public:
+ static QString preprocess(const QString &input, bool *hasEscapeSequences = 0);
+ static void scan(const QString &preprocessedInput, QVector<Symbol> *symbols);
+};
+
+class Q_GUI_EXPORT Parser
+{
+public:
+ Parser();
+ Parser(const QString &css, bool file = false);
+
+ void init(const QString &css, bool file = false);
+ bool parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity = Qt::CaseSensitive);
+ Symbol errorSymbol();
+
+ bool parseImport(ImportRule *importRule);
+ bool parseMedia(MediaRule *mediaRule);
+ bool parseMedium(QStringList *media);
+ bool parsePage(PageRule *pageRule);
+ bool parsePseudoPage(QString *selector);
+ bool parseNextOperator(Value *value);
+ bool parseCombinator(BasicSelector::Relation *relation);
+ bool parseProperty(Declaration *decl);
+ bool parseRuleset(StyleRule *styleRule);
+ bool parseSelector(Selector *sel);
+ bool parseSimpleSelector(BasicSelector *basicSel);
+ bool parseClass(QString *name);
+ bool parseElementName(QString *name);
+ bool parseAttrib(AttributeSelector *attr);
+ bool parsePseudo(Pseudo *pseudo);
+ bool parseNextDeclaration(Declaration *declaration);
+ bool parsePrio(Declaration *declaration);
+ bool parseExpr(QVector<Value> *values);
+ bool parseTerm(Value *value);
+ bool parseFunction(QString *name, QString *args);
+ bool parseHexColor(QColor *col);
+ bool testAndParseUri(QString *uri);
+
+ inline bool testRuleset() { return testSelector(); }
+ inline bool testSelector() { return testSimpleSelector(); }
+ inline bool parseNextSelector(Selector *sel) { if (!testSelector()) return recordError(); return parseSelector(sel); }
+ bool testSimpleSelector();
+ inline bool parseNextSimpleSelector(BasicSelector *basicSel) { if (!testSimpleSelector()) return recordError(); return parseSimpleSelector(basicSel); }
+ inline bool testElementName() { return test(IDENT) || test(STAR); }
+ inline bool testClass() { return test(DOT); }
+ inline bool testAttrib() { return test(LBRACKET); }
+ inline bool testPseudo() { return test(COLON); }
+ inline bool testMedium() { return test(IDENT); }
+ inline bool parseNextMedium(QStringList *media) { if (!testMedium()) return recordError(); return parseMedium(media); }
+ inline bool testPseudoPage() { return test(COLON); }
+ inline bool testImport() { return testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("import")); }
+ inline bool testMedia() { return testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("media")); }
+ inline bool testPage() { return testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("page")); }
+ inline bool testCombinator() { return test(PLUS) || test(GREATER) || test(S); }
+ inline bool testProperty() { return test(IDENT); }
+ bool testTerm();
+ inline bool testExpr() { return testTerm(); }
+ inline bool parseNextExpr(QVector<Value> *values) { if (!testExpr()) return recordError(); return parseExpr(values); }
+ bool testPrio();
+ inline bool testHexColor() { return test(HASH); }
+ inline bool testFunction() { return test(FUNCTION); }
+ inline bool parseNextFunction(QString *name, QString *args) { if (!testFunction()) return recordError(); return parseFunction(name, args); }
+
+ inline bool lookupElementName() const { return lookup() == IDENT || lookup() == STAR; }
+
+ inline void skipSpace() { while (test(S)) {}; }
+
+ inline bool hasNext() const { return index < symbols.count(); }
+ inline TokenType next() { return symbols.at(index++).token; }
+ bool next(TokenType t);
+ bool test(TokenType t);
+ inline void prev() { index--; }
+ inline const Symbol &symbol() const { return symbols.at(index - 1); }
+ inline QString lexem() const { return symbol().lexem(); }
+ QString unquotedLexem() const;
+ QString lexemUntil(TokenType t);
+ bool until(TokenType target, TokenType target2 = NONE);
+ inline TokenType lookup() const {
+ return (index - 1) < symbols.count() ? symbols.at(index - 1).token : NONE;
+ }
+
+ bool testTokenAndEndsWith(TokenType t, const QLatin1String &str);
+
+ inline bool recordError() { errorIndex = index; return false; }
+
+ QVector<Symbol> symbols;
+ int index;
+ int errorIndex;
+ bool hasEscapeSequences;
+ QString sourcePath;
+};
+
+} // namespace QCss
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE( QCss::BackgroundData )
+Q_DECLARE_METATYPE( QCss::LengthData )
+Q_DECLARE_METATYPE( QCss::BorderData )
+
+
+#endif // QT_NO_CSSPARSER
+
+#endif
diff --git a/src/gui/text/qcssscanner.cpp b/src/gui/text/qcssscanner.cpp
new file mode 100644
index 0000000000..409b86969c
--- /dev/null
+++ b/src/gui/text/qcssscanner.cpp
@@ -0,0 +1,1146 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+// auto generated. DO NOT EDIT.
+class QCssScanner_Generated
+{
+public:
+ QCssScanner_Generated(const QString &inp);
+
+ inline QChar next() {
+ return (pos < input.length()) ? input.at(pos++) : QChar();
+ }
+ int handleCommentStart();
+ int lex();
+
+ QString input;
+ int pos;
+ int lexemStart;
+ int lexemLength;
+};
+
+QCssScanner_Generated::QCssScanner_Generated(const QString &inp)
+{
+ input = inp;
+ pos = 0;
+ lexemStart = 0;
+ lexemLength = 0;
+}
+
+
+int QCssScanner_Generated::lex()
+{
+ lexemStart = pos;
+ lexemLength = 0;
+ int lastAcceptingPos = -1;
+ int token = -1;
+ QChar ch;
+
+ // initial state
+ ch = next();
+ if (ch.unicode() >= 9 && ch.unicode() <= 10)
+ goto state_1;
+ if (ch.unicode() >= 12 && ch.unicode() <= 13)
+ goto state_1;
+ if (ch.unicode() == 32)
+ goto state_1;
+ if (ch.unicode() == 33) {
+ token = QCss::EXCLAMATION_SYM;
+ goto found;
+ }
+ if (ch.unicode() == 34)
+ goto state_3;
+ if (ch.unicode() == 35)
+ goto state_4;
+ if (ch.unicode() == 39)
+ goto state_5;
+ if (ch.unicode() == 40) {
+ token = QCss::LPAREN;
+ goto found;
+ }
+ if (ch.unicode() == 41) {
+ token = QCss::RPAREN;
+ goto found;
+ }
+ if (ch.unicode() == 42) {
+ token = QCss::STAR;
+ goto found;
+ }
+ if (ch.unicode() == 43)
+ goto state_9;
+ if (ch.unicode() == 44)
+ goto state_10;
+ if (ch.unicode() == 45)
+ goto state_11;
+ if (ch.unicode() == 46)
+ goto state_12;
+ if (ch.unicode() == 47)
+ goto state_13;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_14;
+ if (ch.unicode() == 58) {
+ token = QCss::COLON;
+ goto found;
+ }
+ if (ch.unicode() == 59) {
+ token = QCss::SEMICOLON;
+ goto found;
+ }
+ if (ch.unicode() == 60)
+ goto state_17;
+ if (ch.unicode() == 61) {
+ token = QCss::EQUAL;
+ goto found;
+ }
+ if (ch.unicode() == 62)
+ goto state_19;
+ if (ch.unicode() == 64)
+ goto state_20;
+ if (ch.unicode() == 91) {
+ token = QCss::LBRACKET;
+ goto found;
+ }
+ if (ch.unicode() == 92)
+ goto state_22;
+ if (ch.unicode() == 93) {
+ token = QCss::RBRACKET;
+ goto found;
+ }
+ if (ch.unicode() == 95)
+ goto state_24;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_24;
+ if (ch.unicode() == 123)
+ goto state_25;
+ if (ch.unicode() == 124)
+ goto state_26;
+ if (ch.unicode() == 125) {
+ token = QCss::RBRACE;
+ goto found;
+ }
+ if (ch.unicode() == 126)
+ goto state_28;
+ goto out;
+ state_1:
+ lastAcceptingPos = pos;
+ token = QCss::S;
+ ch = next();
+ if (ch.unicode() >= 9 && ch.unicode() <= 10)
+ goto state_29;
+ if (ch.unicode() >= 12 && ch.unicode() <= 13)
+ goto state_29;
+ if (ch.unicode() == 32)
+ goto state_29;
+ if (ch.unicode() == 43)
+ goto state_9;
+ if (ch.unicode() == 44)
+ goto state_10;
+ if (ch.unicode() == 62)
+ goto state_19;
+ if (ch.unicode() == 123)
+ goto state_25;
+ goto out;
+ state_3:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_30;
+ if (ch.unicode() == 11)
+ goto state_30;
+ if (ch.unicode() >= 14 && ch.unicode() <= 33)
+ goto state_30;
+ if (ch.unicode() == 34)
+ goto state_31;
+ if (ch.unicode() >= 35 && ch.unicode() <= 91)
+ goto state_30;
+ if (ch.unicode() == 92)
+ goto state_32;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_30;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_30;
+ if (ch.unicode() >= 123)
+ goto state_30;
+ goto out;
+ state_4:
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_33;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_33;
+ if (ch.unicode() == 92)
+ goto state_34;
+ if (ch.unicode() == 95)
+ goto state_33;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_33;
+ goto out;
+ state_5:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_35;
+ if (ch.unicode() == 11)
+ goto state_35;
+ if (ch.unicode() >= 14 && ch.unicode() <= 38)
+ goto state_35;
+ if (ch.unicode() == 39)
+ goto state_36;
+ if (ch.unicode() >= 40 && ch.unicode() <= 91)
+ goto state_35;
+ if (ch.unicode() == 92)
+ goto state_37;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_35;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_35;
+ if (ch.unicode() >= 123)
+ goto state_35;
+ goto out;
+ state_9:
+ lastAcceptingPos = pos;
+ token = QCss::PLUS;
+ goto out;
+ state_10:
+ lastAcceptingPos = pos;
+ token = QCss::COMMA;
+ goto out;
+ state_11:
+ lastAcceptingPos = pos;
+ token = QCss::MINUS;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_38;
+ if (ch.unicode() == 92)
+ goto state_22;
+ if (ch.unicode() == 95)
+ goto state_24;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_24;
+ goto out;
+ state_12:
+ lastAcceptingPos = pos;
+ token = QCss::DOT;
+ ch = next();
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_39;
+ goto out;
+ state_13:
+ lastAcceptingPos = pos;
+ token = QCss::SLASH;
+ ch = next();
+ if (ch.unicode() == 42) {
+ token = handleCommentStart();
+ goto found;
+ }
+ goto out;
+ state_14:
+ lastAcceptingPos = pos;
+ token = QCss::NUMBER;
+ ch = next();
+ if (ch.unicode() == 37)
+ goto state_41;
+ if (ch.unicode() == 45)
+ goto state_42;
+ if (ch.unicode() == 46)
+ goto state_43;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_44;
+ if (ch.unicode() == 92)
+ goto state_45;
+ if (ch.unicode() == 95)
+ goto state_46;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_46;
+ goto out;
+ state_17:
+ ch = next();
+ if (ch.unicode() == 33)
+ goto state_47;
+ goto out;
+ state_19:
+ lastAcceptingPos = pos;
+ token = QCss::GREATER;
+ goto out;
+ state_20:
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_48;
+ if (ch.unicode() == 92)
+ goto state_49;
+ if (ch.unicode() == 95)
+ goto state_50;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_50;
+ goto out;
+ state_22:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_51;
+ if (ch.unicode() == 11)
+ goto state_51;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_51;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_51;
+ if (ch.unicode() >= 103)
+ goto state_51;
+ goto out;
+ state_24:
+ lastAcceptingPos = pos;
+ token = QCss::IDENT;
+ ch = next();
+ if (ch.unicode() == 40)
+ goto state_52;
+ if (ch.unicode() == 45)
+ goto state_53;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_53;
+ if (ch.unicode() == 92)
+ goto state_54;
+ if (ch.unicode() == 95)
+ goto state_53;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_53;
+ goto out;
+ state_25:
+ lastAcceptingPos = pos;
+ token = QCss::LBRACE;
+ goto out;
+ state_26:
+ lastAcceptingPos = pos;
+ token = QCss::OR;
+ ch = next();
+ if (ch.unicode() == 61) {
+ token = QCss::DASHMATCH;
+ goto found;
+ }
+ goto out;
+ state_28:
+ ch = next();
+ if (ch.unicode() == 61) {
+ token = QCss::INCLUDES;
+ goto found;
+ }
+ goto out;
+ state_29:
+ lastAcceptingPos = pos;
+ token = QCss::S;
+ ch = next();
+ if (ch.unicode() >= 9 && ch.unicode() <= 10)
+ goto state_29;
+ if (ch.unicode() >= 12 && ch.unicode() <= 13)
+ goto state_29;
+ if (ch.unicode() == 32)
+ goto state_29;
+ if (ch.unicode() == 43)
+ goto state_9;
+ if (ch.unicode() == 44)
+ goto state_10;
+ if (ch.unicode() == 62)
+ goto state_19;
+ if (ch.unicode() == 123)
+ goto state_25;
+ goto out;
+ state_30:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_30;
+ if (ch.unicode() == 11)
+ goto state_30;
+ if (ch.unicode() >= 14 && ch.unicode() <= 33)
+ goto state_30;
+ if (ch.unicode() == 34)
+ goto state_31;
+ if (ch.unicode() >= 35 && ch.unicode() <= 91)
+ goto state_30;
+ if (ch.unicode() == 92)
+ goto state_32;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_30;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_30;
+ if (ch.unicode() >= 123)
+ goto state_30;
+ goto out;
+ state_31:
+ lastAcceptingPos = pos;
+ token = QCss::STRING;
+ goto out;
+ state_32:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_57;
+ if (ch.unicode() == 10)
+ goto state_58;
+ if (ch.unicode() == 11)
+ goto state_57;
+ if (ch.unicode() == 12)
+ goto state_59;
+ if (ch.unicode() == 13)
+ goto state_60;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_57;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_57;
+ if (ch.unicode() >= 103)
+ goto state_57;
+ goto out;
+ state_33:
+ lastAcceptingPos = pos;
+ token = QCss::HASH;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_61;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_61;
+ if (ch.unicode() == 92)
+ goto state_62;
+ if (ch.unicode() == 95)
+ goto state_61;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_61;
+ goto out;
+ state_34:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_63;
+ if (ch.unicode() == 11)
+ goto state_63;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_63;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_63;
+ if (ch.unicode() >= 103)
+ goto state_63;
+ goto out;
+ state_35:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_35;
+ if (ch.unicode() == 11)
+ goto state_35;
+ if (ch.unicode() >= 14 && ch.unicode() <= 38)
+ goto state_35;
+ if (ch.unicode() == 39)
+ goto state_36;
+ if (ch.unicode() >= 40 && ch.unicode() <= 91)
+ goto state_35;
+ if (ch.unicode() == 92)
+ goto state_37;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_35;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_35;
+ if (ch.unicode() >= 123)
+ goto state_35;
+ goto out;
+ state_36:
+ lastAcceptingPos = pos;
+ token = QCss::STRING;
+ goto out;
+ state_37:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_64;
+ if (ch.unicode() == 10)
+ goto state_65;
+ if (ch.unicode() == 11)
+ goto state_64;
+ if (ch.unicode() == 12)
+ goto state_66;
+ if (ch.unicode() == 13)
+ goto state_67;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_64;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_64;
+ if (ch.unicode() >= 103)
+ goto state_64;
+ goto out;
+ state_38:
+ ch = next();
+ if (ch.unicode() == 62) {
+ token = QCss::CDC;
+ goto found;
+ }
+ goto out;
+ state_39:
+ lastAcceptingPos = pos;
+ token = QCss::NUMBER;
+ ch = next();
+ if (ch.unicode() == 37)
+ goto state_41;
+ if (ch.unicode() == 45)
+ goto state_42;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_69;
+ if (ch.unicode() == 92)
+ goto state_45;
+ if (ch.unicode() == 95)
+ goto state_46;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_46;
+ goto out;
+ state_41:
+ lastAcceptingPos = pos;
+ token = QCss::PERCENTAGE;
+ goto out;
+ state_42:
+ ch = next();
+ if (ch.unicode() == 92)
+ goto state_45;
+ if (ch.unicode() == 95)
+ goto state_46;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_46;
+ goto out;
+ state_43:
+ ch = next();
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_39;
+ goto out;
+ state_44:
+ lastAcceptingPos = pos;
+ token = QCss::NUMBER;
+ ch = next();
+ if (ch.unicode() == 37)
+ goto state_41;
+ if (ch.unicode() == 45)
+ goto state_42;
+ if (ch.unicode() == 46)
+ goto state_43;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_44;
+ if (ch.unicode() == 92)
+ goto state_45;
+ if (ch.unicode() == 95)
+ goto state_46;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_46;
+ goto out;
+ state_45:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_70;
+ if (ch.unicode() == 11)
+ goto state_70;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_70;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_70;
+ if (ch.unicode() >= 103)
+ goto state_70;
+ goto out;
+ state_46:
+ lastAcceptingPos = pos;
+ token = QCss::LENGTH;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_71;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_71;
+ if (ch.unicode() == 92)
+ goto state_72;
+ if (ch.unicode() == 95)
+ goto state_71;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_71;
+ goto out;
+ state_47:
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_73;
+ goto out;
+ state_48:
+ ch = next();
+ if (ch.unicode() == 92)
+ goto state_49;
+ if (ch.unicode() == 95)
+ goto state_50;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_50;
+ goto out;
+ state_49:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_74;
+ if (ch.unicode() == 11)
+ goto state_74;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_74;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_74;
+ if (ch.unicode() >= 103)
+ goto state_74;
+ goto out;
+ state_50:
+ lastAcceptingPos = pos;
+ token = QCss::ATKEYWORD_SYM;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_75;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_75;
+ if (ch.unicode() == 92)
+ goto state_76;
+ if (ch.unicode() == 95)
+ goto state_75;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_75;
+ goto out;
+ state_51:
+ lastAcceptingPos = pos;
+ token = QCss::IDENT;
+ ch = next();
+ if (ch.unicode() == 40)
+ goto state_52;
+ if (ch.unicode() == 45)
+ goto state_53;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_53;
+ if (ch.unicode() == 92)
+ goto state_54;
+ if (ch.unicode() == 95)
+ goto state_53;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_53;
+ goto out;
+ state_52:
+ lastAcceptingPos = pos;
+ token = QCss::FUNCTION;
+ goto out;
+ state_53:
+ lastAcceptingPos = pos;
+ token = QCss::IDENT;
+ ch = next();
+ if (ch.unicode() == 40)
+ goto state_52;
+ if (ch.unicode() == 45)
+ goto state_53;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_53;
+ if (ch.unicode() == 92)
+ goto state_54;
+ if (ch.unicode() == 95)
+ goto state_53;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_53;
+ goto out;
+ state_54:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_77;
+ if (ch.unicode() == 11)
+ goto state_77;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_77;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_77;
+ if (ch.unicode() >= 103)
+ goto state_77;
+ goto out;
+ state_57:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_30;
+ if (ch.unicode() == 11)
+ goto state_30;
+ if (ch.unicode() >= 14 && ch.unicode() <= 33)
+ goto state_30;
+ if (ch.unicode() == 34)
+ goto state_31;
+ if (ch.unicode() >= 35 && ch.unicode() <= 91)
+ goto state_30;
+ if (ch.unicode() == 92)
+ goto state_32;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_30;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_30;
+ if (ch.unicode() >= 123)
+ goto state_30;
+ goto out;
+ state_58:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_30;
+ if (ch.unicode() == 11)
+ goto state_30;
+ if (ch.unicode() >= 14 && ch.unicode() <= 33)
+ goto state_30;
+ if (ch.unicode() == 34)
+ goto state_31;
+ if (ch.unicode() >= 35 && ch.unicode() <= 91)
+ goto state_30;
+ if (ch.unicode() == 92)
+ goto state_32;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_30;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_30;
+ if (ch.unicode() >= 123)
+ goto state_30;
+ goto out;
+ state_59:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_30;
+ if (ch.unicode() == 11)
+ goto state_30;
+ if (ch.unicode() >= 14 && ch.unicode() <= 33)
+ goto state_30;
+ if (ch.unicode() == 34)
+ goto state_31;
+ if (ch.unicode() >= 35 && ch.unicode() <= 91)
+ goto state_30;
+ if (ch.unicode() == 92)
+ goto state_32;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_30;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_30;
+ if (ch.unicode() >= 123)
+ goto state_30;
+ goto out;
+ state_60:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_30;
+ if (ch.unicode() == 10)
+ goto state_78;
+ if (ch.unicode() == 11)
+ goto state_30;
+ if (ch.unicode() >= 14 && ch.unicode() <= 33)
+ goto state_30;
+ if (ch.unicode() == 34)
+ goto state_31;
+ if (ch.unicode() >= 35 && ch.unicode() <= 91)
+ goto state_30;
+ if (ch.unicode() == 92)
+ goto state_32;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_30;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_30;
+ if (ch.unicode() >= 123)
+ goto state_30;
+ goto out;
+ state_61:
+ lastAcceptingPos = pos;
+ token = QCss::HASH;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_61;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_61;
+ if (ch.unicode() == 92)
+ goto state_62;
+ if (ch.unicode() == 95)
+ goto state_61;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_61;
+ goto out;
+ state_62:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_79;
+ if (ch.unicode() == 11)
+ goto state_79;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_79;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_79;
+ if (ch.unicode() >= 103)
+ goto state_79;
+ goto out;
+ state_63:
+ lastAcceptingPos = pos;
+ token = QCss::HASH;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_61;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_61;
+ if (ch.unicode() == 92)
+ goto state_62;
+ if (ch.unicode() == 95)
+ goto state_61;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_61;
+ goto out;
+ state_64:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_35;
+ if (ch.unicode() == 11)
+ goto state_35;
+ if (ch.unicode() >= 14 && ch.unicode() <= 38)
+ goto state_35;
+ if (ch.unicode() == 39)
+ goto state_36;
+ if (ch.unicode() >= 40 && ch.unicode() <= 91)
+ goto state_35;
+ if (ch.unicode() == 92)
+ goto state_37;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_35;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_35;
+ if (ch.unicode() >= 123)
+ goto state_35;
+ goto out;
+ state_65:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_35;
+ if (ch.unicode() == 11)
+ goto state_35;
+ if (ch.unicode() >= 14 && ch.unicode() <= 38)
+ goto state_35;
+ if (ch.unicode() == 39)
+ goto state_36;
+ if (ch.unicode() >= 40 && ch.unicode() <= 91)
+ goto state_35;
+ if (ch.unicode() == 92)
+ goto state_37;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_35;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_35;
+ if (ch.unicode() >= 123)
+ goto state_35;
+ goto out;
+ state_66:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_35;
+ if (ch.unicode() == 11)
+ goto state_35;
+ if (ch.unicode() >= 14 && ch.unicode() <= 38)
+ goto state_35;
+ if (ch.unicode() == 39)
+ goto state_36;
+ if (ch.unicode() >= 40 && ch.unicode() <= 91)
+ goto state_35;
+ if (ch.unicode() == 92)
+ goto state_37;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_35;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_35;
+ if (ch.unicode() >= 123)
+ goto state_35;
+ goto out;
+ state_67:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_35;
+ if (ch.unicode() == 10)
+ goto state_80;
+ if (ch.unicode() == 11)
+ goto state_35;
+ if (ch.unicode() >= 14 && ch.unicode() <= 38)
+ goto state_35;
+ if (ch.unicode() == 39)
+ goto state_36;
+ if (ch.unicode() >= 40 && ch.unicode() <= 91)
+ goto state_35;
+ if (ch.unicode() == 92)
+ goto state_37;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_35;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_35;
+ if (ch.unicode() >= 123)
+ goto state_35;
+ goto out;
+ state_69:
+ lastAcceptingPos = pos;
+ token = QCss::NUMBER;
+ ch = next();
+ if (ch.unicode() == 37)
+ goto state_41;
+ if (ch.unicode() == 45)
+ goto state_42;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_69;
+ if (ch.unicode() == 92)
+ goto state_45;
+ if (ch.unicode() == 95)
+ goto state_46;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_46;
+ goto out;
+ state_70:
+ lastAcceptingPos = pos;
+ token = QCss::LENGTH;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_71;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_71;
+ if (ch.unicode() == 92)
+ goto state_72;
+ if (ch.unicode() == 95)
+ goto state_71;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_71;
+ goto out;
+ state_71:
+ lastAcceptingPos = pos;
+ token = QCss::LENGTH;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_71;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_71;
+ if (ch.unicode() == 92)
+ goto state_72;
+ if (ch.unicode() == 95)
+ goto state_71;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_71;
+ goto out;
+ state_72:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_81;
+ if (ch.unicode() == 11)
+ goto state_81;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_81;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_81;
+ if (ch.unicode() >= 103)
+ goto state_81;
+ goto out;
+ state_73:
+ ch = next();
+ if (ch.unicode() == 45) {
+ token = QCss::CDO;
+ goto found;
+ }
+ goto out;
+ state_74:
+ lastAcceptingPos = pos;
+ token = QCss::ATKEYWORD_SYM;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_75;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_75;
+ if (ch.unicode() == 92)
+ goto state_76;
+ if (ch.unicode() == 95)
+ goto state_75;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_75;
+ goto out;
+ state_75:
+ lastAcceptingPos = pos;
+ token = QCss::ATKEYWORD_SYM;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_75;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_75;
+ if (ch.unicode() == 92)
+ goto state_76;
+ if (ch.unicode() == 95)
+ goto state_75;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_75;
+ goto out;
+ state_76:
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_83;
+ if (ch.unicode() == 11)
+ goto state_83;
+ if (ch.unicode() >= 14 && ch.unicode() <= 47)
+ goto state_83;
+ if (ch.unicode() >= 58 && ch.unicode() <= 96)
+ goto state_83;
+ if (ch.unicode() >= 103)
+ goto state_83;
+ goto out;
+ state_77:
+ lastAcceptingPos = pos;
+ token = QCss::IDENT;
+ ch = next();
+ if (ch.unicode() == 40)
+ goto state_52;
+ if (ch.unicode() == 45)
+ goto state_53;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_53;
+ if (ch.unicode() == 92)
+ goto state_54;
+ if (ch.unicode() == 95)
+ goto state_53;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_53;
+ goto out;
+ state_78:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_30;
+ if (ch.unicode() == 11)
+ goto state_30;
+ if (ch.unicode() >= 14 && ch.unicode() <= 33)
+ goto state_30;
+ if (ch.unicode() == 34)
+ goto state_31;
+ if (ch.unicode() >= 35 && ch.unicode() <= 91)
+ goto state_30;
+ if (ch.unicode() == 92)
+ goto state_32;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_30;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_30;
+ if (ch.unicode() >= 123)
+ goto state_30;
+ goto out;
+ state_79:
+ lastAcceptingPos = pos;
+ token = QCss::HASH;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_61;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_61;
+ if (ch.unicode() == 92)
+ goto state_62;
+ if (ch.unicode() == 95)
+ goto state_61;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_61;
+ goto out;
+ state_80:
+ lastAcceptingPos = pos;
+ token = QCss::INVALID;
+ ch = next();
+ if (ch.unicode() >= 1 && ch.unicode() <= 9)
+ goto state_35;
+ if (ch.unicode() == 11)
+ goto state_35;
+ if (ch.unicode() >= 14 && ch.unicode() <= 38)
+ goto state_35;
+ if (ch.unicode() == 39)
+ goto state_36;
+ if (ch.unicode() >= 40 && ch.unicode() <= 91)
+ goto state_35;
+ if (ch.unicode() == 92)
+ goto state_37;
+ if (ch.unicode() >= 93 && ch.unicode() <= 96)
+ goto state_35;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_35;
+ if (ch.unicode() >= 123)
+ goto state_35;
+ goto out;
+ state_81:
+ lastAcceptingPos = pos;
+ token = QCss::LENGTH;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_71;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_71;
+ if (ch.unicode() == 92)
+ goto state_72;
+ if (ch.unicode() == 95)
+ goto state_71;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_71;
+ goto out;
+ state_83:
+ lastAcceptingPos = pos;
+ token = QCss::ATKEYWORD_SYM;
+ ch = next();
+ if (ch.unicode() == 45)
+ goto state_75;
+ if (ch.unicode() >= 48 && ch.unicode() <= 57)
+ goto state_75;
+ if (ch.unicode() == 92)
+ goto state_76;
+ if (ch.unicode() == 95)
+ goto state_75;
+ if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') || (ch.unicode() >= 'A' && ch.unicode() <= 'Z') || ch.unicode() >= 256)
+ goto state_75;
+ goto out;
+ found:
+ lastAcceptingPos = pos;
+
+ out:
+ if (lastAcceptingPos != -1) {
+ lexemLength = lastAcceptingPos - lexemStart;
+ pos = lastAcceptingPos;
+ }
+ return token;
+}
+
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
new file mode 100644
index 0000000000..b8cfb1f902
--- /dev/null
+++ b/src/gui/text/qfont.cpp
@@ -0,0 +1,3188 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qfont.h"
+#include "qdebug.h"
+#include "qpaintdevice.h"
+#include "qfontdatabase.h"
+#include "qfontmetrics.h"
+#include "qfontinfo.h"
+#include "qpainter.h"
+#include "qhash.h"
+#include "qdatastream.h"
+#include "qapplication.h"
+#include "qstringlist.h"
+
+#include "qthread.h"
+#include "qthreadstorage.h"
+
+#include <private/qunicodetables_p.h>
+#include "qfont_p.h"
+#include <private/qfontengine_p.h>
+#include <private/qpainter_p.h>
+#include <private/qtextengine_p.h>
+#include <limits.h>
+
+#ifdef Q_WS_X11
+#include "qx11info_x11.h"
+#include <private/qt_x11_p.h>
+#endif
+#ifdef Q_WS_QWS
+#include "qscreen_qws.h"
+#if !defined(QT_NO_QWS_QPF2)
+#include <qfile.h>
+#include "qfontengine_qpf_p.h"
+#endif
+#endif
+#ifdef Q_OS_SYMBIAN
+#include <private/qt_s60_p.h>
+#endif
+#ifdef Q_WS_QPA
+#include <QtGui/qplatformscreen_qpa.h>
+#include <QtGui/private/qapplication_p.h>
+#endif
+
+#include <QMutexLocker>
+
+// #define QFONTCACHE_DEBUG
+#ifdef QFONTCACHE_DEBUG
+# define FC_DEBUG qDebug
+#else
+# define FC_DEBUG if (false) qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_WS_WIN
+extern HDC shared_dc();
+#endif
+
+#ifdef Q_WS_X11
+extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
+#endif
+
+bool QFontDef::exactMatch(const QFontDef &other) const
+{
+ /*
+ QFontDef comparison is more complicated than just simple
+ per-member comparisons.
+
+ When comparing point/pixel sizes, either point or pixelsize
+ could be -1. in This case we have to compare the non negative
+ size value.
+
+ This test will fail if the point-sizes differ by 1/2 point or
+ more or they do not round to the same value. We have to do this
+ since our API still uses 'int' point-sizes in the API, but store
+ deci-point-sizes internally.
+
+ To compare the family members, we need to parse the font names
+ and compare the family/foundry strings separately. This allows
+ us to compare e.g. "Helvetica" and "Helvetica [Adobe]" with
+ positive results.
+ */
+ if (pixelSize != -1 && other.pixelSize != -1) {
+ if (pixelSize != other.pixelSize)
+ return false;
+ } else if (pointSize != -1 && other.pointSize != -1) {
+ if (pointSize != other.pointSize)
+ return false;
+ } else {
+ return false;
+ }
+
+ if (!ignorePitch && !other.ignorePitch && fixedPitch != other.fixedPitch)
+ return false;
+
+ if (stretch != 0 && other.stretch != 0 && stretch != other.stretch)
+ return false;
+
+ QString this_family, this_foundry, other_family, other_foundry;
+ QFontDatabase::parseFontName(family, this_foundry, this_family);
+ QFontDatabase::parseFontName(other.family, other_foundry, other_family);
+
+ this_family = QFontDatabase::resolveFontFamilyAlias(this_family);
+ other_family = QFontDatabase::resolveFontFamilyAlias(other_family);
+
+ return (styleHint == other.styleHint
+ && styleStrategy == other.styleStrategy
+ && weight == other.weight
+ && style == other.style
+ && this_family == other_family
+ && (this_foundry.isEmpty()
+ || other_foundry.isEmpty()
+ || this_foundry == other_foundry)
+#ifdef Q_WS_X11
+ && addStyle == other.addStyle
+#endif // Q_WS_X11
+ );
+}
+
+extern bool qt_is_gui_used;
+
+Q_GUI_EXPORT int qt_defaultDpiX()
+{
+ if (!qt_is_gui_used)
+ return 75;
+
+ int dpi;
+#ifdef Q_WS_X11
+ dpi = QX11Info::appDpiX();
+#elif defined(Q_WS_WIN)
+ dpi = GetDeviceCaps(shared_dc(),LOGPIXELSX);
+#elif defined(Q_WS_MAC)
+ extern float qt_mac_defaultDpi_x(); //qpaintdevice_mac.cpp
+ dpi = qt_mac_defaultDpi_x();
+#elif defined(Q_WS_QWS)
+ if (!qt_screen)
+ return 72;
+ QScreen *screen = qt_screen;
+ const QList<QScreen*> subScreens = qt_screen->subScreens();
+ if (!subScreens.isEmpty())
+ screen = subScreens.at(0);
+ dpi = qRound(screen->width() / (screen->physicalWidth() / qreal(25.4)));
+#elif defined(Q_WS_QPA)
+ QPlatformIntegration *pi = QApplicationPrivate::platformIntegration();
+ if (pi) {
+ QPlatformScreen *screen = QApplicationPrivate::platformIntegration()->screens().at(0);
+ const QSize screenSize = screen->geometry().size();
+ const QSize physicalSize = screen->physicalSize();
+ dpi = qRound(screenSize.width() / (physicalSize.width() / qreal(25.4)));
+ } else {
+ //PI has not been initialised, or it is being initialised. Give a default dpi
+ dpi = 100;
+ }
+#elif defined(Q_OS_SYMBIAN)
+ dpi = S60->defaultDpiX;
+#endif // Q_WS_X11
+
+ return dpi;
+}
+
+Q_GUI_EXPORT int qt_defaultDpiY()
+{
+ if (!qt_is_gui_used)
+ return 75;
+
+ int dpi;
+#ifdef Q_WS_X11
+ dpi = QX11Info::appDpiY();
+#elif defined(Q_WS_WIN)
+ dpi = GetDeviceCaps(shared_dc(),LOGPIXELSY);
+#elif defined(Q_WS_MAC)
+ extern float qt_mac_defaultDpi_y(); //qpaintdevice_mac.cpp
+ dpi = qt_mac_defaultDpi_y();
+#elif defined(Q_WS_QWS)
+ if (!qt_screen)
+ return 72;
+ QScreen *screen = qt_screen;
+ const QList<QScreen*> subScreens = qt_screen->subScreens();
+ if (!subScreens.isEmpty())
+ screen = subScreens.at(0);
+ dpi = qRound(screen->height() / (screen->physicalHeight() / qreal(25.4)));
+#elif defined(Q_WS_QPA)
+ QPlatformIntegration *pi = QApplicationPrivate::platformIntegration();
+ if (pi) {
+ QPlatformScreen *screen = QApplicationPrivate::platformIntegration()->screens().at(0);
+ const QSize screenSize = screen->geometry().size();
+ const QSize physicalSize = screen->physicalSize();
+ dpi = qRound(screenSize.height() / (physicalSize.height() / qreal(25.4)));
+ } else {
+ //PI has not been initialised, or it is being initialised. Give a default dpi
+ dpi = 100;
+ }
+#elif defined(Q_OS_SYMBIAN)
+ dpi = S60->defaultDpiY;
+#endif // Q_WS_X11
+
+ return dpi;
+}
+
+Q_GUI_EXPORT int qt_defaultDpi()
+{
+ return qt_defaultDpiY();
+}
+
+QFontPrivate::QFontPrivate()
+ : engineData(0), dpi(qt_defaultDpi()), screen(0),
+ rawMode(false), underline(false), overline(false), strikeOut(false), kerning(true),
+ capital(0), letterSpacingIsAbsolute(false), scFont(0)
+{
+#ifdef Q_WS_X11
+ if (QX11Info::display())
+ screen = QX11Info::appScreen();
+ else
+ screen = 0;
+#endif
+#ifdef Q_WS_WIN
+ hdc = 0;
+#endif
+}
+
+QFontPrivate::QFontPrivate(const QFontPrivate &other)
+ : request(other.request), engineData(0), dpi(other.dpi), screen(other.screen),
+ rawMode(other.rawMode), underline(other.underline), overline(other.overline),
+ strikeOut(other.strikeOut), kerning(other.kerning),
+ capital(other.capital), letterSpacingIsAbsolute(other.letterSpacingIsAbsolute),
+ letterSpacing(other.letterSpacing), wordSpacing(other.wordSpacing),
+ scFont(other.scFont)
+{
+#ifdef Q_WS_WIN
+ hdc = other.hdc;
+#endif
+ if (scFont && scFont != this)
+ scFont->ref.ref();
+}
+
+QFontPrivate::~QFontPrivate()
+{
+ if (engineData)
+ engineData->ref.deref();
+ engineData = 0;
+ if (scFont && scFont != this)
+ scFont->ref.deref();
+ scFont = 0;
+}
+
+extern QMutex *qt_fontdatabase_mutex();
+
+#if !defined(Q_WS_MAC)
+#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engines[script]
+#else
+#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engine
+#endif
+
+QFontEngine *QFontPrivate::engineForScript(int script) const
+{
+ QMutexLocker locker(qt_fontdatabase_mutex());
+ if (script >= QUnicodeTables::Inherited)
+ script = QUnicodeTables::Common;
+ if (engineData && engineData->fontCache != QFontCache::instance()) {
+ // throw out engineData that came from a different thread
+ engineData->ref.deref();
+ engineData = 0;
+ }
+ if (!engineData || !QT_FONT_ENGINE_FROM_DATA(engineData, script))
+ QFontDatabase::load(this, script);
+ return QT_FONT_ENGINE_FROM_DATA(engineData, script);
+}
+
+void QFontPrivate::alterCharForCapitalization(QChar &c) const {
+ switch (capital) {
+ case QFont::AllUppercase:
+ case QFont::SmallCaps:
+ c = c.toUpper();
+ break;
+ case QFont::AllLowercase:
+ c = c.toLower();
+ break;
+ case QFont::MixedCase:
+ break;
+ }
+}
+
+QFontPrivate *QFontPrivate::smallCapsFontPrivate() const
+{
+ if (scFont)
+ return scFont;
+ QFont font(const_cast<QFontPrivate *>(this));
+ qreal pointSize = font.pointSizeF();
+ if (pointSize > 0)
+ font.setPointSizeF(pointSize * .7);
+ else
+ font.setPixelSize((font.pixelSize() * 7 + 5) / 10);
+ scFont = font.d.data();
+ if (scFont != this)
+ scFont->ref.ref();
+ return scFont;
+}
+
+
+void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
+{
+ Q_ASSERT(other != 0);
+
+ dpi = other->dpi;
+
+ if ((mask & QFont::AllPropertiesResolved) == QFont::AllPropertiesResolved) return;
+
+ // assign the unset-bits with the set-bits of the other font def
+ if (! (mask & QFont::FamilyResolved))
+ request.family = other->request.family;
+
+ if (! (mask & QFont::SizeResolved)) {
+ request.pointSize = other->request.pointSize;
+ request.pixelSize = other->request.pixelSize;
+ }
+
+ if (! (mask & QFont::StyleHintResolved))
+ request.styleHint = other->request.styleHint;
+
+ if (! (mask & QFont::StyleStrategyResolved))
+ request.styleStrategy = other->request.styleStrategy;
+
+ if (! (mask & QFont::WeightResolved))
+ request.weight = other->request.weight;
+
+ if (! (mask & QFont::StyleResolved))
+ request.style = other->request.style;
+
+ if (! (mask & QFont::FixedPitchResolved))
+ request.fixedPitch = other->request.fixedPitch;
+
+ if (! (mask & QFont::StretchResolved))
+ request.stretch = other->request.stretch;
+
+ if (! (mask & QFont::HintingPreferenceResolved))
+ request.hintingPreference = other->request.hintingPreference;
+
+ if (! (mask & QFont::UnderlineResolved))
+ underline = other->underline;
+
+ if (! (mask & QFont::OverlineResolved))
+ overline = other->overline;
+
+ if (! (mask & QFont::StrikeOutResolved))
+ strikeOut = other->strikeOut;
+
+ if (! (mask & QFont::KerningResolved))
+ kerning = other->kerning;
+
+ if (! (mask & QFont::LetterSpacingResolved)) {
+ letterSpacing = other->letterSpacing;
+ letterSpacingIsAbsolute = other->letterSpacingIsAbsolute;
+ }
+ if (! (mask & QFont::WordSpacingResolved))
+ wordSpacing = other->wordSpacing;
+ if (! (mask & QFont::CapitalizationResolved))
+ capital = other->capital;
+}
+
+
+
+
+QFontEngineData::QFontEngineData()
+ : ref(1), fontCache(QFontCache::instance())
+{
+#if !defined(Q_WS_MAC)
+ memset(engines, 0, QUnicodeTables::ScriptCount * sizeof(QFontEngine *));
+#else
+ engine = 0;
+#endif
+}
+
+QFontEngineData::~QFontEngineData()
+{
+#if !defined(Q_WS_MAC)
+ for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
+ if (engines[i])
+ engines[i]->ref.deref();
+ engines[i] = 0;
+ }
+#else
+ if (engine)
+ engine->ref.deref();
+ engine = 0;
+#endif // Q_WS_X11 || Q_WS_WIN || Q_WS_MAC
+}
+
+
+
+
+/*!
+ \class QFont
+ \reentrant
+
+ \brief The QFont class specifies a font used for drawing text.
+
+ \ingroup painting
+ \ingroup appearance
+ \ingroup shared
+ \ingroup richtext-processing
+
+
+ When you create a QFont object you specify various attributes that
+ you want the font to have. Qt will use the font with the specified
+ attributes, or if no matching font exists, Qt will use the closest
+ matching installed font. The attributes of the font that is
+ actually used are retrievable from a QFontInfo object. If the
+ window system provides an exact match exactMatch() returns true.
+ Use QFontMetrics to get measurements, e.g. the pixel length of a
+ string using QFontMetrics::width().
+
+ Note that a QApplication instance must exist before a QFont can be
+ used. You can set the application's default font with
+ QApplication::setFont().
+
+ If a chosen font does not include all the characters that
+ need to be displayed, QFont will try to find the characters in the
+ nearest equivalent fonts. When a QPainter draws a character from a
+ font the QFont will report whether or not it has the character; if
+ it does not, QPainter will draw an unfilled square.
+
+ Create QFonts like this:
+
+ \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 0
+
+ The attributes set in the constructor can also be set later, e.g.
+ setFamily(), setPointSize(), setPointSizeFloat(), setWeight() and
+ setItalic(). The remaining attributes must be set after
+ contstruction, e.g. setBold(), setUnderline(), setOverline(),
+ setStrikeOut() and setFixedPitch(). QFontInfo objects should be
+ created \e after the font's attributes have been set. A QFontInfo
+ object will not change, even if you change the font's
+ attributes. The corresponding "get" functions, e.g. family(),
+ pointSize(), etc., return the values that were set, even though
+ the values used may differ. The actual values are available from a
+ QFontInfo object.
+
+ If the requested font family is unavailable you can influence the
+ \link #fontmatching font matching algorithm\endlink by choosing a
+ particular \l{QFont::StyleHint} and \l{QFont::StyleStrategy} with
+ setStyleHint(). The default family (corresponding to the current
+ style hint) is returned by defaultFamily().
+
+ The font-matching algorithm has a lastResortFamily() and
+ lastResortFont() in cases where a suitable match cannot be found.
+ You can provide substitutions for font family names using
+ insertSubstitution() and insertSubstitutions(). Substitutions can
+ be removed with removeSubstitution(). Use substitute() to retrieve
+ a family's first substitute, or the family name itself if it has
+ no substitutes. Use substitutes() to retrieve a list of a family's
+ substitutes (which may be empty).
+
+ Every QFont has a key() which you can use, for example, as the key
+ in a cache or dictionary. If you want to store a user's font
+ preferences you could use QSettings, writing the font information
+ with toString() and reading it back with fromString(). The
+ operator<<() and operator>>() functions are also available, but
+ they work on a data stream.
+
+ It is possible to set the height of characters shown on the screen
+ to a specified number of pixels with setPixelSize(); however using
+ setPointSize() has a similar effect and provides device
+ independence.
+
+ In X11 you can set a font using its system
+ specific name with setRawName().
+
+ Loading fonts can be expensive, especially on X11. QFont contains
+ extensive optimizations to make the copying of QFont objects fast,
+ and to cache the results of the slow window system functions it
+ depends upon.
+
+ \target fontmatching
+ The font matching algorithm works as follows:
+ \list 1
+ \o The specified font family is searched for.
+ \o If not found, the styleHint() is used to select a replacement
+ family.
+ \o Each replacement font family is searched for.
+ \o If none of these are found or there was no styleHint(), "helvetica"
+ will be searched for.
+ \o If "helvetica" isn't found Qt will try the lastResortFamily().
+ \o If the lastResortFamily() isn't found Qt will try the
+ lastResortFont() which will always return a name of some kind.
+ \endlist
+
+ Note that the actual font matching algorithm varies from platform to platform.
+
+ In Windows a request for the "Courier" font is automatically changed to
+ "Courier New", an improved version of Courier that allows for smooth scaling.
+ The older "Courier" bitmap font can be selected by setting the PreferBitmap
+ style strategy (see setStyleStrategy()).
+
+ Once a font is found, the remaining attributes are matched in order of
+ priority:
+ \list 1
+ \o fixedPitch()
+ \o pointSize() (see below)
+ \o weight()
+ \o style()
+ \endlist
+
+ If you have a font which matches on family, even if none of the
+ other attributes match, this font will be chosen in preference to
+ a font which doesn't match on family but which does match on the
+ other attributes. This is because font family is the dominant
+ search criteria.
+
+ The point size is defined to match if it is within 20% of the
+ requested point size. When several fonts match and are only
+ distinguished by point size, the font with the closest point size
+ to the one requested will be chosen.
+
+ The actual family, font size, weight and other font attributes
+ used for drawing text will depend on what's available for the
+ chosen family under the window system. A QFontInfo object can be
+ used to determine the actual values used for drawing the text.
+
+ Examples:
+
+ \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 1
+ If you had both an Adobe and a Cronyx Helvetica, you might get
+ either.
+
+ \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 2
+
+ You can specify the foundry you want in the family name. The font f
+ in the above example will be set to "Helvetica
+ [Cronyx]".
+
+ To determine the attributes of the font actually used in the window
+ system, use a QFontInfo object, e.g.
+
+ \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 3
+
+ To find out font metrics use a QFontMetrics object, e.g.
+
+ \snippet doc/src/snippets/code/src_gui_text_qfont.cpp 4
+
+ For more general information on fonts, see the
+ \link http://nwalsh.com/comp.fonts/FAQ/ comp.fonts FAQ.\endlink
+ Information on encodings can be found from
+ \link http://czyborra.com/ Roman Czyborra's\endlink page.
+
+ \sa QFontComboBox, QFontMetrics, QFontInfo, QFontDatabase, {Character Map Example}
+*/
+
+/*!
+ \internal
+ \enum QFont::ResolveProperties
+
+ This enum describes the properties of a QFont that can be set on a font
+ individually and then considered resolved.
+
+ \value FamilyResolved
+ \value SizeResolved
+ \value StyleHintResolved
+ \value StyleStrategyResolved
+ \value WeightResolved
+ \value StyleResolved
+ \value UnderlineResolved
+ \value OverlineResolved
+ \value StrikeOutResolved
+ \value FixedPitchResolved
+ \value StretchResolved
+ \value KerningResolved
+ \value CapitalizationResolved
+ \value LetterSpacingResolved
+ \value WordSpacingResolved
+ \value CompletelyResolved
+*/
+
+/*!
+ \enum QFont::Style
+
+ This enum describes the different styles of glyphs that are used to
+ display text.
+
+ \value StyleNormal Normal glyphs used in unstyled text.
+ \value StyleItalic Italic glyphs that are specifically designed for
+ the purpose of representing italicized text.
+ \value StyleOblique Glyphs with an italic appearance that are typically
+ based on the unstyled glyphs, but are not fine-tuned
+ for the purpose of representing italicized text.
+
+ \sa Weight
+*/
+
+/*!
+ \fn Qt::HANDLE QFont::handle() const
+
+ Returns the window system handle to the font, for low-level
+ access. Using this function is \e not portable.
+*/
+
+/*!
+ \fn FT_Face QFont::freetypeFace() const
+
+ Returns the handle to the primary FreeType face of the font. If font merging is not disabled a
+ QFont can contain several physical fonts.
+
+ Returns 0 if the font does not contain a FreeType face.
+
+ \note This function is only available on platforms that provide the FreeType library;
+ i.e., X11 and some Embedded Linux platforms.
+*/
+
+/*!
+ \fn QString QFont::rawName() const
+
+ Returns the name of the font within the underlying window system.
+
+ On X11, this function will return an empty string if Qt is built with
+ FontConfig support; otherwise the XLFD (X Logical Font Description) is
+ returned.
+
+ Using the return value of this function is usually \e not \e
+ portable.
+
+ \sa setRawName()
+*/
+
+/*!
+ \fn void QFont::setRawName(const QString &name)
+
+ Sets a font by its system specific name. The function is
+ particularly useful under X, where system font settings (for
+ example X resources) are usually available in XLFD (X Logical Font
+ Description) form only. You can pass an XLFD as \a name to this
+ function.
+
+ A font set with setRawName() is still a full-featured QFont. It can
+ be queried (for example with italic()) or modified (for example with
+ setItalic()) and is therefore also suitable for rendering rich text.
+
+ If Qt's internal font database cannot resolve the raw name, the
+ font becomes a raw font with \a name as its family.
+
+ Note that the present implementation does not handle wildcards in
+ XLFDs well, and that font aliases (file \c fonts.alias in the font
+ directory on X11) are not supported.
+
+ \sa rawName(), setRawMode(), setFamily()
+*/
+
+/*!
+ \fn QString QFont::lastResortFamily() const
+
+ Returns the "last resort" font family name.
+
+ The current implementation tries a wide variety of common fonts,
+ returning the first one it finds. Is is possible that no family is
+ found in which case an empty string is returned.
+
+ \sa lastResortFont()
+*/
+
+/*!
+ \fn QString QFont::defaultFamily() const
+
+ Returns the family name that corresponds to the current style
+ hint.
+
+ \sa StyleHint styleHint() setStyleHint()
+*/
+
+/*!
+ \fn QString QFont::lastResortFont() const
+
+ Returns a "last resort" font name for the font matching algorithm.
+ This is used if the last resort family is not available. It will
+ always return a name, if necessary returning something like
+ "fixed" or "system".
+
+ The current implementation tries a wide variety of common fonts,
+ returning the first one it finds. The implementation may change
+ at any time, but this function will always return a string
+ containing something.
+
+ It is theoretically possible that there really isn't a
+ lastResortFont() in which case Qt will abort with an error
+ message. We have not been able to identify a case where this
+ happens. Please \link bughowto.html report it as a bug\endlink if
+ it does, preferably with a list of the fonts you have installed.
+
+ \sa lastResortFamily() rawName()
+*/
+
+/*!
+ Constructs a font from \a font for use on the paint device \a pd.
+*/
+QFont::QFont(const QFont &font, QPaintDevice *pd)
+ : resolve_mask(font.resolve_mask)
+{
+ Q_ASSERT(pd != 0);
+ int dpi = pd->logicalDpiY();
+#ifdef Q_WS_X11
+ const QX11Info *info = qt_x11Info(pd);
+ int screen = info ? info->screen() : 0;
+#else
+ const int screen = 0;
+#endif
+ if (font.d->dpi != dpi || font.d->screen != screen ) {
+ d = new QFontPrivate(*font.d);
+ d->dpi = dpi;
+ d->screen = screen;
+ } else {
+ d = font.d.data();
+ }
+#ifdef Q_WS_WIN
+ if (pd->devType() == QInternal::Printer && pd->getDC())
+ d->hdc = pd->getDC();
+#endif
+}
+
+/*!
+ \internal
+*/
+QFont::QFont(QFontPrivate *data)
+ : d(data), resolve_mask(QFont::AllPropertiesResolved)
+{
+}
+
+/*! \internal
+ Detaches the font object from common font data.
+*/
+void QFont::detach()
+{
+ if (d->ref == 1) {
+ if (d->engineData)
+ d->engineData->ref.deref();
+ d->engineData = 0;
+ if (d->scFont && d->scFont != d.data())
+ d->scFont->ref.deref();
+ d->scFont = 0;
+ return;
+ }
+
+ d.detach();
+}
+
+/*!
+ Constructs a font object that uses the application's default font.
+
+ \sa QApplication::setFont(), QApplication::font()
+*/
+QFont::QFont()
+ : d(QApplication::font().d.data()), resolve_mask(0)
+{
+}
+
+/*!
+ Constructs a font object with the specified \a family, \a
+ pointSize, \a weight and \a italic settings.
+
+ If \a pointSize is zero or negative, the point size of the font
+ is set to a system-dependent default value. Generally, this is
+ 12 points, except on Symbian where it is 7 points.
+
+ The \a family name may optionally also include a foundry name,
+ e.g. "Helvetica [Cronyx]". If the \a family is
+ available from more than one foundry and the foundry isn't
+ specified, an arbitrary foundry is chosen. If the family isn't
+ available a family will be set using the \l{QFont}{font matching}
+ algorithm.
+
+ \sa Weight, setFamily(), setPointSize(), setWeight(), setItalic(),
+ setStyleHint() QApplication::font()
+*/
+QFont::QFont(const QString &family, int pointSize, int weight, bool italic)
+ : d(new QFontPrivate()), resolve_mask(QFont::FamilyResolved)
+{
+ if (pointSize <= 0) {
+#ifdef Q_OS_SYMBIAN
+ pointSize = 7;
+#else
+ pointSize = 12;
+#endif
+ } else {
+ resolve_mask |= QFont::SizeResolved;
+ }
+
+ if (weight < 0) {
+ weight = Normal;
+ } else {
+ resolve_mask |= QFont::WeightResolved | QFont::StyleResolved;
+ }
+
+ if (italic)
+ resolve_mask |= QFont::StyleResolved;
+
+ d->request.family = family;
+ d->request.pointSize = qreal(pointSize);
+ d->request.pixelSize = -1;
+ d->request.weight = weight;
+ d->request.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
+}
+
+/*!
+ Constructs a font that is a copy of \a font.
+*/
+QFont::QFont(const QFont &font)
+ : d(font.d.data()), resolve_mask(font.resolve_mask)
+{
+}
+
+/*!
+ Destroys the font object and frees all allocated resources.
+*/
+QFont::~QFont()
+{
+}
+
+/*!
+ Assigns \a font to this font and returns a reference to it.
+*/
+QFont &QFont::operator=(const QFont &font)
+{
+ d = font.d.data();
+ resolve_mask = font.resolve_mask;
+ return *this;
+}
+
+/*!
+ Returns the requested font family name, i.e. the name set in the
+ constructor or the last setFont() call.
+
+ \sa setFamily() substitutes() substitute()
+*/
+QString QFont::family() const
+{
+ return d->request.family;
+}
+
+/*!
+ Sets the family name of the font. The name is case insensitive and
+ may include a foundry name.
+
+ The \a family name may optionally also include a foundry name,
+ e.g. "Helvetica [Cronyx]". If the \a family is
+ available from more than one foundry and the foundry isn't
+ specified, an arbitrary foundry is chosen. If the family isn't
+ available a family will be set using the \l{QFont}{font matching}
+ algorithm.
+
+ \sa family(), setStyleHint(), QFontInfo
+*/
+void QFont::setFamily(const QString &family)
+{
+ detach();
+
+ d->request.family = family;
+#if defined(Q_WS_X11)
+ d->request.addStyle.clear();
+#endif // Q_WS_X11
+
+ resolve_mask |= QFont::FamilyResolved;
+}
+
+/*!
+ Returns the point size of the font. Returns -1 if the font size
+ was specified in pixels.
+
+ \sa setPointSize() pointSizeF()
+*/
+int QFont::pointSize() const
+{
+ return qRound(d->request.pointSize);
+}
+
+/*!
+ \since 4.8
+
+ \enum QFont::HintingPreference
+
+ This enum describes the different levels of hinting that can be applied
+ to glyphs to improve legibility on displays where it might be warranted
+ by the density of pixels.
+
+ \value PreferDefaultHinting Use the default hinting level for the target platform.
+ \value PreferNoHinting If possible, render text without hinting the outlines
+ of the glyphs. The text layout will be typographically accurate and
+ scalable, using the same metrics as are used e.g. when printing.
+ \value PreferVerticalHinting If possible, render text with no horizontal hinting,
+ but align glyphs to the pixel grid in the vertical direction. The text will appear
+ crisper on displays where the density is too low to give an accurate rendering
+ of the glyphs. But since the horizontal metrics of the glyphs are unhinted, the text's
+ layout will be scalable to higher density devices (such as printers) without impacting
+ details such as line breaks.
+ \value PreferFullHinting If possible, render text with hinting in both horizontal and
+ vertical directions. The text will be altered to optimize legibility on the target
+ device, but since the metrics will depend on the target size of the text, the positions
+ of glyphs, line breaks, and other typographical detail will not scale, meaning that a
+ text layout may look different on devices with different pixel densities.
+
+ Please note that this enum only describes a preference, as the full range of hinting levels
+ are not supported on all of Qt's supported platforms. The following table details the effect
+ of a given hinting preference on a selected set of target platforms.
+
+ \table
+ \header
+ \o
+ \o PreferDefaultHinting
+ \o PreferNoHinting
+ \o PreferVerticalHinting
+ \o PreferFullHinting
+ \row
+ \o Windows Vista (w/o Platform Update) and earlier
+ \o Full hinting
+ \o Full hinting
+ \o Full hinting
+ \o Full hinting
+ \row
+ \o Windows 7 and Windows Vista (w/Platform Update) and DirectWrite enabled in Qt
+ \o Full hinting
+ \o Vertical hinting
+ \o Vertical hinting
+ \o Full hinting
+ \row
+ \o FreeType
+ \o Operating System setting
+ \o No hinting
+ \o Vertical hinting (light)
+ \o Full hinting
+ \row
+ \o Cocoa on Mac OS X
+ \o No hinting
+ \o No hinting
+ \o No hinting
+ \o No hinting
+ \endtable
+
+ \note Please be aware that altering the hinting preference on Windows is available through
+ the DirectWrite font engine. This is available on Windows Vista after installing the platform
+ update, and on Windows 7. In order to use this extension, configure Qt using -directwrite.
+ The target application will then depend on the availability of DirectWrite on the target
+ system.
+
+*/
+
+/*!
+ \since 4.8
+
+ Set the preference for the hinting level of the glyphs to \a hintingPreference. This is a hint
+ to the underlying font rendering system to use a certain level of hinting, and has varying
+ support across platforms. See the table in the documentation for QFont::HintingPreference for
+ more details.
+
+ The default hinting preference is QFont::PreferDefaultHinting.
+*/
+void QFont::setHintingPreference(HintingPreference hintingPreference)
+{
+ detach();
+
+ d->request.hintingPreference = hintingPreference;
+
+ resolve_mask |= QFont::HintingPreferenceResolved;
+}
+
+/*!
+ \since 4.8
+
+ Returns the currently preferred hinting level for glyphs rendered with this font.
+*/
+QFont::HintingPreference QFont::hintingPreference() const
+{
+ return QFont::HintingPreference(d->request.hintingPreference);
+}
+
+/*!
+ Sets the point size to \a pointSize. The point size must be
+ greater than zero.
+
+ \sa pointSize() setPointSizeF()
+*/
+void QFont::setPointSize(int pointSize)
+{
+ if (pointSize <= 0) {
+ qWarning("QFont::setPointSize: Point size <= 0 (%d), must be greater than 0", pointSize);
+ return;
+ }
+
+ detach();
+
+ d->request.pointSize = qreal(pointSize);
+ d->request.pixelSize = -1;
+
+ resolve_mask |= QFont::SizeResolved;
+}
+
+/*!
+ Sets the point size to \a pointSize. The point size must be
+ greater than zero. The requested precision may not be achieved on
+ all platforms.
+
+ \sa pointSizeF() setPointSize() setPixelSize()
+*/
+void QFont::setPointSizeF(qreal pointSize)
+{
+ if (pointSize <= 0) {
+ qWarning("QFont::setPointSizeF: Point size <= 0 (%f), must be greater than 0", pointSize);
+ return;
+ }
+
+ detach();
+
+ d->request.pointSize = pointSize;
+ d->request.pixelSize = -1;
+
+ resolve_mask |= QFont::SizeResolved;
+}
+
+/*!
+ Returns the point size of the font. Returns -1 if the font size was
+ specified in pixels.
+
+ \sa pointSize() setPointSizeF() pixelSize() QFontInfo::pointSize() QFontInfo::pixelSize()
+*/
+qreal QFont::pointSizeF() const
+{
+ return d->request.pointSize;
+}
+
+/*!
+ Sets the font size to \a pixelSize pixels.
+
+ Using this function makes the font device dependent. Use
+ setPointSize() or setPointSizeF() to set the size of the font
+ in a device independent manner.
+
+ \sa pixelSize()
+*/
+void QFont::setPixelSize(int pixelSize)
+{
+ if (pixelSize <= 0) {
+ qWarning("QFont::setPixelSize: Pixel size <= 0 (%d)", pixelSize);
+ return;
+ }
+
+ detach();
+
+ d->request.pixelSize = pixelSize;
+ d->request.pointSize = -1;
+
+ resolve_mask |= QFont::SizeResolved;
+}
+
+/*!
+ Returns the pixel size of the font if it was set with
+ setPixelSize(). Returns -1 if the size was set with setPointSize()
+ or setPointSizeF().
+
+ \sa setPixelSize() pointSize() QFontInfo::pointSize() QFontInfo::pixelSize()
+*/
+int QFont::pixelSize() const
+{
+ return d->request.pixelSize;
+}
+
+#ifdef QT3_SUPPORT
+/*! \obsolete
+
+ Sets the logical pixel height of font characters when shown on
+ the screen to \a pixelSize.
+*/
+void QFont::setPixelSizeFloat(qreal pixelSize)
+{
+ setPixelSize((int)pixelSize);
+}
+#endif
+
+/*!
+ \fn bool QFont::italic() const
+
+ Returns true if the style() of the font is not QFont::StyleNormal
+
+ \sa setItalic() style()
+*/
+
+/*!
+ \fn void QFont::setItalic(bool enable)
+
+ Sets the style() of the font to QFont::StyleItalic if \a enable is true;
+ otherwise the style is set to QFont::StyleNormal.
+
+ \sa italic() QFontInfo
+*/
+
+/*!
+ Returns the style of the font.
+
+ \sa setStyle()
+*/
+QFont::Style QFont::style() const
+{
+ return (QFont::Style)d->request.style;
+}
+
+
+/*!
+ Sets the style of the font to \a style.
+
+ \sa italic(), QFontInfo
+*/
+void QFont::setStyle(Style style)
+{
+ detach();
+
+ d->request.style = style;
+ resolve_mask |= QFont::StyleResolved;
+}
+
+/*!
+ Returns the weight of the font which is one of the enumerated
+ values from \l{QFont::Weight}.
+
+ \sa setWeight(), Weight, QFontInfo
+*/
+int QFont::weight() const
+{
+ return d->request.weight;
+}
+
+/*!
+ \enum QFont::Weight
+
+ Qt uses a weighting scale from 0 to 99 similar to, but not the
+ same as, the scales used in Windows or CSS. A weight of 0 is
+ ultralight, whilst 99 will be an extremely black.
+
+ This enum contains the predefined font weights:
+
+ \value Light 25
+ \value Normal 50
+ \value DemiBold 63
+ \value Bold 75
+ \value Black 87
+*/
+
+/*!
+ Sets the weight the font to \a weight, which should be a value
+ from the \l QFont::Weight enumeration.
+
+ \sa weight(), QFontInfo
+*/
+void QFont::setWeight(int weight)
+{
+ Q_ASSERT_X(weight >= 0 && weight <= 99, "QFont::setWeight", "Weight must be between 0 and 99");
+
+ detach();
+
+ d->request.weight = weight;
+ resolve_mask |= QFont::WeightResolved;
+}
+
+/*!
+ \fn bool QFont::bold() const
+
+ Returns true if weight() is a value greater than \link Weight
+ QFont::Normal \endlink; otherwise returns false.
+
+ \sa weight(), setBold(), QFontInfo::bold()
+*/
+
+/*!
+ \fn void QFont::setBold(bool enable)
+
+ If \a enable is true sets the font's weight to \link Weight
+ QFont::Bold \endlink; otherwise sets the weight to \link Weight
+ QFont::Normal\endlink.
+
+ For finer boldness control use setWeight().
+
+ \sa bold(), setWeight()
+*/
+
+/*!
+ Returns true if underline has been set; otherwise returns false.
+
+ \sa setUnderline()
+*/
+bool QFont::underline() const
+{
+ return d->underline;
+}
+
+/*!
+ If \a enable is true, sets underline on; otherwise sets underline
+ off.
+
+ \sa underline(), QFontInfo
+*/
+void QFont::setUnderline(bool enable)
+{
+ detach();
+
+ d->underline = enable;
+ resolve_mask |= QFont::UnderlineResolved;
+}
+
+/*!
+ Returns true if overline has been set; otherwise returns false.
+
+ \sa setOverline()
+*/
+bool QFont::overline() const
+{
+ return d->overline;
+}
+
+/*!
+ If \a enable is true, sets overline on; otherwise sets overline off.
+
+ \sa overline(), QFontInfo
+*/
+void QFont::setOverline(bool enable)
+{
+ detach();
+
+ d->overline = enable;
+ resolve_mask |= QFont::OverlineResolved;
+}
+
+/*!
+ Returns true if strikeout has been set; otherwise returns false.
+
+ \sa setStrikeOut()
+*/
+bool QFont::strikeOut() const
+{
+ return d->strikeOut;
+}
+
+/*!
+ If \a enable is true, sets strikeout on; otherwise sets strikeout
+ off.
+
+ \sa strikeOut(), QFontInfo
+*/
+void QFont::setStrikeOut(bool enable)
+{
+ detach();
+
+ d->strikeOut = enable;
+ resolve_mask |= QFont::StrikeOutResolved;
+}
+
+/*!
+ Returns true if fixed pitch has been set; otherwise returns false.
+
+ \sa setFixedPitch(), QFontInfo::fixedPitch()
+*/
+bool QFont::fixedPitch() const
+{
+ return d->request.fixedPitch;
+}
+
+/*!
+ If \a enable is true, sets fixed pitch on; otherwise sets fixed
+ pitch off.
+
+ \sa fixedPitch(), QFontInfo
+*/
+void QFont::setFixedPitch(bool enable)
+{
+ detach();
+
+ d->request.fixedPitch = enable;
+ d->request.ignorePitch = false;
+ resolve_mask |= QFont::FixedPitchResolved;
+}
+
+/*!
+ Returns true if kerning should be used when drawing text with this font.
+
+ \sa setKerning()
+*/
+bool QFont::kerning() const
+{
+ return d->kerning;
+}
+
+/*!
+ Enables kerning for this font if \a enable is true; otherwise
+ disables it. By default, kerning is enabled.
+
+ When kerning is enabled, glyph metrics do not add up anymore,
+ even for Latin text. In other words, the assumption that
+ width('a') + width('b') is equal to width("ab") is not
+ neccesairly true.
+
+ \sa kerning(), QFontMetrics
+*/
+void QFont::setKerning(bool enable)
+{
+ detach();
+ d->kerning = enable;
+ resolve_mask |= QFont::KerningResolved;
+}
+
+/*!
+ Returns the StyleStrategy.
+
+ The style strategy affects the \l{QFont}{font matching} algorithm.
+ See \l QFont::StyleStrategy for the list of available strategies.
+
+ \sa setStyleHint() QFont::StyleHint
+*/
+QFont::StyleStrategy QFont::styleStrategy() const
+{
+ return (StyleStrategy) d->request.styleStrategy;
+}
+
+/*!
+ Returns the StyleHint.
+
+ The style hint affects the \l{QFont}{font matching} algorithm.
+ See \l QFont::StyleHint for the list of available hints.
+
+ \sa setStyleHint(), QFont::StyleStrategy QFontInfo::styleHint()
+*/
+QFont::StyleHint QFont::styleHint() const
+{
+ return (StyleHint) d->request.styleHint;
+}
+
+/*!
+ \enum QFont::StyleHint
+
+ Style hints are used by the \l{QFont}{font matching} algorithm to
+ find an appropriate default family if a selected font family is
+ not available.
+
+ \value AnyStyle leaves the font matching algorithm to choose the
+ family. This is the default.
+
+ \value SansSerif the font matcher prefer sans serif fonts.
+ \value Helvetica is a synonym for \c SansSerif.
+
+ \value Serif the font matcher prefers serif fonts.
+ \value Times is a synonym for \c Serif.
+
+ \value TypeWriter the font matcher prefers fixed pitch fonts.
+ \value Courier a synonym for \c TypeWriter.
+
+ \value OldEnglish the font matcher prefers decorative fonts.
+ \value Decorative is a synonym for \c OldEnglish.
+
+ \value Monospace the font matcher prefers fonts that map to the
+ CSS generic font-family 'monospace'.
+
+ \value Fantasy the font matcher prefers fonts that map to the
+ CSS generic font-family 'fantasy'.
+
+ \value Cursive the font matcher prefers fonts that map to the
+ CSS generic font-family 'cursive'.
+
+ \value System the font matcher prefers system fonts.
+*/
+
+/*!
+ \enum QFont::StyleStrategy
+
+ The style strategy tells the \l{QFont}{font matching} algorithm
+ what type of fonts should be used to find an appropriate default
+ family.
+
+ The following strategies are available:
+
+ \value PreferDefault the default style strategy. It does not prefer
+ any type of font.
+ \value PreferBitmap prefers bitmap fonts (as opposed to outline
+ fonts).
+ \value PreferDevice prefers device fonts.
+ \value PreferOutline prefers outline fonts (as opposed to bitmap fonts).
+ \value ForceOutline forces the use of outline fonts.
+ \value NoAntialias don't antialias the fonts.
+ \value PreferAntialias antialias if possible.
+ \value OpenGLCompatible forces the use of OpenGL compatible
+ fonts.
+ \value NoFontMerging If the font selected for a certain writing system
+ does not contain a character requested to draw, then Qt automatically chooses a similar
+ looking font that contains the character. The NoFontMerging flag disables this feature.
+ Please note that enabling this flag will not prevent Qt from automatically picking a
+ suitable font when the selected font does not support the writing system of the text.
+
+ Any of these may be OR-ed with one of these flags:
+
+ \value PreferMatch prefer an exact match. The font matcher will try to
+ use the exact font size that has been specified.
+ \value PreferQuality prefer the best quality font. The font matcher
+ will use the nearest standard point size that the font
+ supports.
+ \value ForceIntegerMetrics forces the use of integer values in font engines that support fractional
+ font metrics.
+*/
+
+/*!
+ Sets the style hint and strategy to \a hint and \a strategy,
+ respectively.
+
+ If these aren't set explicitly the style hint will default to
+ \c AnyStyle and the style strategy to \c PreferDefault.
+
+ Qt does not support style hints on X11 since this information
+ is not provided by the window system.
+
+ \sa StyleHint, styleHint(), StyleStrategy, styleStrategy(), QFontInfo
+*/
+void QFont::setStyleHint(StyleHint hint, StyleStrategy strategy)
+{
+ detach();
+
+ if ((resolve_mask & (QFont::StyleHintResolved | QFont::StyleStrategyResolved)) &&
+ (StyleHint) d->request.styleHint == hint &&
+ (StyleStrategy) d->request.styleStrategy == strategy)
+ return;
+
+ d->request.styleHint = hint;
+ d->request.styleStrategy = strategy;
+ resolve_mask |= QFont::StyleHintResolved;
+ resolve_mask |= QFont::StyleStrategyResolved;
+
+#if defined(Q_WS_X11)
+ d->request.addStyle.clear();
+#endif // Q_WS_X11
+}
+
+/*!
+ Sets the style strategy for the font to \a s.
+
+ \sa QFont::StyleStrategy
+*/
+void QFont::setStyleStrategy(StyleStrategy s)
+{
+ detach();
+
+ if ((resolve_mask & QFont::StyleStrategyResolved) &&
+ s == (StyleStrategy)d->request.styleStrategy)
+ return;
+
+ d->request.styleStrategy = s;
+ resolve_mask |= QFont::StyleStrategyResolved;
+}
+
+
+/*!
+ \enum QFont::Stretch
+
+ Predefined stretch values that follow the CSS naming convention. The higher
+ the value, the more stretched the text is.
+
+ \value UltraCondensed 50
+ \value ExtraCondensed 62
+ \value Condensed 75
+ \value SemiCondensed 87
+ \value Unstretched 100
+ \value SemiExpanded 112
+ \value Expanded 125
+ \value ExtraExpanded 150
+ \value UltraExpanded 200
+
+ \sa setStretch() stretch()
+*/
+
+/*!
+ Returns the stretch factor for the font.
+
+ \sa setStretch()
+ */
+int QFont::stretch() const
+{
+ return d->request.stretch;
+}
+
+/*!
+ Sets the stretch factor for the font.
+
+ The stretch factor changes the width of all characters in the font
+ by \a factor percent. For example, setting \a factor to 150
+ results in all characters in the font being 1.5 times (ie. 150%)
+ wider. The default stretch factor is 100. The minimum stretch
+ factor is 1, and the maximum stretch factor is 4000.
+
+ The stretch factor is only applied to outline fonts. The stretch
+ factor is ignored for bitmap fonts.
+
+ NOTE: QFont cannot stretch XLFD fonts. When loading XLFD fonts on
+ X11, the stretch factor is matched against a predefined set of
+ values for the SETWIDTH_NAME field of the XLFD.
+
+ \sa stretch() QFont::Stretch
+*/
+void QFont::setStretch(int factor)
+{
+ if (factor < 1 || factor > 4000) {
+ qWarning("QFont::setStretch: Parameter '%d' out of range", factor);
+ return;
+ }
+
+ if ((resolve_mask & QFont::StretchResolved) &&
+ d->request.stretch == (uint)factor)
+ return;
+
+ detach();
+
+ d->request.stretch = (uint)factor;
+ resolve_mask |= QFont::StretchResolved;
+}
+
+/*!
+ \enum QFont::SpacingType
+ \since 4.4
+
+ \value PercentageSpacing A value of 100 will keep the spacing unchanged; a value of 200 will enlarge the
+ spacing after a character by the width of the character itself.
+ \value AbsoluteSpacing A positive value increases the letter spacing by the corresponding pixels; a negative
+ value decreases the spacing.
+*/
+
+/*!
+ \since 4.4
+ Returns the letter spacing for the font.
+
+ \sa setLetterSpacing(), letterSpacingType(), setWordSpacing()
+ */
+qreal QFont::letterSpacing() const
+{
+ return d->letterSpacing.toReal();
+}
+
+/*!
+ \since 4.4
+ Sets the letter spacing for the font to \a spacing and the type
+ of spacing to \a type.
+
+ Letter spacing changes the default spacing between individual
+ letters in the font. The spacing between the letters can be
+ made smaller as well as larger.
+
+ \sa letterSpacing(), letterSpacingType(), setWordSpacing()
+*/
+void QFont::setLetterSpacing(SpacingType type, qreal spacing)
+{
+ const QFixed newSpacing = QFixed::fromReal(spacing);
+ const bool absoluteSpacing = type == AbsoluteSpacing;
+ if ((resolve_mask & QFont::LetterSpacingResolved) &&
+ d->letterSpacingIsAbsolute == absoluteSpacing &&
+ d->letterSpacing == newSpacing)
+ return;
+
+ detach();
+
+ d->letterSpacing = newSpacing;
+ d->letterSpacingIsAbsolute = absoluteSpacing;
+ resolve_mask |= QFont::LetterSpacingResolved;
+}
+
+/*!
+ \since 4.4
+ Returns the spacing type used for letter spacing.
+
+ \sa letterSpacing(), setLetterSpacing(), setWordSpacing()
+*/
+QFont::SpacingType QFont::letterSpacingType() const
+{
+ return d->letterSpacingIsAbsolute ? AbsoluteSpacing : PercentageSpacing;
+}
+
+/*!
+ \since 4.4
+ Returns the word spacing for the font.
+
+ \sa setWordSpacing(), setLetterSpacing()
+ */
+qreal QFont::wordSpacing() const
+{
+ return d->wordSpacing.toReal();
+}
+
+/*!
+ \since 4.4
+ Sets the word spacing for the font to \a spacing.
+
+ Word spacing changes the default spacing between individual
+ words. A positive value increases the word spacing
+ by a corresponding amount of pixels, while a negative value
+ decreases the inter-word spacing accordingly.
+
+ Word spacing will not apply to writing systems, where indiviaul
+ words are not separated by white space.
+
+ \sa wordSpacing(), setLetterSpacing()
+*/
+void QFont::setWordSpacing(qreal spacing)
+{
+ const QFixed newSpacing = QFixed::fromReal(spacing);
+ if ((resolve_mask & QFont::WordSpacingResolved) &&
+ d->wordSpacing == newSpacing)
+ return;
+
+ detach();
+
+ d->wordSpacing = newSpacing;
+ resolve_mask |= QFont::WordSpacingResolved;
+}
+
+/*!
+ \enum QFont::Capitalization
+ \since 4.4
+
+ Rendering option for text this font applies to.
+
+
+ \value MixedCase This is the normal text rendering option where no capitalization change is applied.
+ \value AllUppercase This alters the text to be rendered in all uppercase type.
+ \value AllLowercase This alters the text to be rendered in all lowercase type.
+ \value SmallCaps This alters the text to be rendered in small-caps type.
+ \value Capitalize This alters the text to be rendered with the first character of each word as an uppercase character.
+*/
+
+/*!
+ \since 4.4
+ Sets the capitalization of the text in this font to \a caps.
+
+ A font's capitalization makes the text appear in the selected capitalization mode.
+
+ \sa capitalization()
+*/
+void QFont::setCapitalization(Capitalization caps)
+{
+ if ((resolve_mask & QFont::CapitalizationResolved) &&
+ capitalization() == caps)
+ return;
+
+ detach();
+
+ d->capital = caps;
+ resolve_mask |= QFont::CapitalizationResolved;
+}
+
+/*!
+ \since 4.4
+ Returns the current capitalization type of the font.
+
+ \sa setCapitalization()
+*/
+QFont::Capitalization QFont::capitalization() const
+{
+ return static_cast<QFont::Capitalization> (d->capital);
+}
+
+
+/*!
+ If \a enable is true, turns raw mode on; otherwise turns raw mode
+ off. This function only has an effect under X11.
+
+ If raw mode is enabled, Qt will search for an X font with a
+ complete font name matching the family name, ignoring all other
+ values set for the QFont. If the font name matches several fonts,
+ Qt will use the first font returned by X. QFontInfo \e cannot be
+ used to fetch information about a QFont using raw mode (it will
+ return the values set in the QFont for all parameters, including
+ the family name).
+
+ \warning Do not use raw mode unless you really, really need it! In
+ most (if not all) cases, setRawName() is a much better choice.
+
+ \sa rawMode(), setRawName()
+*/
+void QFont::setRawMode(bool enable)
+{
+ detach();
+
+ if ((bool) d->rawMode == enable) return;
+
+ d->rawMode = enable;
+}
+
+/*!
+ Returns true if a window system font exactly matching the settings
+ of this font is available.
+
+ \sa QFontInfo
+*/
+bool QFont::exactMatch() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return (d->rawMode
+ ? engine->type() != QFontEngine::Box
+ : d->request.exactMatch(engine->fontDef));
+}
+
+/*!
+ Returns true if this font is equal to \a f; otherwise returns
+ false.
+
+ Two QFonts are considered equal if their font attributes are
+ equal. If rawMode() is enabled for both fonts, only the family
+ fields are compared.
+
+ \sa operator!=() isCopyOf()
+*/
+bool QFont::operator==(const QFont &f) const
+{
+ return (f.d == d
+ || (f.d->request == d->request
+ && f.d->request.pointSize == d->request.pointSize
+ && f.d->underline == d->underline
+ && f.d->overline == d->overline
+ && f.d->strikeOut == d->strikeOut
+ && f.d->kerning == d->kerning
+ && f.d->capital == d->capital
+ && f.d->letterSpacingIsAbsolute == d->letterSpacingIsAbsolute
+ && f.d->letterSpacing == d->letterSpacing
+ && f.d->wordSpacing == d->wordSpacing
+ ));
+}
+
+
+/*!
+ Provides an arbitrary comparison of this font and font \a f.
+ All that is guaranteed is that the operator returns false if both
+ fonts are equal and that (f1 \< f2) == !(f2 \< f1) if the fonts
+ are not equal.
+
+ This function is useful in some circumstances, for example if you
+ want to use QFont objects as keys in a QMap.
+
+ \sa operator==() operator!=() isCopyOf()
+*/
+bool QFont::operator<(const QFont &f) const
+{
+ if (f.d == d) return false;
+ // the < operator for fontdefs ignores point sizes.
+ QFontDef &r1 = f.d->request;
+ QFontDef &r2 = d->request;
+ if (r1.pointSize != r2.pointSize) return r1.pointSize < r2.pointSize;
+ if (r1.pixelSize != r2.pixelSize) return r1.pixelSize < r2.pixelSize;
+ if (r1.weight != r2.weight) return r1.weight < r2.weight;
+ if (r1.style != r2.style) return r1.style < r2.style;
+ if (r1.stretch != r2.stretch) return r1.stretch < r2.stretch;
+ if (r1.styleHint != r2.styleHint) return r1.styleHint < r2.styleHint;
+ if (r1.styleStrategy != r2.styleStrategy) return r1.styleStrategy < r2.styleStrategy;
+ if (r1.family != r2.family) return r1.family < r2.family;
+#ifdef Q_WS_X11
+ if (r1.addStyle != r2.addStyle) return r1.addStyle < r2.addStyle;
+#endif // Q_WS_X11
+ if (f.d->capital != d->capital) return f.d->capital < d->capital;
+
+ if (f.d->letterSpacingIsAbsolute != d->letterSpacingIsAbsolute) return f.d->letterSpacingIsAbsolute < d->letterSpacingIsAbsolute;
+ if (f.d->letterSpacing != d->letterSpacing) return f.d->letterSpacing < d->letterSpacing;
+ if (f.d->wordSpacing != d->wordSpacing) return f.d->wordSpacing < d->wordSpacing;
+
+ int f1attrs = (f.d->underline << 3) + (f.d->overline << 2) + (f.d->strikeOut<<1) + f.d->kerning;
+ int f2attrs = (d->underline << 3) + (d->overline << 2) + (d->strikeOut<<1) + d->kerning;
+ return f1attrs < f2attrs;
+}
+
+
+/*!
+ Returns true if this font is different from \a f; otherwise
+ returns false.
+
+ Two QFonts are considered to be different if their font attributes
+ are different. If rawMode() is enabled for both fonts, only the
+ family fields are compared.
+
+ \sa operator==()
+*/
+bool QFont::operator!=(const QFont &f) const
+{
+ return !(operator==(f));
+}
+
+/*!
+ Returns the font as a QVariant
+*/
+QFont::operator QVariant() const
+{
+ return QVariant(QVariant::Font, this);
+}
+
+/*!
+ Returns true if this font and \a f are copies of each other, i.e.
+ one of them was created as a copy of the other and neither has
+ been modified since. This is much stricter than equality.
+
+ \sa operator=() operator==()
+*/
+bool QFont::isCopyOf(const QFont & f) const
+{
+ return d == f.d;
+}
+
+/*!
+ Returns true if raw mode is used for font name matching; otherwise
+ returns false.
+
+ \sa setRawMode() rawName()
+*/
+bool QFont::rawMode() const
+{
+ return d->rawMode;
+}
+
+/*!
+ Returns a new QFont that has attributes copied from \a other that
+ have not been previously set on this font.
+*/
+QFont QFont::resolve(const QFont &other) const
+{
+ if (*this == other
+ && (resolve_mask == other.resolve_mask || resolve_mask == 0)
+ && d->dpi == other.d->dpi) {
+ QFont o = other;
+ o.resolve_mask = resolve_mask;
+ return o;
+ }
+
+ QFont font(*this);
+ font.detach();
+ font.d->resolve(resolve_mask, other.d.data());
+
+ return font;
+}
+
+/*!
+ \fn uint QFont::resolve() const
+ \internal
+*/
+
+/*!
+ \fn void QFont::resolve(uint mask)
+ \internal
+*/
+
+#ifdef QT3_SUPPORT
+
+/*! \obsolete
+
+ Please use QApplication::font() instead.
+*/
+QFont QFont::defaultFont()
+{
+ return QApplication::font();
+}
+
+/*! \obsolete
+
+ Please use QApplication::setFont() instead.
+*/
+void QFont::setDefaultFont(const QFont &f)
+{
+ QApplication::setFont(f);
+}
+
+/*!
+ \fn qreal QFont::pointSizeFloat() const
+ \compat
+
+ Use pointSizeF() instead.
+*/
+
+/*!
+ \fn void QFont::setPointSizeFloat(qreal size)
+ \compat
+
+ Use setPointSizeF() instead.
+*/
+#endif
+
+
+
+
+/*****************************************************************************
+ QFont substitution management
+ *****************************************************************************/
+
+typedef QHash<QString, QStringList> QFontSubst;
+Q_GLOBAL_STATIC(QFontSubst, globalFontSubst)
+
+// create substitution dict
+static void initFontSubst()
+{
+ // default substitutions
+ static const char * const initTbl[] = {
+
+#if defined(Q_WS_X11)
+ "arial", "helvetica",
+ "times new roman", "times",
+ "courier new", "courier",
+ "sans serif", "helvetica",
+#elif defined(Q_WS_WIN)
+ "times", "times new roman",
+ "courier", "courier new",
+ "helvetica", "arial",
+ "sans serif", "arial",
+#endif
+
+ 0, 0
+ };
+
+ QFontSubst *fontSubst = globalFontSubst();
+ Q_ASSERT(fontSubst != 0);
+ if (!fontSubst->isEmpty())
+ return;
+#if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)
+ if (X11->has_fontconfig)
+ return;
+#endif
+
+ for (int i=0; initTbl[i] != 0; i += 2) {
+ QStringList &list = (*fontSubst)[QString::fromLatin1(initTbl[i])];
+ list.append(QString::fromLatin1(initTbl[i+1]));
+ }
+}
+
+/*!
+ Returns the first family name to be used whenever \a familyName is
+ specified. The lookup is case insensitive.
+
+ If there is no substitution for \a familyName, \a familyName is
+ returned.
+
+ To obtain a list of substitutions use substitutes().
+
+ \sa setFamily() insertSubstitutions() insertSubstitution() removeSubstitution()
+*/
+QString QFont::substitute(const QString &familyName)
+{
+ initFontSubst();
+
+ QFontSubst *fontSubst = globalFontSubst();
+ Q_ASSERT(fontSubst != 0);
+ QFontSubst::ConstIterator it = fontSubst->constFind(familyName.toLower());
+ if (it != fontSubst->constEnd() && !(*it).isEmpty())
+ return (*it).first();
+
+ return familyName;
+}
+
+
+/*!
+ Returns a list of family names to be used whenever \a familyName
+ is specified. The lookup is case insensitive.
+
+ If there is no substitution for \a familyName, an empty list is
+ returned.
+
+ \sa substitute() insertSubstitutions() insertSubstitution() removeSubstitution()
+ */
+QStringList QFont::substitutes(const QString &familyName)
+{
+ initFontSubst();
+
+ QFontSubst *fontSubst = globalFontSubst();
+ Q_ASSERT(fontSubst != 0);
+ return fontSubst->value(familyName.toLower(), QStringList());
+}
+
+
+/*!
+ Inserts \a substituteName into the substitution
+ table for the family \a familyName.
+
+ \sa insertSubstitutions() removeSubstitution() substitutions() substitute() substitutes()
+*/
+void QFont::insertSubstitution(const QString &familyName,
+ const QString &substituteName)
+{
+ initFontSubst();
+
+ QFontSubst *fontSubst = globalFontSubst();
+ Q_ASSERT(fontSubst != 0);
+ QStringList &list = (*fontSubst)[familyName.toLower()];
+ QString s = substituteName.toLower();
+ if (!list.contains(s))
+ list.append(s);
+}
+
+
+/*!
+ Inserts the list of families \a substituteNames into the
+ substitution list for \a familyName.
+
+ \sa insertSubstitution(), removeSubstitution(), substitutions(), substitute()
+*/
+void QFont::insertSubstitutions(const QString &familyName,
+ const QStringList &substituteNames)
+{
+ initFontSubst();
+
+ QFontSubst *fontSubst = globalFontSubst();
+ Q_ASSERT(fontSubst != 0);
+ QStringList &list = (*fontSubst)[familyName.toLower()];
+ QStringList::ConstIterator it = substituteNames.constBegin();
+ while (it != substituteNames.constEnd()) {
+ QString s = (*it).toLower();
+ if (!list.contains(s))
+ list.append(s);
+ it++;
+ }
+}
+
+/*! \fn void QFont::initialize()
+ \internal
+
+ Internal function that initializes the font system. The font cache
+ and font dict do not alloc the keys. The key is a QString which is
+ shared between QFontPrivate and QXFontName.
+*/
+
+/*! \fn void QFont::cleanup()
+ \internal
+
+ Internal function that cleans up the font system.
+*/
+
+// ### mark: should be called removeSubstitutions()
+/*!
+ Removes all the substitutions for \a familyName.
+
+ \sa insertSubstitutions(), insertSubstitution(), substitutions(), substitute()
+*/
+void QFont::removeSubstitution(const QString &familyName)
+{ // ### function name should be removeSubstitutions() or
+ // ### removeSubstitutionList()
+ initFontSubst();
+
+ QFontSubst *fontSubst = globalFontSubst();
+ Q_ASSERT(fontSubst != 0);
+ fontSubst->remove(familyName.toLower());
+}
+
+
+/*!
+ Returns a sorted list of substituted family names.
+
+ \sa insertSubstitution(), removeSubstitution(), substitute()
+*/
+QStringList QFont::substitutions()
+{
+ initFontSubst();
+
+ QFontSubst *fontSubst = globalFontSubst();
+ Q_ASSERT(fontSubst != 0);
+ QStringList ret;
+ QFontSubst::ConstIterator it = fontSubst->constBegin();
+
+ while (it != fontSubst->constEnd()) {
+ ret.append(it.key());
+ ++it;
+ }
+
+ ret.sort();
+ return ret;
+}
+
+
+/* \internal
+ Internal function. Converts boolean font settings to an unsigned
+ 8-bit number. Used for serialization etc.
+*/
+static quint8 get_font_bits(int version, const QFontPrivate *f)
+{
+ Q_ASSERT(f != 0);
+ quint8 bits = 0;
+ if (f->request.style)
+ bits |= 0x01;
+ if (f->underline)
+ bits |= 0x02;
+ if (f->overline)
+ bits |= 0x40;
+ if (f->strikeOut)
+ bits |= 0x04;
+ if (f->request.fixedPitch)
+ bits |= 0x08;
+ // if (f.hintSetByUser)
+ // bits |= 0x10;
+ if (f->rawMode)
+ bits |= 0x20;
+ if (version >= QDataStream::Qt_4_0) {
+ if (f->kerning)
+ bits |= 0x10;
+ }
+ if (f->request.style == QFont::StyleOblique)
+ bits |= 0x80;
+ return bits;
+}
+
+static quint8 get_extended_font_bits(const QFontPrivate *f)
+{
+ Q_ASSERT(f != 0);
+ quint8 bits = 0;
+ if (f->request.ignorePitch)
+ bits |= 0x01;
+ if (f->letterSpacingIsAbsolute)
+ bits |= 0x02;
+ return bits;
+}
+
+#ifndef QT_NO_DATASTREAM
+
+/* \internal
+ Internal function. Sets boolean font settings from an unsigned
+ 8-bit number. Used for serialization etc.
+*/
+static void set_font_bits(int version, quint8 bits, QFontPrivate *f)
+{
+ Q_ASSERT(f != 0);
+ f->request.style = (bits & 0x01) != 0 ? QFont::StyleItalic : QFont::StyleNormal;
+ f->underline = (bits & 0x02) != 0;
+ f->overline = (bits & 0x40) != 0;
+ f->strikeOut = (bits & 0x04) != 0;
+ f->request.fixedPitch = (bits & 0x08) != 0;
+ // f->hintSetByUser = (bits & 0x10) != 0;
+ f->rawMode = (bits & 0x20) != 0;
+ if (version >= QDataStream::Qt_4_0)
+ f->kerning = (bits & 0x10) != 0;
+ if ((bits & 0x80) != 0)
+ f->request.style = QFont::StyleOblique;
+}
+
+static void set_extended_font_bits(quint8 bits, QFontPrivate *f)
+{
+ Q_ASSERT(f != 0);
+ f->request.ignorePitch = (bits & 0x01) != 0;
+ f->letterSpacingIsAbsolute = (bits & 0x02) != 0;
+}
+#endif
+
+
+/*!
+ Returns the font's key, a textual representation of a font. It is
+ typically used as the key for a cache or dictionary of fonts.
+
+ \sa QMap
+*/
+QString QFont::key() const
+{
+ return toString();
+}
+
+/*!
+ Returns a description of the font. The description is a
+ comma-separated list of the attributes, perfectly suited for use
+ in QSettings.
+
+ \sa fromString()
+ */
+QString QFont::toString() const
+{
+ const QChar comma(QLatin1Char(','));
+ return family() + comma +
+ QString::number( pointSizeF()) + comma +
+ QString::number( pixelSize()) + comma +
+ QString::number((int) styleHint()) + comma +
+ QString::number( weight()) + comma +
+ QString::number((int) style()) + comma +
+ QString::number((int) underline()) + comma +
+ QString::number((int) strikeOut()) + comma +
+ QString::number((int)fixedPitch()) + comma +
+ QString::number((int) rawMode());
+}
+
+
+/*!
+ Sets this font to match the description \a descrip. The description
+ is a comma-separated list of the font attributes, as returned by
+ toString().
+
+ \sa toString()
+ */
+bool QFont::fromString(const QString &descrip)
+{
+ QStringList l(descrip.split(QLatin1Char(',')));
+
+ int count = l.count();
+ if (!count || (count > 2 && count < 9) || count > 11) {
+ qWarning("QFont::fromString: Invalid description '%s'",
+ descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
+ return false;
+ }
+
+ setFamily(l[0]);
+ if (count > 1 && l[1].toDouble() > 0.0)
+ setPointSizeF(l[1].toDouble());
+ if (count == 9) {
+ setStyleHint((StyleHint) l[2].toInt());
+ setWeight(qMax(qMin(99, l[3].toInt()), 0));
+ setItalic(l[4].toInt());
+ setUnderline(l[5].toInt());
+ setStrikeOut(l[6].toInt());
+ setFixedPitch(l[7].toInt());
+ setRawMode(l[8].toInt());
+ } else if (count == 10) {
+ if (l[2].toInt() > 0)
+ setPixelSize(l[2].toInt());
+ setStyleHint((StyleHint) l[3].toInt());
+ setWeight(qMax(qMin(99, l[4].toInt()), 0));
+ setStyle((QFont::Style)l[5].toInt());
+ setUnderline(l[6].toInt());
+ setStrikeOut(l[7].toInt());
+ setFixedPitch(l[8].toInt());
+ setRawMode(l[9].toInt());
+ }
+ if (count >= 9 && !d->request.fixedPitch) // assume 'false' fixedPitch equals default
+ d->request.ignorePitch = true;
+
+ return true;
+}
+
+#if !defined(Q_WS_QWS)
+/*! \internal
+
+ Internal function that dumps font cache statistics.
+*/
+void QFont::cacheStatistics()
+{
+
+
+}
+#endif // !Q_WS_QWS
+
+
+
+/*****************************************************************************
+ QFont stream functions
+ *****************************************************************************/
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \relates QFont
+
+ Writes the font \a font to the data stream \a s. (toString()
+ writes to a text stream.)
+
+ \sa \link datastreamformat.html Format of the QDataStream operators \endlink
+*/
+QDataStream &operator<<(QDataStream &s, const QFont &font)
+{
+ if (s.version() == 1) {
+ s << font.d->request.family.toLatin1();
+ } else {
+ s << font.d->request.family;
+ }
+
+ if (s.version() >= QDataStream::Qt_4_0) {
+ // 4.0
+ double pointSize = font.d->request.pointSize;
+ qint32 pixelSize = font.d->request.pixelSize;
+ s << pointSize;
+ s << pixelSize;
+ } else if (s.version() <= 3) {
+ qint16 pointSize = (qint16) (font.d->request.pointSize * 10);
+ if (pointSize < 0) {
+#ifdef Q_WS_X11
+ pointSize = (qint16)(font.d->request.pixelSize*720/QX11Info::appDpiY());
+#else
+ pointSize = (qint16)QFontInfo(font).pointSize() * 10;
+#endif
+ }
+ s << pointSize;
+ } else {
+ s << (qint16) (font.d->request.pointSize * 10);
+ s << (qint16) font.d->request.pixelSize;
+ }
+
+ s << (quint8) font.d->request.styleHint;
+ if (s.version() >= QDataStream::Qt_3_1)
+ s << (quint8) font.d->request.styleStrategy;
+ s << (quint8) 0
+ << (quint8) font.d->request.weight
+ << get_font_bits(s.version(), font.d.data());
+ if (s.version() >= QDataStream::Qt_4_3)
+ s << (quint16)font.d->request.stretch;
+ if (s.version() >= QDataStream::Qt_4_4)
+ s << get_extended_font_bits(font.d.data());
+ if (s.version() >= QDataStream::Qt_4_5) {
+ s << font.d->letterSpacing.value();
+ s << font.d->wordSpacing.value();
+ }
+ return s;
+}
+
+
+/*!
+ \relates QFont
+
+ Reads the font \a font from the data stream \a s. (fromString()
+ reads from a text stream.)
+
+ \sa \link datastreamformat.html Format of the QDataStream operators \endlink
+*/
+QDataStream &operator>>(QDataStream &s, QFont &font)
+{
+ font.d = new QFontPrivate;
+ font.resolve_mask = QFont::AllPropertiesResolved;
+
+ quint8 styleHint, styleStrategy = QFont::PreferDefault, charSet, weight, bits;
+
+ if (s.version() == 1) {
+ QByteArray fam;
+ s >> fam;
+ font.d->request.family = QString::fromLatin1(fam);
+ } else {
+ s >> font.d->request.family;
+ }
+
+ if (s.version() >= QDataStream::Qt_4_0) {
+ // 4.0
+ double pointSize;
+ qint32 pixelSize;
+ s >> pointSize;
+ s >> pixelSize;
+ font.d->request.pointSize = qreal(pointSize);
+ font.d->request.pixelSize = pixelSize;
+ } else {
+ qint16 pointSize, pixelSize = -1;
+ s >> pointSize;
+ if (s.version() >= 4)
+ s >> pixelSize;
+ font.d->request.pointSize = qreal(pointSize / 10.);
+ font.d->request.pixelSize = pixelSize;
+ }
+ s >> styleHint;
+ if (s.version() >= QDataStream::Qt_3_1)
+ s >> styleStrategy;
+
+ s >> charSet;
+ s >> weight;
+ s >> bits;
+
+ font.d->request.styleHint = styleHint;
+ font.d->request.styleStrategy = styleStrategy;
+ font.d->request.weight = weight;
+
+ set_font_bits(s.version(), bits, font.d.data());
+
+ if (s.version() >= QDataStream::Qt_4_3) {
+ quint16 stretch;
+ s >> stretch;
+ font.d->request.stretch = stretch;
+ }
+
+ if (s.version() >= QDataStream::Qt_4_4) {
+ quint8 extendedBits;
+ s >> extendedBits;
+ set_extended_font_bits(extendedBits, font.d.data());
+ }
+ if (s.version() >= QDataStream::Qt_4_5) {
+ int value;
+ s >> value;
+ font.d->letterSpacing.setValue(value);
+ s >> value;
+ font.d->wordSpacing.setValue(value);
+ }
+
+ return s;
+}
+
+#endif // QT_NO_DATASTREAM
+
+
+/*****************************************************************************
+ QFontInfo member functions
+ *****************************************************************************/
+
+/*!
+ \class QFontInfo
+ \reentrant
+
+ \brief The QFontInfo class provides general information about fonts.
+
+ \ingroup appearance
+ \ingroup shared
+
+ The QFontInfo class provides the same access functions as QFont,
+ e.g. family(), pointSize(), italic(), weight(), fixedPitch(),
+ styleHint() etc. But whilst the QFont access functions return the
+ values that were set, a QFontInfo object returns the values that
+ apply to the font that will actually be used to draw the text.
+
+ For example, when the program asks for a 25pt Courier font on a
+ machine that has a non-scalable 24pt Courier font, QFont will
+ (normally) use the 24pt Courier for rendering. In this case,
+ QFont::pointSize() returns 25 and QFontInfo::pointSize() returns
+ 24.
+
+ There are three ways to create a QFontInfo object.
+ \list 1
+ \o Calling the QFontInfo constructor with a QFont creates a font
+ info object for a screen-compatible font, i.e. the font cannot be
+ a printer font. If the font is changed later, the font
+ info object is \e not updated.
+
+ (Note: If you use a printer font the values returned may be
+ inaccurate. Printer fonts are not always accessible so the nearest
+ screen font is used if a printer font is supplied.)
+
+ \o QWidget::fontInfo() returns the font info for a widget's font.
+ This is equivalent to calling QFontInfo(widget->font()). If the
+ widget's font is changed later, the font info object is \e not
+ updated.
+
+ \o QPainter::fontInfo() returns the font info for a painter's
+ current font. If the painter's font is changed later, the font
+ info object is \e not updated.
+ \endlist
+
+ \sa QFont QFontMetrics QFontDatabase
+*/
+
+/*!
+ Constructs a font info object for \a font.
+
+ The font must be screen-compatible, i.e. a font you use when
+ drawing text in \link QWidget widgets\endlink or \link QPixmap
+ pixmaps\endlink, not QPicture or QPrinter.
+
+ The font info object holds the information for the font that is
+ passed in the constructor at the time it is created, and is not
+ updated if the font's attributes are changed later.
+
+ Use QPainter::fontInfo() to get the font info when painting.
+ This will give correct results also when painting on paint device
+ that is not screen-compatible.
+*/
+QFontInfo::QFontInfo(const QFont &font)
+ : d(font.d.data())
+{
+}
+
+/*!
+ Constructs a copy of \a fi.
+*/
+QFontInfo::QFontInfo(const QFontInfo &fi)
+ : d(fi.d.data())
+{
+}
+
+/*!
+ Destroys the font info object.
+*/
+QFontInfo::~QFontInfo()
+{
+}
+
+/*!
+ Assigns the font info in \a fi.
+*/
+QFontInfo &QFontInfo::operator=(const QFontInfo &fi)
+{
+ d = fi.d.data();
+ return *this;
+}
+
+/*!
+ Returns the family name of the matched window system font.
+
+ \sa QFont::family()
+*/
+QString QFontInfo::family() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return engine->fontDef.family;
+}
+
+/*!
+ Returns the point size of the matched window system font.
+
+ \sa pointSizeF() QFont::pointSize()
+*/
+int QFontInfo::pointSize() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return qRound(engine->fontDef.pointSize);
+}
+
+/*!
+ Returns the point size of the matched window system font.
+
+ \sa QFont::pointSizeF()
+*/
+qreal QFontInfo::pointSizeF() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return engine->fontDef.pointSize;
+}
+
+/*!
+ Returns the pixel size of the matched window system font.
+
+ \sa QFont::pointSize()
+*/
+int QFontInfo::pixelSize() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return engine->fontDef.pixelSize;
+}
+
+/*!
+ Returns the italic value of the matched window system font.
+
+ \sa QFont::italic()
+*/
+bool QFontInfo::italic() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return engine->fontDef.style != QFont::StyleNormal;
+}
+
+/*!
+ Returns the style value of the matched window system font.
+
+ \sa QFont::style()
+*/
+QFont::Style QFontInfo::style() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return (QFont::Style)engine->fontDef.style;
+}
+
+/*!
+ Returns the weight of the matched window system font.
+
+ \sa QFont::weight(), bold()
+*/
+int QFontInfo::weight() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return engine->fontDef.weight;
+
+}
+
+/*!
+ \fn bool QFontInfo::bold() const
+
+ Returns true if weight() would return a value greater than
+ QFont::Normal; otherwise returns false.
+
+ \sa weight(), QFont::bold()
+*/
+
+/*!
+ Returns the underline value of the matched window system font.
+
+ \sa QFont::underline()
+
+ \internal
+
+ Here we read the underline flag directly from the QFont.
+ This is OK for X11 and for Windows because we always get what we want.
+*/
+bool QFontInfo::underline() const
+{
+ return d->underline;
+}
+
+/*!
+ Returns the overline value of the matched window system font.
+
+ \sa QFont::overline()
+
+ \internal
+
+ Here we read the overline flag directly from the QFont.
+ This is OK for X11 and for Windows because we always get what we want.
+*/
+bool QFontInfo::overline() const
+{
+ return d->overline;
+}
+
+/*!
+ Returns the strikeout value of the matched window system font.
+
+ \sa QFont::strikeOut()
+
+ \internal Here we read the strikeOut flag directly from the QFont.
+ This is OK for X11 and for Windows because we always get what we want.
+*/
+bool QFontInfo::strikeOut() const
+{
+ return d->strikeOut;
+}
+
+/*!
+ Returns the fixed pitch value of the matched window system font.
+
+ \sa QFont::fixedPitch()
+*/
+bool QFontInfo::fixedPitch() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+#ifdef Q_OS_MAC
+ if (!engine->fontDef.fixedPitchComputed) {
+ QChar ch[2] = { QLatin1Char('i'), QLatin1Char('m') };
+ QGlyphLayoutArray<2> g;
+ int l = 2;
+ engine->stringToCMap(ch, 2, &g, &l, 0);
+ engine->fontDef.fixedPitch = g.advances_x[0] == g.advances_x[1];
+ engine->fontDef.fixedPitchComputed = true;
+ }
+#endif
+ return engine->fontDef.fixedPitch;
+}
+
+/*!
+ Returns the style of the matched window system font.
+
+ Currently only returns the style hint set in QFont.
+
+ \sa QFont::styleHint() QFont::StyleHint
+*/
+QFont::StyleHint QFontInfo::styleHint() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return (QFont::StyleHint) engine->fontDef.styleHint;
+}
+
+/*!
+ Returns true if the font is a raw mode font; otherwise returns
+ false.
+
+ If it is a raw mode font, all other functions in QFontInfo will
+ return the same values set in the QFont, regardless of the font
+ actually used.
+
+ \sa QFont::rawMode()
+*/
+bool QFontInfo::rawMode() const
+{
+ return d->rawMode;
+}
+
+/*!
+ Returns true if the matched window system font is exactly the same
+ as the one specified by the font; otherwise returns false.
+
+ \sa QFont::exactMatch()
+*/
+bool QFontInfo::exactMatch() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ return (d->rawMode
+ ? engine->type() != QFontEngine::Box
+ : d->request.exactMatch(engine->fontDef));
+}
+
+
+
+
+// **********************************************************************
+// QFontCache
+// **********************************************************************
+
+#ifdef QFONTCACHE_DEBUG
+// fast timeouts for debugging
+static const int fast_timeout = 1000; // 1s
+static const int slow_timeout = 5000; // 5s
+#else
+static const int fast_timeout = 10000; // 10s
+static const int slow_timeout = 300000; // 5m
+#endif // QFONTCACHE_DEBUG
+
+const uint QFontCache::min_cost = 4*1024; // 4mb
+
+#ifdef QT_NO_THREAD
+Q_GLOBAL_STATIC(QFontCache, theFontCache)
+
+QFontCache *QFontCache::instance()
+{
+ return theFontCache();
+}
+
+void QFontCache::cleanup()
+{
+}
+#else
+Q_GLOBAL_STATIC(QThreadStorage<QFontCache *>, theFontCache)
+
+QFontCache *QFontCache::instance()
+{
+ QFontCache *&fontCache = theFontCache()->localData();
+ if (!fontCache)
+ fontCache = new QFontCache;
+ return fontCache;
+}
+
+void QFontCache::cleanup()
+{
+ QThreadStorage<QFontCache *> *cache = 0;
+ QT_TRY {
+ cache = theFontCache();
+ } QT_CATCH (const std::bad_alloc &) {
+ // no cache - just ignore
+ }
+ if (cache && cache->hasLocalData())
+ cache->setLocalData(0);
+}
+#endif // QT_NO_THREAD
+
+QFontCache::QFontCache()
+ : QObject(), total_cost(0), max_cost(min_cost),
+ current_timestamp(0), fast(false), timer_id(-1)
+{
+}
+
+QFontCache::~QFontCache()
+{
+ clear();
+ {
+ EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
+ end = engineDataCache.constEnd();
+ while (it != end) {
+ if (it.value()->ref == 0)
+ delete it.value();
+ else
+ FC_DEBUG("QFontCache::~QFontCache: engineData %p still has refcount %d",
+ it.value(), int(it.value()->ref));
+ ++it;
+ }
+ }
+ EngineCache::ConstIterator it = engineCache.constBegin(),
+ end = engineCache.constEnd();
+ while (it != end) {
+ if (--it.value().data->cache_count == 0) {
+ if (it.value().data->ref == 0) {
+ FC_DEBUG("QFontCache::~QFontCache: deleting engine %p key=(%d / %g %g %d %d %d)",
+ it.value().data, it.key().script, it.key().def.pointSize,
+ it.key().def.pixelSize, it.key().def.weight, it.key().def.style,
+ it.key().def.fixedPitch);
+
+ delete it.value().data;
+ } else {
+ FC_DEBUG("QFontCache::~QFontCache: engine = %p still has refcount %d",
+ it.value().data, int(it.value().data->ref));
+ }
+ }
+ ++it;
+ }
+}
+
+void QFontCache::clear()
+{
+ {
+ EngineDataCache::Iterator it = engineDataCache.begin(),
+ end = engineDataCache.end();
+ while (it != end) {
+ QFontEngineData *data = it.value();
+#if !defined(Q_WS_MAC)
+ for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
+ if (data->engines[i]) {
+ data->engines[i]->ref.deref();
+ data->engines[i] = 0;
+ }
+ }
+#else
+ if (data->engine) {
+ data->engine->ref.deref();
+ data->engine = 0;
+ }
+#endif
+ ++it;
+ }
+ }
+
+ for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
+ it != end; ++it) {
+ if (it->data->ref == 0) {
+ delete it->data;
+ it->data = 0;
+ }
+ }
+
+ for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
+ it != end; ++it) {
+ if (it->data && it->data->ref == 0) {
+ delete it->data;
+ it->data = 0;
+ }
+ }
+
+ engineCache.clear();
+}
+
+#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
+void QFontCache::removeEngineForFont(const QByteArray &_fontName)
+{
+
+ /* This could be optimized but the code becomes much more complex if we want to handle multi
+ * font engines and it is probably not worth it. Therefore we just clear the entire font cache.
+ */
+ Q_UNUSED(_fontName);
+ clear();
+}
+#endif
+
+QFontEngineData *QFontCache::findEngineData(const Key &key) const
+{
+ EngineDataCache::ConstIterator it = engineDataCache.find(key),
+ end = engineDataCache.end();
+ if (it == end) return 0;
+
+ // found
+ return it.value();
+}
+
+void QFontCache::insertEngineData(const Key &key, QFontEngineData *engineData)
+{
+ FC_DEBUG("QFontCache: inserting new engine data %p", engineData);
+
+ engineDataCache.insert(key, engineData);
+ increaseCost(sizeof(QFontEngineData));
+}
+
+QFontEngine *QFontCache::findEngine(const Key &key)
+{
+ EngineCache::Iterator it = engineCache.find(key),
+ end = engineCache.end();
+ if (it == end) return 0;
+
+ // found... update the hitcount and timestamp
+ it.value().hits++;
+ it.value().timestamp = ++current_timestamp;
+
+ FC_DEBUG("QFontCache: found font engine\n"
+ " %p: timestamp %4u hits %3u ref %2d/%2d, type '%s'",
+ it.value().data, it.value().timestamp, it.value().hits,
+ int(it.value().data->ref), it.value().data->cache_count,
+ it.value().data->name());
+
+ return it.value().data;
+}
+
+void QFontCache::insertEngine(const Key &key, QFontEngine *engine)
+{
+ FC_DEBUG("QFontCache: inserting new engine %p", engine);
+
+ Engine data(engine);
+ data.timestamp = ++current_timestamp;
+
+ engineCache.insert(key, data);
+
+ // only increase the cost if this is the first time we insert the engine
+ if (engine->cache_count == 0)
+ increaseCost(engine->cache_cost);
+
+ ++engine->cache_count;
+}
+
+void QFontCache::increaseCost(uint cost)
+{
+ cost = (cost + 512) / 1024; // store cost in kb
+ cost = cost > 0 ? cost : 1;
+ total_cost += cost;
+
+ FC_DEBUG(" COST: increased %u kb, total_cost %u kb, max_cost %u kb",
+ cost, total_cost, max_cost);
+
+ if (total_cost > max_cost) {
+ max_cost = total_cost;
+
+ if (timer_id == -1 || ! fast) {
+ FC_DEBUG(" TIMER: starting fast timer (%d ms)", fast_timeout);
+
+ if (timer_id != -1) killTimer(timer_id);
+ timer_id = startTimer(fast_timeout);
+ fast = true;
+ }
+ }
+}
+
+void QFontCache::decreaseCost(uint cost)
+{
+ cost = (cost + 512) / 1024; // cost is stored in kb
+ cost = cost > 0 ? cost : 1;
+ Q_ASSERT(cost <= total_cost);
+ total_cost -= cost;
+
+ FC_DEBUG(" COST: decreased %u kb, total_cost %u kb, max_cost %u kb",
+ cost, total_cost, max_cost);
+}
+
+#if defined(Q_WS_WIN) || defined (Q_WS_QWS)
+void QFontCache::cleanupPrinterFonts()
+{
+ FC_DEBUG("QFontCache::cleanupPrinterFonts");
+
+ {
+ FC_DEBUG(" CLEAN engine data:");
+
+ // clean out all unused engine data
+ EngineDataCache::Iterator it = engineDataCache.begin(),
+ end = engineDataCache.end();
+ while (it != end) {
+ if (it.key().screen == 0) {
+ ++it;
+ continue;
+ }
+
+ if(it.value()->ref != 0) {
+ for(int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
+ if(it.value()->engines[i]) {
+ it.value()->engines[i]->ref.deref();
+ it.value()->engines[i] = 0;
+ }
+ }
+ ++it;
+ } else {
+
+ EngineDataCache::Iterator rem = it++;
+
+ decreaseCost(sizeof(QFontEngineData));
+
+ FC_DEBUG(" %p", rem.value());
+
+ delete rem.value();
+ engineDataCache.erase(rem);
+ }
+ }
+ }
+
+ EngineCache::Iterator it = engineCache.begin(),
+ end = engineCache.end();
+ while(it != end) {
+ if (it.value().data->ref != 0 || it.key().screen == 0) {
+ ++it;
+ continue;
+ }
+
+ FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type '%s'",
+ it.value().data, it.value().timestamp, it.value().hits,
+ int(it.value().data->ref), it.value().data->cache_count,
+ it.value().data->name());
+
+ if (--it.value().data->cache_count == 0) {
+ FC_DEBUG(" DELETE: last occurrence in cache");
+
+ decreaseCost(it.value().data->cache_cost);
+ delete it.value().data;
+ }
+
+ engineCache.erase(it++);
+ }
+}
+#endif
+
+void QFontCache::timerEvent(QTimerEvent *)
+{
+ FC_DEBUG("QFontCache::timerEvent: performing cache maintenance (timestamp %u)",
+ current_timestamp);
+
+ if (total_cost <= max_cost && max_cost <= min_cost) {
+ FC_DEBUG(" cache redused sufficiently, stopping timer");
+
+ killTimer(timer_id);
+ timer_id = -1;
+ fast = false;
+
+ return;
+ }
+
+ // go through the cache and count up everything in use
+ uint in_use_cost = 0;
+
+ {
+ FC_DEBUG(" SWEEP engine data:");
+
+ // make sure the cost of each engine data is at least 1kb
+ const uint engine_data_cost =
+ sizeof(QFontEngineData) > 1024 ? sizeof(QFontEngineData) : 1024;
+
+ EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
+ end = engineDataCache.constEnd();
+ for (; it != end; ++it) {
+#ifdef QFONTCACHE_DEBUG
+ FC_DEBUG(" %p: ref %2d", it.value(), int(it.value()->ref));
+
+# if defined(Q_WS_X11) || defined(Q_WS_WIN)
+ // print out all engines
+ for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
+ if (! it.value()->engines[i])
+ continue;
+ FC_DEBUG(" contains %p", it.value()->engines[i]);
+ }
+# endif // Q_WS_X11 || Q_WS_WIN
+#endif // QFONTCACHE_DEBUG
+
+ if (it.value()->ref != 0)
+ in_use_cost += engine_data_cost;
+ }
+ }
+
+ {
+ FC_DEBUG(" SWEEP engine:");
+
+ EngineCache::ConstIterator it = engineCache.constBegin(),
+ end = engineCache.constEnd();
+ for (; it != end; ++it) {
+ FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, cost %u bytes",
+ it.value().data, it.value().timestamp, it.value().hits,
+ int(it.value().data->ref), it.value().data->cache_count,
+ it.value().data->cache_cost);
+
+ if (it.value().data->ref != 0)
+ in_use_cost += it.value().data->cache_cost / it.value().data->cache_count;
+ }
+
+ // attempt to make up for rounding errors
+ in_use_cost += engineCache.size();
+ }
+
+ in_use_cost = (in_use_cost + 512) / 1024; // cost is stored in kb
+
+ /*
+ calculate the new maximum cost for the cache
+
+ NOTE: in_use_cost is *not* correct due to rounding errors in the
+ above algorithm. instead of worrying about getting the
+ calculation correct, we are more interested in speed, and use
+ in_use_cost as a floor for new_max_cost
+ */
+ uint new_max_cost = qMax(qMax(max_cost / 2, in_use_cost), min_cost);
+
+ FC_DEBUG(" after sweep, in use %u kb, total %u kb, max %u kb, new max %u kb",
+ in_use_cost, total_cost, max_cost, new_max_cost);
+
+ if (new_max_cost == max_cost) {
+ if (fast) {
+ FC_DEBUG(" cannot shrink cache, slowing timer");
+
+ killTimer(timer_id);
+ timer_id = startTimer(slow_timeout);
+ fast = false;
+ }
+
+ return;
+ } else if (! fast) {
+ FC_DEBUG(" dropping into passing gear");
+
+ killTimer(timer_id);
+ timer_id = startTimer(fast_timeout);
+ fast = true;
+ }
+
+ max_cost = new_max_cost;
+
+ {
+ FC_DEBUG(" CLEAN engine data:");
+
+ // clean out all unused engine data
+ EngineDataCache::Iterator it = engineDataCache.begin(),
+ end = engineDataCache.end();
+ while (it != end) {
+ if (it.value()->ref != 0) {
+ ++it;
+ continue;
+ }
+
+ EngineDataCache::Iterator rem = it++;
+
+ decreaseCost(sizeof(QFontEngineData));
+
+ FC_DEBUG(" %p", rem.value());
+
+ delete rem.value();
+ engineDataCache.erase(rem);
+ }
+ }
+
+ // clean out the engine cache just enough to get below our new max cost
+ uint current_cost;
+ do {
+ current_cost = total_cost;
+
+ EngineCache::Iterator it = engineCache.begin(),
+ end = engineCache.end();
+ // determine the oldest and least popular of the unused engines
+ uint oldest = ~0u;
+ uint least_popular = ~0u;
+
+ for (; it != end; ++it) {
+ if (it.value().data->ref != 0)
+ continue;
+
+ if (it.value().timestamp < oldest &&
+ it.value().hits <= least_popular) {
+ oldest = it.value().timestamp;
+ least_popular = it.value().hits;
+ }
+ }
+
+ FC_DEBUG(" oldest %u least popular %u", oldest, least_popular);
+
+ for (it = engineCache.begin(); it != end; ++it) {
+ if (it.value().data->ref == 0 &&
+ it.value().timestamp == oldest &&
+ it.value().hits == least_popular)
+ break;
+ }
+
+ if (it != end) {
+ FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type '%s'",
+ it.value().data, it.value().timestamp, it.value().hits,
+ int(it.value().data->ref), it.value().data->cache_count,
+ it.value().data->name());
+
+ if (--it.value().data->cache_count == 0) {
+ FC_DEBUG(" DELETE: last occurrence in cache");
+
+ decreaseCost(it.value().data->cache_cost);
+ delete it.value().data;
+ } else {
+ /*
+ this particular font engine is in the cache multiple
+ times... set current_cost to zero, so that we can
+ keep looping to get rid of all occurrences
+ */
+ current_cost = 0;
+ }
+
+ engineCache.erase(it);
+ }
+ } while (current_cost != total_cost && total_cost > max_cost);
+}
+
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug stream, const QFont &font)
+{
+ return stream << "QFont(" << font.toString() << ')';
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h
new file mode 100644
index 0000000000..8dbc746813
--- /dev/null
+++ b/src/gui/text/qfont.h
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QFONT_H
+#define QFONT_H
+
+#include <QtGui/qwindowdefs.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qsharedpointer.h>
+
+#if defined(Q_WS_X11) || defined(Q_WS_QWS)
+typedef struct FT_FaceRec_* FT_Face;
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QFontPrivate; /* don't touch */
+class QStringList;
+class QVariant;
+class Q3TextFormatCollection;
+
+class Q_GUI_EXPORT QFont
+{
+ Q_GADGET
+ Q_ENUMS(StyleStrategy)
+public:
+ enum StyleHint {
+ Helvetica, SansSerif = Helvetica,
+ Times, Serif = Times,
+ Courier, TypeWriter = Courier,
+ OldEnglish, Decorative = OldEnglish,
+ System,
+ AnyStyle,
+ Cursive,
+ Monospace,
+ Fantasy
+ };
+
+ enum StyleStrategy {
+ PreferDefault = 0x0001,
+ PreferBitmap = 0x0002,
+ PreferDevice = 0x0004,
+ PreferOutline = 0x0008,
+ ForceOutline = 0x0010,
+ PreferMatch = 0x0020,
+ PreferQuality = 0x0040,
+ PreferAntialias = 0x0080,
+ NoAntialias = 0x0100,
+ OpenGLCompatible = 0x0200,
+ ForceIntegerMetrics = 0x0400,
+ NoFontMerging = 0x8000
+ };
+
+ enum HintingPreference {
+ PreferDefaultHinting = 0,
+ PreferNoHinting = 1,
+ PreferVerticalHinting = 2,
+ PreferFullHinting = 3
+ };
+
+ enum Weight {
+ Light = 25,
+ Normal = 50,
+ DemiBold = 63,
+ Bold = 75,
+ Black = 87
+ };
+
+ enum Style {
+ StyleNormal,
+ StyleItalic,
+ StyleOblique
+ };
+
+ enum Stretch {
+ UltraCondensed = 50,
+ ExtraCondensed = 62,
+ Condensed = 75,
+ SemiCondensed = 87,
+ Unstretched = 100,
+ SemiExpanded = 112,
+ Expanded = 125,
+ ExtraExpanded = 150,
+ UltraExpanded = 200
+ };
+
+ enum Capitalization {
+ MixedCase,
+ AllUppercase,
+ AllLowercase,
+ SmallCaps,
+ Capitalize
+ };
+
+ enum SpacingType {
+ PercentageSpacing,
+ AbsoluteSpacing
+ };
+
+ enum ResolveProperties {
+ FamilyResolved = 0x0001,
+ SizeResolved = 0x0002,
+ StyleHintResolved = 0x0004,
+ StyleStrategyResolved = 0x0008,
+ WeightResolved = 0x0010,
+ StyleResolved = 0x0020,
+ UnderlineResolved = 0x0040,
+ OverlineResolved = 0x0080,
+ StrikeOutResolved = 0x0100,
+ FixedPitchResolved = 0x0200,
+ StretchResolved = 0x0400,
+ KerningResolved = 0x0800,
+ CapitalizationResolved = 0x1000,
+ LetterSpacingResolved = 0x2000,
+ WordSpacingResolved = 0x4000,
+ HintingPreferenceResolved = 0x8000,
+ AllPropertiesResolved = 0xffff
+ };
+
+ QFont();
+ QFont(const QString &family, int pointSize = -1, int weight = -1, bool italic = false);
+ QFont(const QFont &, QPaintDevice *pd);
+ QFont(const QFont &);
+ ~QFont();
+
+ QString family() const;
+ void setFamily(const QString &);
+
+ int pointSize() const;
+ void setPointSize(int);
+ qreal pointSizeF() const;
+ void setPointSizeF(qreal);
+
+ int pixelSize() const;
+ void setPixelSize(int);
+
+ int weight() const;
+ void setWeight(int);
+
+ inline bool bold() const;
+ inline void setBold(bool);
+
+ void setStyle(Style style);
+ Style style() const;
+
+ inline bool italic() const;
+ inline void setItalic(bool b);
+
+ bool underline() const;
+ void setUnderline(bool);
+
+ bool overline() const;
+ void setOverline(bool);
+
+ bool strikeOut() const;
+ void setStrikeOut(bool);
+
+ bool fixedPitch() const;
+ void setFixedPitch(bool);
+
+ bool kerning() const;
+ void setKerning(bool);
+
+ StyleHint styleHint() const;
+ StyleStrategy styleStrategy() const;
+ void setStyleHint(StyleHint, StyleStrategy = PreferDefault);
+ void setStyleStrategy(StyleStrategy s);
+
+ int stretch() const;
+ void setStretch(int);
+
+ qreal letterSpacing() const;
+ SpacingType letterSpacingType() const;
+ void setLetterSpacing(SpacingType type, qreal spacing);
+
+ qreal wordSpacing() const;
+ void setWordSpacing(qreal spacing);
+
+ void setCapitalization(Capitalization);
+ Capitalization capitalization() const;
+
+ void setHintingPreference(HintingPreference hintingPreference);
+ HintingPreference hintingPreference() const;
+
+ // is raw mode still needed?
+ bool rawMode() const;
+ void setRawMode(bool);
+
+ // dupicated from QFontInfo
+ bool exactMatch() const;
+
+ QFont &operator=(const QFont &);
+ bool operator==(const QFont &) const;
+ bool operator!=(const QFont &) const;
+ bool operator<(const QFont &) const;
+ operator QVariant() const;
+ bool isCopyOf(const QFont &) const;
+#ifdef Q_COMPILER_RVALUE_REFS
+ inline QFont &operator=(QFont &&other)
+ { qSwap(d, other.d); return *this; }
+#endif
+
+#ifdef Q_WS_WIN
+ HFONT handle() const;
+#else // !Q_WS_WIN
+ Qt::HANDLE handle() const;
+#endif // Q_WS_WIN
+#ifdef Q_WS_MAC
+ quint32 macFontID() const;
+#endif
+#if defined(Q_WS_X11) || defined(Q_WS_QWS)
+ FT_Face freetypeFace() const;
+#endif
+
+ // needed for X11
+ void setRawName(const QString &);
+ QString rawName() const;
+
+ QString key() const;
+
+ QString toString() const;
+ bool fromString(const QString &);
+
+ static QString substitute(const QString &);
+ static QStringList substitutes(const QString &);
+ static QStringList substitutions();
+ static void insertSubstitution(const QString&, const QString &);
+ static void insertSubstitutions(const QString&, const QStringList &);
+ static void removeSubstitution(const QString &);
+ static void initialize();
+ static void cleanup();
+#ifndef Q_WS_QWS
+ static void cacheStatistics();
+#endif
+
+ QString defaultFamily() const;
+ QString lastResortFamily() const;
+ QString lastResortFont() const;
+
+ QFont resolve(const QFont &) const;
+ inline uint resolve() const { return resolve_mask; }
+ inline void resolve(uint mask) { resolve_mask = mask; }
+
+#ifdef QT3_SUPPORT
+ static QT3_SUPPORT QFont defaultFont();
+ static QT3_SUPPORT void setDefaultFont(const QFont &);
+ QT3_SUPPORT void setPixelSizeFloat(qreal);
+ QT3_SUPPORT qreal pointSizeFloat() const { return pointSizeF(); }
+ QT3_SUPPORT void setPointSizeFloat(qreal size) { setPointSizeF(size); }
+#endif
+
+private:
+ QFont(QFontPrivate *);
+
+ void detach();
+
+#if defined(Q_WS_MAC)
+ void macSetFont(QPaintDevice *);
+#elif defined(Q_WS_X11)
+ void x11SetScreen(int screen = -1);
+ int x11Screen() const;
+#endif
+
+ friend class QFontPrivate;
+ friend class QFontDialogPrivate;
+ friend class QFontMetrics;
+ friend class QFontMetricsF;
+ friend class QFontInfo;
+ friend class QPainter;
+ friend class QPainterPrivate;
+ friend class QPSPrintEngineFont;
+ friend class QApplication;
+ friend class QWidget;
+ friend class QWidgetPrivate;
+ friend class Q3TextFormatCollection;
+ friend class QTextLayout;
+ friend class QTextEngine;
+ friend class QStackTextEngine;
+ friend class QTextLine;
+ friend struct QScriptLine;
+ friend class QGLContext;
+ friend class QWin32PaintEngine;
+ friend class QAlphaPaintEngine;
+ friend class QPainterPath;
+ friend class QTextItemInt;
+ friend class QPicturePaintEngine;
+ friend class QPainterReplayer;
+ friend class QPaintBufferEngine;
+ friend class QCommandLinkButtonPrivate;
+ friend class QFontEngine;
+
+#ifndef QT_NO_DATASTREAM
+ friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QFont &);
+ friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QFont &);
+#endif
+
+ QExplicitlySharedDataPointer<QFontPrivate> d;
+ uint resolve_mask;
+};
+
+
+inline bool QFont::bold() const
+{ return weight() > Normal; }
+
+
+inline void QFont::setBold(bool enable)
+{ setWeight(enable ? Bold : Normal); }
+
+inline bool QFont::italic() const
+{
+ return (style() != StyleNormal);
+}
+
+inline void QFont::setItalic(bool b) {
+ setStyle(b ? StyleItalic : StyleNormal);
+}
+
+
+/*****************************************************************************
+ QFont stream functions
+ *****************************************************************************/
+
+#ifndef QT_NO_DATASTREAM
+Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QFont &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QFont &);
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QFont &);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFONT_H
diff --git a/src/gui/text/qfont_mac.cpp b/src/gui/text/qfont_mac.cpp
new file mode 100644
index 0000000000..daf68c03ea
--- /dev/null
+++ b/src/gui/text/qfont_mac.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qfont.h"
+#include "qfont_p.h"
+#include "qfontengine_p.h"
+#include "qfontengine_mac_p.h"
+#include "qfontinfo.h"
+#include "qfontmetrics.h"
+#include "qpaintdevice.h"
+#include "qstring.h"
+#include <private/qt_mac_p.h>
+#include <private/qtextengine_p.h>
+#include <private/qunicodetables_p.h>
+#include <qapplication.h>
+#include "qfontdatabase.h"
+#include <qpainter.h>
+#include "qtextengine_p.h"
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+extern float qt_mac_defaultDpi_x(); //qpaintdevice_mac.cpp
+
+int qt_mac_pixelsize(const QFontDef &def, int dpi)
+{
+ float ret;
+ if(def.pixelSize == -1)
+ ret = def.pointSize * dpi / qt_mac_defaultDpi_x();
+ else
+ ret = def.pixelSize;
+ return qRound(ret);
+}
+int qt_mac_pointsize(const QFontDef &def, int dpi)
+{
+ float ret;
+ if(def.pointSize < 0)
+ ret = def.pixelSize * qt_mac_defaultDpi_x() / float(dpi);
+ else
+ ret = def.pointSize;
+ return qRound(ret);
+}
+
+QString QFont::rawName() const
+{
+ return family();
+}
+
+void QFont::setRawName(const QString &name)
+{
+ setFamily(name);
+}
+
+void QFont::cleanup()
+{
+ QFontCache::cleanup();
+}
+
+/*!
+ Returns an ATSUFontID
+*/
+quint32 QFont::macFontID() const // ### need 64-bit version
+{
+#ifdef QT_MAC_USE_COCOA
+ return 0;
+#elif 1
+ QFontEngine *fe = d->engineForScript(QUnicodeTables::Common);
+ if (fe && fe->type() == QFontEngine::Multi)
+ return static_cast<QFontEngineMacMulti*>(fe)->macFontID();
+#else
+ Str255 name;
+ if(FMGetFontFamilyName((FMFontFamily)((UInt32)handle()), name) == noErr) {
+ short fnum;
+ GetFNum(name, &fnum);
+ return fnum;
+ }
+#endif
+ return 0;
+}
+
+// Returns an ATSUFonFamilyRef
+Qt::HANDLE QFont::handle() const
+{
+#if 0
+ QFontEngine *fe = d->engineForScript(QUnicodeTables::Common);
+ if (fe && fe->type() == QFontEngine::Mac)
+ return (Qt::HANDLE)static_cast<QFontEngineMacMulti*>(fe)->fontFamilyRef();
+#endif
+ return 0;
+}
+
+void QFont::initialize()
+{ }
+
+QString QFont::defaultFamily() const
+{
+ switch(d->request.styleHint) {
+ case QFont::Times:
+ return QString::fromLatin1("Times New Roman");
+ case QFont::Courier:
+ return QString::fromLatin1("Courier New");
+ case QFont::Monospace:
+ return QString::fromLatin1("Courier");
+ case QFont::Decorative:
+ return QString::fromLatin1("Bookman Old Style");
+ case QFont::Cursive:
+ return QString::fromLatin1("Apple Chancery");
+ case QFont::Fantasy:
+ return QString::fromLatin1("Papyrus");
+ case QFont::Helvetica:
+ case QFont::System:
+ default:
+ return QString::fromLatin1("Helvetica");
+ }
+}
+
+QString QFont::lastResortFamily() const
+{
+ return QString::fromLatin1("Helvetica");
+}
+
+QString QFont::lastResortFont() const
+{
+ return QString::fromLatin1("Geneva");
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
new file mode 100644
index 0000000000..43dca81e55
--- /dev/null
+++ b/src/gui/text/qfont_p.h
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QFONT_P_H
+#define QFONT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of internal files. This header file may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtGui/qfont.h"
+#include "QtCore/qmap.h"
+#include "QtCore/qobject.h"
+#include <private/qunicodetables_p.h>
+#include <QtGui/qfontdatabase.h>
+#include "private/qfixed_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// forwards
+class QFontCache;
+class QFontEngine;
+
+struct QFontDef
+{
+ inline QFontDef()
+ : pointSize(-1.0), pixelSize(-1),
+ styleStrategy(QFont::PreferDefault), styleHint(QFont::AnyStyle),
+ weight(50), fixedPitch(false), style(QFont::StyleNormal), stretch(100),
+ ignorePitch(true), hintingPreference(QFont::PreferDefaultHinting)
+#ifdef Q_WS_MAC
+ ,fixedPitchComputed(false)
+#endif
+ {
+ }
+
+ QString family;
+
+#ifdef Q_WS_X11
+ QString addStyle;
+#endif // Q_WS_X11
+
+ qreal pointSize;
+ qreal pixelSize;
+
+ uint styleStrategy : 16;
+ uint styleHint : 8;
+
+ uint weight : 7; // 0-99
+ uint fixedPitch : 1;
+ uint style : 2;
+ uint stretch : 12; // 0-400
+
+ uint ignorePitch : 1;
+ uint hintingPreference : 2;
+ uint fixedPitchComputed : 1; // for Mac OS X only
+ int reserved : 14; // for future extensions
+
+ bool exactMatch(const QFontDef &other) const;
+ bool operator==(const QFontDef &other) const
+ {
+ return pixelSize == other.pixelSize
+ && weight == other.weight
+ && style == other.style
+ && stretch == other.stretch
+ && styleHint == other.styleHint
+ && styleStrategy == other.styleStrategy
+ && ignorePitch == other.ignorePitch && fixedPitch == other.fixedPitch
+ && family == other.family
+ && hintingPreference == other.hintingPreference
+#ifdef Q_WS_X11
+ && addStyle == other.addStyle
+#endif
+ ;
+ }
+ inline bool operator<(const QFontDef &other) const
+ {
+ if (pixelSize != other.pixelSize) return pixelSize < other.pixelSize;
+ if (weight != other.weight) return weight < other.weight;
+ if (style != other.style) return style < other.style;
+ if (stretch != other.stretch) return stretch < other.stretch;
+ if (styleHint != other.styleHint) return styleHint < other.styleHint;
+ if (styleStrategy != other.styleStrategy) return styleStrategy < other.styleStrategy;
+ if (family != other.family) return family < other.family;
+ if (hintingPreference != other.hintingPreference) return hintingPreference < other.hintingPreference;
+
+#ifdef Q_WS_X11
+ if (addStyle != other.addStyle) return addStyle < other.addStyle;
+#endif // Q_WS_X11
+
+ if (ignorePitch != other.ignorePitch) return ignorePitch < other.ignorePitch;
+ if (fixedPitch != other.fixedPitch) return fixedPitch < other.fixedPitch;
+ return false;
+ }
+};
+
+class QFontEngineData
+{
+public:
+ QFontEngineData();
+ ~QFontEngineData();
+
+ QAtomicInt ref;
+ QFontCache *fontCache;
+
+#if !defined(Q_WS_MAC)
+ QFontEngine *engines[QUnicodeTables::ScriptCount];
+#else
+ QFontEngine *engine;
+#endif
+};
+
+
+class Q_GUI_EXPORT QFontPrivate
+{
+public:
+#ifdef Q_WS_X11
+ static int defaultEncodingID;
+#endif // Q_WS_X11
+
+ QFontPrivate();
+ QFontPrivate(const QFontPrivate &other);
+ ~QFontPrivate();
+
+ QFontEngine *engineForScript(int script) const;
+ void alterCharForCapitalization(QChar &c) const;
+
+ QAtomicInt ref;
+ QFontDef request;
+ mutable QFontEngineData *engineData;
+ int dpi;
+ int screen;
+
+#ifdef Q_WS_WIN
+ HDC hdc;
+#endif
+
+ uint rawMode : 1;
+ uint underline : 1;
+ uint overline : 1;
+ uint strikeOut : 1;
+ uint kerning : 1;
+ uint capital : 3;
+ bool letterSpacingIsAbsolute : 1;
+
+ QFixed letterSpacing;
+ QFixed wordSpacing;
+
+ mutable QFontPrivate *scFont;
+ QFont smallCapsFont() const { return QFont(smallCapsFontPrivate()); }
+ QFontPrivate *smallCapsFontPrivate() const;
+
+ static QFontPrivate *get(const QFont &font)
+ {
+ return font.d.data();
+ }
+
+ void resolve(uint mask, const QFontPrivate *other);
+private:
+ QFontPrivate &operator=(const QFontPrivate &) { return *this; }
+};
+
+
+class QFontCache : public QObject
+{
+ Q_OBJECT
+public:
+ // note: these static functions work on a per-thread basis
+ static QFontCache *instance();
+ static void cleanup();
+
+ QFontCache();
+ ~QFontCache();
+
+ void clear();
+#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
+ void removeEngineForFont(const QByteArray &fontName);
+#endif
+ // universal key structure. QFontEngineDatas and QFontEngines are cached using
+ // the same keys
+ struct Key {
+ Key() : script(0), screen(0) { }
+ Key(const QFontDef &d, int c, int s = 0)
+ : def(d), script(c), screen(s) { }
+
+ QFontDef def;
+ int script;
+ int screen;
+
+ inline bool operator<(const Key &other) const
+ {
+ if (script != other.script) return script < other.script;
+ if (screen != other.screen) return screen < other.screen;
+ return def < other.def;
+ }
+ inline bool operator==(const Key &other) const
+ { return def == other.def && script == other.script && screen == other.screen; }
+ };
+
+ // QFontEngineData cache
+ typedef QMap<Key,QFontEngineData*> EngineDataCache;
+ EngineDataCache engineDataCache;
+
+ QFontEngineData *findEngineData(const Key &key) const;
+ void insertEngineData(const Key &key, QFontEngineData *engineData);
+
+ // QFontEngine cache
+ struct Engine {
+ Engine() : data(0), timestamp(0), hits(0) { }
+ Engine(QFontEngine *d) : data(d), timestamp(0), hits(0) { }
+
+ QFontEngine *data;
+ uint timestamp;
+ uint hits;
+ };
+
+ typedef QMap<Key,Engine> EngineCache;
+ EngineCache engineCache;
+
+ QFontEngine *findEngine(const Key &key);
+ void insertEngine(const Key &key, QFontEngine *engine);
+
+#if defined(Q_WS_WIN) || defined(Q_WS_QWS)
+ void cleanupPrinterFonts();
+#endif
+
+ private:
+ void increaseCost(uint cost);
+ void decreaseCost(uint cost);
+ void timerEvent(QTimerEvent *event);
+
+ static const uint min_cost;
+ uint total_cost, max_cost;
+ uint current_timestamp;
+ bool fast;
+ int timer_id;
+};
+
+Q_GUI_EXPORT int qt_defaultDpiX();
+Q_GUI_EXPORT int qt_defaultDpiY();
+Q_GUI_EXPORT int qt_defaultDpi();
+
+QT_END_NAMESPACE
+
+#endif // QFONT_P_H
diff --git a/src/gui/text/qfont_qpa.cpp b/src/gui/text/qfont_qpa.cpp
new file mode 100644
index 0000000000..ff12da8d97
--- /dev/null
+++ b/src/gui/text/qfont_qpa.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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,QFont::StyleHint(d->request.styleHint),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/qfont_qws.cpp b/src/gui/text/qfont_qws.cpp
new file mode 100644
index 0000000000..ea2a944432
--- /dev/null
+++ b/src/gui/text/qfont_qws.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qwidget.h"
+#include "qpainter.h"
+#include "qfont_p.h"
+#include <private/qunicodetables_p.h>
+#include "qfontdatabase.h"
+#include "qtextcodec.h"
+#include "qapplication.h"
+#include "qfile.h"
+#include "qtextstream.h"
+#include "qmap.h"
+//#include "qmemorymanager_qws.h"
+#include "qtextengine_p.h"
+#include "qfontengine_p.h"
+#if !defined(QT_NO_FREETYPE)
+#include "qfontengine_ft_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+void QFont::initialize()
+{ }
+
+void QFont::cleanup()
+{
+ QFontCache::cleanup();
+}
+
+
+/*****************************************************************************
+ QFont member functions
+ *****************************************************************************/
+
+Qt::HANDLE QFont::handle() const
+{
+#ifndef QT_NO_FREETYPE
+ return freetypeFace();
+#endif
+ return 0;
+}
+
+FT_Face QFont::freetypeFace() const
+{
+#ifndef QT_NO_FREETYPE
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ if (engine->type() == QFontEngine::Multi)
+ engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
+ if (engine->type() == QFontEngine::Freetype) {
+ const QFontEngineFT *ft = static_cast<const QFontEngineFT *>(engine);
+ return ft->non_locked_face();
+ }
+#endif
+ return 0;
+}
+
+QString QFont::rawName() const
+{
+ return QLatin1String("unknown");
+}
+
+void QFont::setRawName(const QString &)
+{
+}
+
+QString QFont::defaultFamily() const
+{
+ switch(d->request.styleHint) {
+ case QFont::Times:
+ return QString::fromLatin1("times");
+ case QFont::Courier:
+ case QFont::Monospace:
+ return QString::fromLatin1("courier");
+ case QFont::Decorative:
+ return QString::fromLatin1("old english");
+ case QFont::Helvetica:
+ case QFont::System:
+ default:
+ return QString::fromLatin1("helvetica");
+ }
+}
+
+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/qfont_s60.cpp b/src/gui/text/qfont_s60.cpp
new file mode 100644
index 0000000000..114191d765
--- /dev/null
+++ b/src/gui/text/qfont_s60.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qfont.h"
+#include "qfont_p.h"
+#include <private/qt_s60_p.h>
+#include <private/qpixmap_s60_p.h>
+#include "qmutex.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QT_NO_FREETYPE
+Q_GLOBAL_STATIC(QMutex, lastResortFamilyMutex);
+#endif // QT_NO_FREETYPE
+
+extern QStringList qt_symbian_fontFamiliesOnFontServer(); // qfontdatabase_s60.cpp
+Q_GLOBAL_STATIC_WITH_INITIALIZER(QStringList, fontFamiliesOnFontServer, {
+ // We are only interested in the initial font families. No Application fonts.
+ // Therefore, we are allowed to cache the list.
+ x->append(qt_symbian_fontFamiliesOnFontServer());
+});
+
+QString QFont::lastResortFont() const
+{
+ // Symbian's font Api does not distinguish between font and family.
+ // Therefore we try to get a "Family" first, then fall back to "Sans".
+ static QString font = lastResortFamily();
+ if (font.isEmpty())
+ font = QLatin1String("Sans");
+ return font;
+}
+
+QString QFont::lastResortFamily() const
+{
+#ifdef QT_NO_FREETYPE
+ QMutexLocker locker(lastResortFamilyMutex());
+ static QString family;
+ if (family.isEmpty()) {
+
+ QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
+
+ CFont *font;
+ const TInt err = S60->screenDevice()->GetNearestFontInTwips(font, TFontSpec());
+ Q_ASSERT(err == KErrNone);
+ const TFontSpec spec = font->FontSpecInTwips();
+ family = QString((const QChar *)spec.iTypeface.iName.Ptr(), spec.iTypeface.iName.Length());
+ S60->screenDevice()->ReleaseFont(font);
+
+ lock.relock();
+ }
+ return family;
+#else // QT_NO_FREETYPE
+ // For the FreeType case we just hard code the face name, since otherwise on
+ // East Asian systems we may get a name for a stroke based (non-ttf) font.
+
+ // TODO: Get the type face name in a proper way
+
+ const bool isJapaneseOrChineseSystem =
+ User::Language() == ELangJapanese || User::Language() == ELangPrcChinese;
+
+ static QString family;
+ if (family.isEmpty()) {
+ QStringList families = qt_symbian_fontFamiliesOnFontServer();
+ const char* const preferredFamilies[] = {"Nokia Sans S60", "Series 60 Sans"};
+ for (int i = 0; i < sizeof preferredFamilies / sizeof preferredFamilies[0]; ++i) {
+ const QString preferredFamily = QLatin1String(preferredFamilies[i]);
+ if (families.contains(preferredFamily)) {
+ family = preferredFamily;
+ break;
+ }
+ }
+ }
+
+ return QLatin1String(isJapaneseOrChineseSystem?"Heisei Kaku Gothic S60":family.toLatin1());
+#endif // QT_NO_FREETYPE
+}
+
+QString QFont::defaultFamily() const
+{
+#ifdef QT_NO_FREETYPE
+ switch(d->request.styleHint) {
+ case QFont::SansSerif: {
+ static const char* const preferredSansSerif[] = {"Nokia Sans S60", "Series 60 Sans"};
+ for (int i = 0; i < sizeof preferredSansSerif / sizeof preferredSansSerif[0]; ++i) {
+ const QString sansSerif = QLatin1String(preferredSansSerif[i]);
+ if (fontFamiliesOnFontServer()->contains(sansSerif))
+ return sansSerif;
+ }
+ }
+ // No break. Intentional fall through.
+ default:
+ return lastResortFamily();
+ }
+#endif // QT_NO_FREETYPE
+ return lastResortFamily();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfont_win.cpp b/src/gui/text/qfont_win.cpp
new file mode 100644
index 0000000000..3ef761bfa5
--- /dev/null
+++ b/src/gui/text/qfont_win.cpp
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qfont.h"
+#include "qfont_p.h"
+#include "qfontengine_p.h"
+#include "qtextengine_p.h"
+#include "qfontmetrics.h"
+#include "qfontinfo.h"
+
+#include "qwidget.h"
+#include "qpainter.h"
+#include <limits.h>
+#include "qt_windows.h"
+#include <private/qapplication_p.h>
+#include "qapplication.h"
+#include <private/qunicodetables_p.h>
+#include <qfontdatabase.h>
+
+QT_BEGIN_NAMESPACE
+
+extern HDC shared_dc(); // common dc for all fonts
+extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
+
+// ### maybe move to qapplication_win
+QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/)
+{
+ QString family = QString::fromWCharArray(lf.lfFaceName);
+ QFont qf(family);
+ qf.setItalic(lf.lfItalic);
+ if (lf.lfWeight != FW_DONTCARE)
+ qf.setWeight(weightFromInteger(lf.lfWeight));
+ int lfh = qAbs(lf.lfHeight);
+ qf.setPointSizeF(lfh * 72.0 / GetDeviceCaps(shared_dc(),LOGPIXELSY));
+ qf.setUnderline(false);
+ qf.setOverline(false);
+ qf.setStrikeOut(false);
+ return qf;
+}
+
+
+static inline float pixelSize(const QFontDef &request, int dpi)
+{
+ float pSize;
+ if (request.pointSize != -1)
+ pSize = request.pointSize * dpi/ 72.;
+ else
+ pSize = request.pixelSize;
+ return pSize;
+}
+
+static inline float pointSize(const QFontDef &fd, int dpi)
+{
+ float pSize;
+ if (fd.pointSize < 0)
+ pSize = fd.pixelSize * 72. / ((float)dpi);
+ else
+ pSize = fd.pointSize;
+ return pSize;
+}
+
+/*****************************************************************************
+ QFont member functions
+ *****************************************************************************/
+
+void QFont::initialize()
+{
+}
+
+void QFont::cleanup()
+{
+ QFontCache::cleanup();
+}
+
+HFONT QFont::handle() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ if (engine->type() == QFontEngine::Multi)
+ engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
+ if (engine->type() == QFontEngine::Win)
+ return static_cast<QFontEngineWin *>(engine)->hfont;
+ return 0;
+}
+
+QString QFont::rawName() const
+{
+ return family();
+}
+
+void QFont::setRawName(const QString &name)
+{
+ setFamily(name);
+}
+
+QString QFont::defaultFamily() const
+{
+ switch(d->request.styleHint) {
+ case QFont::Times:
+ return QString::fromLatin1("Times New Roman");
+ case QFont::Courier:
+ case QFont::Monospace:
+ return QString::fromLatin1("Courier New");
+ case QFont::Decorative:
+ return QString::fromLatin1("Bookman Old Style");
+ case QFont::Cursive:
+ return QString::fromLatin1("Comic Sans MS");
+ case QFont::Fantasy:
+ return QString::fromLatin1("Impact");
+ case QFont::Helvetica:
+ return QString::fromLatin1("Arial");
+ case QFont::System:
+ default:
+ return QString::fromLatin1("MS Sans Serif");
+ }
+}
+
+QString QFont::lastResortFamily() const
+{
+ return QString::fromLatin1("helvetica");
+}
+
+QString QFont::lastResortFont() const
+{
+ return QString::fromLatin1("arial");
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfont_x11.cpp b/src/gui/text/qfont_x11.cpp
new file mode 100644
index 0000000000..c72a5fade5
--- /dev/null
+++ b/src/gui/text/qfont_x11.cpp
@@ -0,0 +1,368 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#define QT_FATAL_ASSERT
+
+#include "qplatformdefs.h"
+
+#include "qfont.h"
+#include "qapplication.h"
+#include "qfontinfo.h"
+#include "qfontdatabase.h"
+#include "qfontmetrics.h"
+#include "qpaintdevice.h"
+#include "qtextcodec.h"
+#include "qiodevice.h"
+#include "qhash.h"
+
+#include <private/qunicodetables_p.h>
+#include "qfont_p.h"
+#include "qfontengine_p.h"
+#include "qfontengine_x11_p.h"
+#include "qtextengine_p.h"
+
+#include <private/qt_x11_p.h>
+#include "qx11info_x11.h"
+
+#include <time.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define QFONTLOADER_DEBUG
+#define QFONTLOADER_DEBUG_VERBOSE
+
+QT_BEGIN_NAMESPACE
+
+double qt_pixelSize(double pointSize, int dpi)
+{
+ if (pointSize < 0)
+ return -1.;
+ if (dpi == 75) // the stupid 75 dpi setting on X11
+ dpi = 72;
+ return (pointSize * dpi) /72.;
+}
+
+double qt_pointSize(double pixelSize, int dpi)
+{
+ if (pixelSize < 0)
+ return -1.;
+ if (dpi == 75) // the stupid 75 dpi setting on X11
+ dpi = 72;
+ return pixelSize * 72. / ((double) dpi);
+}
+
+/*
+ Removes wildcards from an XLFD.
+
+ Returns \a xlfd with all wildcards removed if a match for \a xlfd is
+ found, otherwise it returns \a xlfd.
+*/
+static QByteArray qt_fixXLFD(const QByteArray &xlfd)
+{
+ QByteArray ret = xlfd;
+ int count = 0;
+ char **fontNames =
+ XListFonts(QX11Info::display(), xlfd, 32768, &count);
+ if (count > 0)
+ ret = fontNames[0];
+ XFreeFontNames(fontNames);
+ return ret ;
+}
+
+typedef QHash<int, QString> FallBackHash;
+Q_GLOBAL_STATIC(FallBackHash, fallBackHash)
+
+// Returns the user-configured fallback family for the specified script.
+QString qt_fallback_font_family(int script)
+{
+ FallBackHash *hash = fallBackHash();
+ return hash->value(script);
+}
+
+// Sets the fallback family for the specified script.
+Q_GUI_EXPORT void qt_x11_set_fallback_font_family(int script, const QString &family)
+{
+ FallBackHash *hash = fallBackHash();
+ if (!family.isEmpty())
+ hash->insert(script, family);
+ else
+ hash->remove(script);
+}
+
+int QFontPrivate::defaultEncodingID = -1;
+
+void QFont::initialize()
+{
+ extern int qt_encoding_id_for_mib(int mib); // from qfontdatabase_x11.cpp
+ QTextCodec *codec = QTextCodec::codecForLocale();
+ // determine the default encoding id using the locale, otherwise
+ // fallback to latin1 (mib == 4)
+ int mib = codec ? codec->mibEnum() : 4;
+
+ // for asian locales, use the mib for the font codec instead of the locale codec
+ switch (mib) {
+ case 38: // eucKR
+ mib = 36;
+ break;
+
+ case 2025: // GB2312
+ mib = 57;
+ break;
+
+ case 113: // GBK
+ mib = -113;
+ break;
+
+ case 114: // GB18030
+ mib = -114;
+ break;
+
+ case 2026: // Big5
+ mib = -2026;
+ break;
+
+ case 2101: // Big5-HKSCS
+ mib = -2101;
+ break;
+
+ case 16: // JIS7
+ mib = 15;
+ break;
+
+ case 17: // SJIS
+ case 18: // eucJP
+ mib = 63;
+ break;
+ }
+
+ // get the default encoding id for the locale encoding...
+ QFontPrivate::defaultEncodingID = qt_encoding_id_for_mib(mib);
+}
+
+void QFont::cleanup()
+{
+ QFontCache::cleanup();
+}
+
+/*!
+ \internal
+ X11 Only: Returns the screen with which this font is associated.
+*/
+int QFont::x11Screen() const
+{
+ return d->screen;
+}
+
+/*! \internal
+ X11 Only: Associate the font with the specified \a screen.
+*/
+void QFont::x11SetScreen(int screen)
+{
+ if (screen < 0) // assume default
+ screen = QX11Info::appScreen();
+
+ if (screen == d->screen)
+ return; // nothing to do
+
+ detach();
+ d->screen = screen;
+}
+
+Qt::HANDLE QFont::handle() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ if (engine->type() == QFontEngine::Multi)
+ engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
+ if (engine->type() == QFontEngine::XLFD)
+ return static_cast<QFontEngineXLFD *>(engine)->fontStruct()->fid;
+ return 0;
+}
+
+
+FT_Face QFont::freetypeFace() const
+{
+#ifndef QT_NO_FREETYPE
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ if (engine->type() == QFontEngine::Multi)
+ engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
+#ifndef QT_NO_FONTCONFIG
+ if (engine->type() == QFontEngine::Freetype) {
+ const QFontEngineFT *ft = static_cast<const QFontEngineFT *>(engine);
+ return ft->non_locked_face();
+ } else
+#endif
+ if (engine->type() == QFontEngine::XLFD) {
+ const QFontEngineXLFD *xlfd = static_cast<const QFontEngineXLFD *>(engine);
+ return xlfd->non_locked_face();
+ }
+#endif
+ return 0;
+}
+
+QString QFont::rawName() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ if (engine->type() == QFontEngine::Multi)
+ engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
+ if (engine->type() == QFontEngine::XLFD)
+ return QString::fromLatin1(engine->name());
+ return QString();
+}
+struct QtFontDesc;
+
+void QFont::setRawName(const QString &name)
+{
+ detach();
+
+ // from qfontdatabase_x11.cpp
+ extern bool qt_fillFontDef(const QByteArray &xlfd, QFontDef *fd, int dpi, QtFontDesc *desc);
+
+ if (!qt_fillFontDef(qt_fixXLFD(name.toLatin1()), &d->request, d->dpi, 0)) {
+ qWarning("QFont::setRawName: Invalid XLFD: \"%s\"", name.toLatin1().constData());
+
+ setFamily(name);
+ setRawMode(true);
+ } else {
+ resolve_mask = QFont::AllPropertiesResolved;
+ }
+}
+
+QString QFont::lastResortFamily() const
+{
+ return QString::fromLatin1("Helvetica");
+}
+
+QString QFont::defaultFamily() const
+{
+ switch (d->request.styleHint) {
+ case QFont::Times:
+ return QString::fromLatin1("Times");
+
+ case QFont::Courier:
+ return QString::fromLatin1("Courier");
+
+ case QFont::Monospace:
+ return QString::fromLatin1("Courier New");
+
+ case QFont::Cursive:
+ return QString::fromLatin1("Comic Sans MS");
+
+ case QFont::Fantasy:
+ return QString::fromLatin1("Impact");
+
+ case QFont::Decorative:
+ return QString::fromLatin1("Old English");
+
+ case QFont::Helvetica:
+ case QFont::System:
+ default:
+ return QString::fromLatin1("Helvetica");
+ }
+}
+
+/*
+ Returns a last resort raw font name for the font matching algorithm.
+ This is used if even the last resort family is not available. It
+ returns \e something, almost no matter what. The current
+ implementation tries a wide variety of common fonts, returning the
+ first one it finds. The implementation may change at any time.
+*/
+static const char * const tryFonts[] = {
+ "-*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*",
+ "-*-courier-medium-r-*-*-*-120-*-*-*-*-*-*",
+ "-*-times-medium-r-*-*-*-120-*-*-*-*-*-*",
+ "-*-lucida-medium-r-*-*-*-120-*-*-*-*-*-*",
+ "-*-helvetica-*-*-*-*-*-120-*-*-*-*-*-*",
+ "-*-courier-*-*-*-*-*-120-*-*-*-*-*-*",
+ "-*-times-*-*-*-*-*-120-*-*-*-*-*-*",
+ "-*-lucida-*-*-*-*-*-120-*-*-*-*-*-*",
+ "-*-helvetica-*-*-*-*-*-*-*-*-*-*-*-*",
+ "-*-courier-*-*-*-*-*-*-*-*-*-*-*-*",
+ "-*-times-*-*-*-*-*-*-*-*-*-*-*-*",
+ "-*-lucida-*-*-*-*-*-*-*-*-*-*-*-*",
+ "-*-fixed-*-*-*-*-*-*-*-*-*-*-*-*",
+ "6x13",
+ "7x13",
+ "8x13",
+ "9x15",
+ "fixed",
+ 0
+};
+
+// Returns true if the font exists, false otherwise
+static bool fontExists(const QString &fontName)
+{
+ int count;
+ char **fontNames = XListFonts(QX11Info::display(), (char*)fontName.toLatin1().constData(), 32768, &count);
+ if (fontNames) XFreeFontNames(fontNames);
+
+ return count != 0;
+}
+
+QString QFont::lastResortFont() const
+{
+ static QString last;
+
+ // already found
+ if (! last.isNull())
+ return last;
+
+ int i = 0;
+ const char* f;
+
+ while ((f = tryFonts[i])) {
+ last = QString::fromLatin1(f);
+
+ if (fontExists(last))
+ return last;
+
+ i++;
+ }
+
+#if defined(CHECK_NULL)
+ qFatal("QFontPrivate::lastResortFont: Cannot find any reasonable font");
+#endif
+ return last;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
new file mode 100644
index 0000000000..36b0ea9b68
--- /dev/null
+++ b/src/gui/text/qfontdatabase.cpp
@@ -0,0 +1,2715 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 <qdir.h>
+#include "qfontdatabase.h"
+#include "qdebug.h"
+#include "qalgorithms.h"
+#include "qapplication.h"
+#include "qvarlengtharray.h" // here or earlier - workaround for VC++6
+#include "qthread.h"
+#include "qmutex.h"
+#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_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
+# include <ft2build.h>
+# include FT_TRUETYPE_TABLES_H
+#endif
+
+// #define QFONTDATABASE_DEBUG
+#ifdef QFONTDATABASE_DEBUG
+# define FD_DEBUG qDebug
+#else
+# define FD_DEBUG if (false) qDebug
+#endif
+
+// #define FONT_MATCH_DEBUG
+#ifdef FONT_MATCH_DEBUG
+# define FM_DEBUG qDebug
+#else
+# define FM_DEBUG if (false) qDebug
+#endif
+
+#if defined(Q_WS_WIN) && !defined(QT_NO_DIRECTWRITE)
+# include <dwrite.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#define SMOOTH_SCALABLE 0xffff
+
+bool qt_enable_test_font = false;
+
+Q_AUTOTEST_EXPORT void qt_setQtEnableTestFont(bool value)
+{
+ qt_enable_test_font = value;
+}
+
+static int getFontWeight(const QString &weightString)
+{
+ QString s = weightString.toLower();
+
+ // Test in decreasing order of commonness
+ if (s == QLatin1String("medium") ||
+ s == QLatin1String("normal")
+ || s.compare(QApplication::translate("QFontDatabase", "Normal"), Qt::CaseInsensitive) == 0)
+ return QFont::Normal;
+ if (s == QLatin1String("bold")
+ || s.compare(QApplication::translate("QFontDatabase", "Bold"), Qt::CaseInsensitive) == 0)
+ return QFont::Bold;
+ if (s == QLatin1String("demibold") || s == QLatin1String("demi bold")
+ || s.compare(QApplication::translate("QFontDatabase", "Demi Bold"), Qt::CaseInsensitive) == 0)
+ return QFont::DemiBold;
+ if (s == QLatin1String("black")
+ || s.compare(QApplication::translate("QFontDatabase", "Black"), Qt::CaseInsensitive) == 0)
+ return QFont::Black;
+ if (s == QLatin1String("light"))
+ return QFont::Light;
+
+ if (s.contains(QLatin1String("bold"))
+ || s.contains(QApplication::translate("QFontDatabase", "Bold"), Qt::CaseInsensitive)) {
+ if (s.contains(QLatin1String("demi"))
+ || s.compare(QApplication::translate("QFontDatabase", "Demi"), Qt::CaseInsensitive) == 0)
+ return (int) QFont::DemiBold;
+ return (int) QFont::Bold;
+ }
+
+ if (s.contains(QLatin1String("light"))
+ || s.compare(QApplication::translate("QFontDatabase", "Light"), Qt::CaseInsensitive) == 0)
+ return (int) QFont::Light;
+
+ if (s.contains(QLatin1String("black"))
+ || s.compare(QApplication::translate("QFontDatabase", "Black"), Qt::CaseInsensitive) == 0)
+ return (int) QFont::Black;
+
+ return (int) QFont::Normal;
+}
+
+// convert 0 ~ 1000 integer to QFont::Weight
+QFont::Weight weightFromInteger(int weight)
+{
+ if (weight < 400)
+ return QFont::Light;
+ else if (weight < 600)
+ return QFont::Normal;
+ else if (weight < 700)
+ return QFont::DemiBold;
+ else if (weight < 800)
+ return QFont::Bold;
+ else
+ return QFont::Black;
+}
+
+struct QtFontEncoding
+{
+ signed int encoding : 16;
+
+ uint xpoint : 16;
+ uint xres : 8;
+ uint yres : 8;
+ uint avgwidth : 16;
+ uchar pitch : 8;
+};
+
+struct QtFontSize
+{
+#ifdef Q_WS_X11
+ QtFontEncoding *encodings;
+ QtFontEncoding *encodingID(int id, uint xpoint = 0, uint xres = 0,
+ uint yres = 0, uint avgwidth = 0, bool add = false);
+ unsigned short count : 16;
+#endif // Q_WS_X11
+
+#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;
+};
+
+
+#ifdef Q_WS_X11
+QtFontEncoding *QtFontSize::encodingID(int id, uint xpoint, uint xres,
+ uint yres, uint avgwidth, bool add)
+{
+ // we don't match using the xpoint, xres and yres parameters, only the id
+ for (int i = 0; i < count; ++i) {
+ if (encodings[i].encoding == id)
+ return encodings + i;
+ }
+
+ if (!add) return 0;
+
+ if (!(count % 4)) {
+ QtFontEncoding *newEncodings = (QtFontEncoding *)
+ realloc(encodings,
+ (((count+4) >> 2) << 2) * sizeof(QtFontEncoding));
+ Q_CHECK_PTR(newEncodings);
+ encodings = newEncodings;
+ }
+ encodings[count].encoding = id;
+ encodings[count].xpoint = xpoint;
+ encodings[count].xres = xres;
+ encodings[count].yres = yres;
+ encodings[count].avgwidth = avgwidth;
+ encodings[count].pitch = '*';
+ return encodings + count++;
+}
+#endif // Q_WS_X11
+
+struct QtFontStyle
+{
+ struct Key {
+ Key(const QString &styleString);
+ Key() : style(QFont::StyleNormal),
+ weight(QFont::Normal), stretch(0) { }
+ Key(const Key &o) : style(o.style),
+ weight(o.weight), stretch(o.stretch) { }
+ uint style : 2;
+ signed int weight : 8;
+ signed int stretch : 12;
+
+ bool operator==(const Key & other) {
+ return (style == other.style &&
+ weight == other.weight &&
+ (stretch == 0 || other.stretch == 0 || stretch == other.stretch));
+ }
+ bool operator!=(const Key &other) {
+ return !operator==(other);
+ }
+ bool operator <(const Key &o) {
+ int x = (style << 12) + (weight << 14) + stretch;
+ int y = (o.style << 12) + (o.weight << 14) + o.stretch;
+ return (x < y);
+ }
+ };
+
+ QtFontStyle(const Key &k)
+ : key(k), bitmapScalable(false), smoothScalable(false),
+ count(0), pixelSizes(0)
+ {
+#if defined(Q_WS_X11)
+ weightName = setwidthName = 0;
+#endif // Q_WS_X11
+ }
+
+ ~QtFontStyle() {
+#ifdef Q_WS_X11
+ delete [] weightName;
+ delete [] setwidthName;
+#endif
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN)
+ while (count) {
+ // bitfield count-- in while condition does not work correctly in mwccsym2
+ count--;
+#ifdef Q_WS_X11
+ free(pixelSizes[count].encodings);
+#endif
+#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);
+ }
+
+ Key key;
+ bool bitmapScalable : 1;
+ bool smoothScalable : 1;
+ signed int count : 30;
+ QtFontSize *pixelSizes;
+
+#ifdef Q_WS_X11
+ const char *weightName;
+ const char *setwidthName;
+#endif // Q_WS_X11
+#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN)
+ bool antialiased;
+#endif
+
+ QtFontSize *pixelSize(unsigned short size, bool = false);
+};
+
+QtFontStyle::Key::Key(const QString &styleString)
+ : style(QFont::StyleNormal), weight(QFont::Normal), stretch(0)
+{
+ weight = getFontWeight(styleString);
+
+ if (styleString.contains(QLatin1String("Italic"))
+ || styleString.contains(QApplication::translate("QFontDatabase", "Italic")))
+ style = QFont::StyleItalic;
+ else if (styleString.contains(QLatin1String("Oblique"))
+ || styleString.contains(QApplication::translate("QFontDatabase", "Oblique")))
+ style = QFont::StyleOblique;
+}
+
+QtFontSize *QtFontStyle::pixelSize(unsigned short size, bool add)
+{
+ for (int i = 0; i < count; i++) {
+ if (pixelSizes[i].pixelSize == size)
+ return pixelSizes + i;
+ }
+ if (!add)
+ return 0;
+
+ if (!pixelSizes) {
+ // Most style have only one font size, we avoid waisting memory
+ QtFontSize *newPixelSizes = (QtFontSize *)malloc(sizeof(QtFontSize));
+ Q_CHECK_PTR(newPixelSizes);
+ pixelSizes = newPixelSizes;
+ } else if (!(count % 8) || count == 1) {
+ QtFontSize *newPixelSizes = (QtFontSize *)
+ realloc(pixelSizes,
+ (((count+8) >> 3) << 3) * sizeof(QtFontSize));
+ Q_CHECK_PTR(newPixelSizes);
+ pixelSizes = newPixelSizes;
+ }
+ pixelSizes[count].pixelSize = size;
+#ifdef Q_WS_X11
+ pixelSizes[count].count = 0;
+ pixelSizes[count].encodings = 0;
+#endif
+#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++);
+}
+
+struct QtFontFoundry
+{
+ QtFontFoundry(const QString &n) : name(n), count(0), styles(0) {}
+ ~QtFontFoundry() {
+ while (count--)
+ delete styles[count];
+ free(styles);
+ }
+
+ QString name;
+
+ int count;
+ QtFontStyle **styles;
+ QtFontStyle *style(const QtFontStyle::Key &, bool = false);
+};
+
+QtFontStyle *QtFontFoundry::style(const QtFontStyle::Key &key, bool create)
+{
+ int pos = 0;
+ if (count) {
+ int low = 0;
+ int high = count;
+ pos = count / 2;
+ while (high > low) {
+ if (styles[pos]->key == key)
+ return styles[pos];
+ if (styles[pos]->key < key)
+ low = pos + 1;
+ else
+ high = pos;
+ pos = (high + low) / 2;
+ }
+ pos = low;
+ }
+ if (!create)
+ return 0;
+
+// qDebug("adding key (weight=%d, style=%d, oblique=%d stretch=%d) at %d", key.weight, key.style, key.oblique, key.stretch, pos);
+ if (!(count % 8)) {
+ QtFontStyle **newStyles = (QtFontStyle **)
+ realloc(styles, (((count+8) >> 3) << 3) * sizeof(QtFontStyle *));
+ Q_CHECK_PTR(newStyles);
+ styles = newStyles;
+ }
+
+ QtFontStyle *style = new QtFontStyle(key);
+ memmove(styles + pos + 1, styles + pos, (count-pos)*sizeof(QtFontStyle *));
+ styles[pos] = style;
+ count++;
+ return styles[pos];
+}
+
+
+struct QtFontFamily
+{
+ enum WritingSystemStatus {
+ Unknown = 0,
+ Supported = 1,
+ UnsupportedFT = 2,
+ UnsupportedXLFD = 4,
+ Unsupported = UnsupportedFT | UnsupportedXLFD
+ };
+
+ QtFontFamily(const QString &n)
+ :
+#ifdef Q_WS_X11
+ fixedPitch(true), ftWritingSystemCheck(false),
+ xlfdLoaded(false), synthetic(false), symbol_checked(false),
+#else
+ fixedPitch(false),
+#endif
+#ifdef Q_WS_WIN
+ writingSystemCheck(false),
+ loaded(false),
+#endif
+#if !defined(QWS) && defined(Q_OS_MAC)
+ fixedPitchComputed(false),
+#endif
+ name(n), count(0), foundries(0)
+#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));
+ }
+ ~QtFontFamily() {
+ while (count--)
+ delete foundries[count];
+ free(foundries);
+ }
+
+ bool fixedPitch : 1;
+#ifdef Q_WS_X11
+ bool ftWritingSystemCheck : 1;
+ bool xlfdLoaded : 1;
+ bool synthetic : 1;
+#endif
+#ifdef Q_WS_WIN
+ bool writingSystemCheck : 1;
+ bool loaded : 1;
+#endif
+#if !defined(QWS) && defined(Q_OS_MAC)
+ bool fixedPitchComputed : 1;
+#endif
+#ifdef Q_WS_X11
+ bool symbol_checked : 1;
+#endif
+
+ QString name;
+#if defined(Q_WS_X11) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
+ QByteArray fontFilename;
+ int fontFileIndex;
+#endif
+#ifdef Q_WS_WIN
+ QString english_name;
+#endif
+ int count;
+ QtFontFoundry **foundries;
+
+#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
+ 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);
+};
+
+#if !defined(QWS) && defined(Q_OS_MAC)
+inline static void qt_mac_get_fixed_pitch(QtFontFamily *f)
+{
+ if(f && !f->fixedPitchComputed) {
+ QFontMetrics fm(f->name);
+ f->fixedPitch = fm.width(QLatin1Char('i')) == fm.width(QLatin1Char('m'));
+ f->fixedPitchComputed = true;
+ }
+}
+#endif
+
+
+QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create)
+{
+ if (f.isNull() && count == 1)
+ return foundries[0];
+
+ for (int i = 0; i < count; i++) {
+ if (foundries[i]->name.compare(f, Qt::CaseInsensitive) == 0)
+ return foundries[i];
+ }
+ if (!create)
+ return 0;
+
+ if (!(count % 8)) {
+ QtFontFoundry **newFoundries = (QtFontFoundry **)
+ realloc(foundries,
+ (((count+8) >> 3) << 3) * sizeof(QtFontFoundry *));
+ Q_CHECK_PTR(newFoundries);
+ foundries = newFoundries;
+ }
+
+ foundries[count] = new QtFontFoundry(f);
+ return foundries[count++];
+}
+
+// ### copied to tools/makeqpf/qpf2.cpp
+
+// see the Unicode subset bitfields in the MSDN docs
+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 },
+};
+
+#define SimplifiedChineseCsbBit 18
+#define TraditionalChineseCsbBit 20
+#define JapaneseCsbBit 17
+#define KoreanCsbBit 21
+
+QList<QFontDatabase::WritingSystem> qt_determine_writing_systems_from_truetype_bits(quint32 unicodeRange[4], quint32 codePageRange[2])
+{
+ QList<QFontDatabase::WritingSystem> 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.append(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.append(QFontDatabase::SimplifiedChinese);
+ hasScript = true;
+ //qDebug("font %s supports Simplified Chinese", familyName.latin1());
+ }
+ if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
+ writingSystems.append(QFontDatabase::TraditionalChinese);
+ hasScript = true;
+ //qDebug("font %s supports Traditional Chinese", familyName.latin1());
+ }
+ if(codePageRange[0] & (1 << JapaneseCsbBit)) {
+ writingSystems.append(QFontDatabase::Japanese);
+ hasScript = true;
+ //qDebug("font %s supports Japanese", familyName.latin1());
+ }
+ if(codePageRange[0] & (1 << KoreanCsbBit)) {
+ writingSystems.append(QFontDatabase::Korean);
+ hasScript = true;
+ //qDebug("font %s supports Korean", familyName.latin1());
+ }
+ if (!hasScript)
+ writingSystems.append(QFontDatabase::Symbol);
+
+ return writingSystems;
+}
+
+#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
+// class with virtual destructor, derived in qfontdatabase_s60.cpp
+class QSymbianFontDatabaseExtras
+{
+public:
+ virtual ~QSymbianFontDatabaseExtras() {}
+};
+#endif
+
+class QFontDatabasePrivate
+{
+public:
+ QFontDatabasePrivate()
+ : count(0), families(0), reregisterAppFonts(false)
+#if defined(Q_WS_QWS)
+ , stream(0)
+#endif
+#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
+ , symbianExtras(0)
+#endif
+#if defined(Q_WS_WIN) && !defined(QT_NO_DIRECTWRITE)
+ , directWriteFactory(0)
+ , directWriteGdiInterop(0)
+#endif
+ { }
+
+ ~QFontDatabasePrivate() {
+ free();
+#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
+ if (symbianExtras)
+ delete symbianExtras;
+#endif
+#if defined(Q_WS_WIN) && !defined(QT_NO_DIRECTWRITE)
+ if (directWriteGdiInterop)
+ directWriteGdiInterop->Release();
+ if (directWriteFactory != 0)
+ directWriteFactory->Release();
+#endif
+ }
+ QtFontFamily *family(const QString &f, bool = false);
+ void free() {
+ while (count--)
+ delete families[count];
+ ::free(families);
+ families = 0;
+ count = 0;
+ // don't clear the memory fonts!
+ }
+
+ int count;
+#if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)
+ QString systemLang;
+#endif
+ QtFontFamily **families;
+
+#if defined(Q_WS_WIN) && !defined(QT_NO_DIRECTWRITE)
+ IDWriteFactory *directWriteFactory;
+ IDWriteGdiInterop *directWriteGdiInterop;
+#endif
+
+
+ struct ApplicationFont {
+ QString fileName;
+ QByteArray data;
+#if defined(Q_OS_WIN)
+ HANDLE handle;
+ bool memoryFont;
+ QVector<FONTSIGNATURE> signatures;
+#elif defined(Q_WS_MAC)
+ ATSFontContainerRef handle;
+#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
+ QString temporaryFileName;
+ TInt screenDeviceFontFileId;
+ TUid fontStoreFontFileUid;
+#endif
+ QStringList families;
+ };
+ QVector<ApplicationFont> applicationFonts;
+ int addAppFont(const QByteArray &fontData, const QString &fileName);
+ bool reregisterAppFonts;
+ bool isApplicationFont(const QString &fileName);
+
+ void invalidate();
+
+#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_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,
+ const QList<QFontDatabase::WritingSystem> &writingSystems = QList<QFontDatabase::WritingSystem>());
+#ifndef QT_NO_FREETYPE
+ QStringList addTTFile(const QByteArray &file, const QByteArray &fontData = QByteArray());
+#endif // QT_NO_FREETYPE
+#endif
+#if defined(Q_WS_QWS)
+ QDataStream *stream;
+#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
+ QSymbianFontDatabaseExtras *symbianExtras;
+#endif
+#if defined(Q_WS_QWS) || defined(Q_WS_QPA)
+ QStringList fallbackFamilies;
+#endif
+};
+
+void QFontDatabasePrivate::invalidate()
+{
+ QFontCache::instance()->clear();
+ free();
+ emit static_cast<QApplication *>(QApplication::instance())->fontDatabaseChanged();
+}
+
+QtFontFamily *QFontDatabasePrivate::family(const QString &f, bool create)
+{
+ int low = 0;
+ int high = count;
+ int pos = count / 2;
+ int res = 1;
+ if (count) {
+ while ((res = families[pos]->name.compare(f, Qt::CaseInsensitive)) && pos != low) {
+ if (res > 0)
+ high = pos;
+ else
+ low = pos;
+ pos = (high + low) / 2;
+ }
+ if (!res)
+ return families[pos];
+ }
+ if (!create)
+ return 0;
+
+ if (res < 0)
+ pos++;
+
+ // qDebug("adding family %s at %d total=%d", f.latin1(), pos, count);
+ if (!(count % 8)) {
+ QtFontFamily **newFamilies = (QtFontFamily **)
+ realloc(families,
+ (((count+8) >> 3) << 3) * sizeof(QtFontFamily *));
+ Q_CHECK_PTR(newFamilies);
+ families = newFamilies;
+ }
+
+ QtFontFamily *family = new QtFontFamily(f);
+ memmove(families + pos + 1, families + pos, (count-pos)*sizeof(QtFontFamily *));
+ families[pos] = family;
+ count++;
+ return families[pos];
+}
+
+#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)
+{
+// qDebug() << "Adding font" << familyname << weight << italic << pixelSize << file << fileIndex << antialiased;
+ QtFontStyle::Key styleKey;
+ styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
+ styleKey.weight = weight;
+ styleKey.stretch = 100;
+ QtFontFamily *f = family(familyname, true);
+
+ if (writingSystems.isEmpty()) {
+ for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
+ f->writingSystems[ws] = QtFontFamily::Supported;
+ }
+ f->bogusWritingSystems = true;
+ } else {
+ for (int i = 0; i < writingSystems.count(); ++i) {
+ f->writingSystems[writingSystems.at(i)] = QtFontFamily::Supported;
+ }
+ }
+
+ QtFontFoundry *foundry = f->foundry(QString::fromLatin1(foundryname), true);
+ QtFontStyle *style = foundry->style(styleKey, true);
+ style->smoothScalable = (pixelSize == 0);
+ style->antialiased = antialiased;
+ QtFontSize *size = style->pixelSize(pixelSize?pixelSize:SMOOTH_SCALABLE, true);
+ size->fileName = file;
+ size->fileIndex = fileIndex;
+
+#if defined(Q_WS_QWS)
+ if (stream) {
+ *stream << familyname << foundry->name << weight << quint8(italic) << pixelSize
+ << file << fileIndex << quint8(antialiased);
+ *stream << quint8(writingSystems.count());
+ for (int i = 0; i < writingSystems.count(); ++i)
+ *stream << quint8(writingSystems.at(i));
+ }
+#else // ..in case of defined(Q_OS_SYMBIAN) && !defined(QT_NO_FREETYPE)
+ f->fontFilename = file;
+ f->fontFileIndex = fileIndex;
+#endif
+}
+#endif
+
+#if (defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
+QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteArray &fontData)
+{
+ QStringList families;
+ 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, 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;
+ bool italic = face->style_flags & FT_STYLE_FLAG_ITALIC;
+
+ if (face->style_flags & FT_STYLE_FLAG_BOLD)
+ weight = QFont::Bold;
+
+ QList<QFontDatabase::WritingSystem> 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.append(QFontDatabase::Symbol);
+ break;
+ }
+ }
+ if (writingSystems.isEmpty()) {
+ 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 = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange);
+ //for (int i = 0; i < writingSystems.count(); ++i)
+ // qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i));
+ }
+ }
+
+ QString family = QString::fromAscii(face->family_name);
+ families.append(family);
+ addFont(family, /*foundry*/ "", weight, italic,
+ /*pixelsize*/ 0, file, index, /*antialias*/ true, writingSystems);
+
+ FT_Done_Face(face);
+ ++index;
+ } while (index < numFaces);
+ return families;
+}
+#endif
+
+static const int scriptForWritingSystem[] = {
+ QUnicodeTables::Common, // Any
+ QUnicodeTables::Latin, // Latin
+ QUnicodeTables::Greek, // Greek
+ QUnicodeTables::Cyrillic, // Cyrillic
+ QUnicodeTables::Armenian, // Armenian
+ QUnicodeTables::Hebrew, // Hebrew
+ QUnicodeTables::Arabic, // Arabic
+ QUnicodeTables::Syriac, // Syriac
+ QUnicodeTables::Thaana, // Thaana
+ QUnicodeTables::Devanagari, // Devanagari
+ QUnicodeTables::Bengali, // Bengali
+ QUnicodeTables::Gurmukhi, // Gurmukhi
+ QUnicodeTables::Gujarati, // Gujarati
+ QUnicodeTables::Oriya, // Oriya
+ QUnicodeTables::Tamil, // Tamil
+ QUnicodeTables::Telugu, // Telugu
+ QUnicodeTables::Kannada, // Kannada
+ QUnicodeTables::Malayalam, // Malayalam
+ QUnicodeTables::Sinhala, // Sinhala
+ QUnicodeTables::Thai, // Thai
+ QUnicodeTables::Lao, // Lao
+ QUnicodeTables::Tibetan, // Tibetan
+ QUnicodeTables::Myanmar, // Myanmar
+ QUnicodeTables::Georgian, // Georgian
+ QUnicodeTables::Khmer, // Khmer
+ QUnicodeTables::Common, // SimplifiedChinese
+ QUnicodeTables::Common, // TraditionalChinese
+ QUnicodeTables::Common, // Japanese
+ QUnicodeTables::Hangul, // Korean
+ QUnicodeTables::Common, // Vietnamese
+ QUnicodeTables::Common, // Yi
+ QUnicodeTables::Common, // Tagalog
+ QUnicodeTables::Common, // Hanunoo
+ QUnicodeTables::Common, // Buhid
+ QUnicodeTables::Common, // Tagbanwa
+ QUnicodeTables::Common, // Limbu
+ QUnicodeTables::Common, // TaiLe
+ QUnicodeTables::Common, // Braille
+ QUnicodeTables::Common, // Symbol
+ QUnicodeTables::Ogham, // Ogham
+ QUnicodeTables::Runic, // Runic
+ QUnicodeTables::Nko // Nko
+};
+
+int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem)
+{
+ return scriptForWritingSystem[writingSystem];
+}
+
+
+#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)
+ || 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);
+}
+#endif
+
+
+/*!
+ \internal
+
+ This makes sense of the font family name:
+
+ if the family name contains a '[' and a ']', then we take the text
+ between the square brackets as the foundry, and the text before the
+ square brackets as the family (ie. "Arial [Monotype]")
+*/
+static void parseFontName(const QString &name, QString &foundry, QString &family)
+{
+ int i = name.indexOf(QLatin1Char('['));
+ int li = name.lastIndexOf(QLatin1Char(']'));
+ if (i >= 0 && li >= 0 && i < li) {
+ foundry = name.mid(i + 1, li - i - 1);
+ if (i > 0 && name[i - 1] == QLatin1Char(' '))
+ i--;
+ family = name.left(i);
+ } else {
+ foundry.clear();
+ family = name;
+ }
+
+ // capitalize the family/foundry names
+ bool space = true;
+ QChar *s = family.data();
+ int len = family.length();
+ while(len--) {
+ if (space) *s = s->toUpper();
+ space = s->isSpace();
+ ++s;
+ }
+
+ space = true;
+ s = foundry.data();
+ len = foundry.length();
+ while(len--) {
+ if (space) *s = s->toUpper();
+ space = s->isSpace();
+ ++s;
+ }
+}
+
+
+struct QtFontDesc
+{
+ inline QtFontDesc() : family(0), foundry(0), style(0), size(0), encoding(0), familyIndex(-1) {}
+ QtFontFamily *family;
+ QtFontFoundry *foundry;
+ QtFontStyle *style;
+ QtFontSize *size;
+ QtFontEncoding *encoding;
+ int familyIndex;
+};
+
+#if !defined(Q_WS_MAC)
+static void match(int script, const QFontDef &request,
+ const QString &family_name, const QString &foundry_name, int force_encoding_id,
+ QtFontDesc *desc, const QList<int> &blacklistedFamilies = QList<int>(), bool forceXLFD=false);
+
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_QPA)
+static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef)
+{
+ fontDef->family = desc.family->name;
+ if (! desc.foundry->name.isEmpty() && desc.family->count > 1) {
+ fontDef->family += QString::fromLatin1(" [");
+ fontDef->family += desc.foundry->name;
+ fontDef->family += QLatin1Char(']');
+ }
+
+ if (desc.style->smoothScalable)
+ fontDef->pixelSize = request.pixelSize;
+ else if ((desc.style->bitmapScalable && (request.styleStrategy & QFont::PreferMatch)))
+ fontDef->pixelSize = request.pixelSize;
+ else
+ fontDef->pixelSize = desc.size->pixelSize;
+
+ fontDef->styleHint = request.styleHint;
+ fontDef->styleStrategy = request.styleStrategy;
+
+ fontDef->weight = desc.style->key.weight;
+ fontDef->style = desc.style->key.style;
+ fontDef->fixedPitch = desc.family->fixedPitch;
+ fontDef->stretch = desc.style->key.stretch;
+ fontDef->ignorePitch = false;
+}
+#endif
+#endif
+
+#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
+ d->engineData = QFontCache::instance()->findEngineData(key);
+ if (!d->engineData) {
+ // create a new one
+ d->engineData = new QFontEngineData;
+ QFontCache::instance()->insertEngineData(key, d->engineData);
+ } else {
+ d->engineData->ref.ref();
+ }
+}
+#endif
+
+static QStringList familyList(const QFontDef &req)
+{
+ // list of families to try
+ QStringList family_list;
+ if (req.family.isEmpty())
+ return family_list;
+
+ QStringList list = req.family.split(QLatin1Char(','));
+ for (int i = 0; i < list.size(); ++i) {
+ QString str = list.at(i).trimmed();
+ if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
+ || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
+ str = str.mid(1, str.length() - 2);
+ family_list << str;
+ }
+
+ // append the substitute list for each family in family_list
+ QStringList subs_list;
+ QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
+ for (; it != end; ++it)
+ subs_list += QFont::substitutes(*it);
+// qDebug() << "adding substs: " << subs_list;
+
+ family_list += subs_list;
+
+ return family_list;
+}
+
+Q_GLOBAL_STATIC(QFontDatabasePrivate, privateDb)
+Q_GLOBAL_STATIC_WITH_ARGS(QMutex, fontDatabaseMutex, (QMutex::Recursive))
+
+// used in qfontengine_x11.cpp
+QMutex *qt_fontdatabase_mutex()
+{
+ return fontDatabaseMutex();
+}
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#if defined(Q_WS_X11)
+# include "qfontdatabase_x11.cpp"
+#elif defined(Q_WS_MAC)
+# include "qfontdatabase_mac.cpp"
+#elif defined(Q_WS_WIN)
+# include "qfontdatabase_win.cpp"
+#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
+#if !defined(Q_WS_X11)
+QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
+{
+ return family;
+}
+#endif
+QT_END_INCLUDE_NAMESPACE
+
+static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey)
+{
+ int best = 0;
+ int dist = 0xffff;
+
+ for ( int i = 0; i < foundry->count; i++ ) {
+ QtFontStyle *style = foundry->styles[i];
+
+ int d = qAbs( styleKey.weight - style->key.weight );
+
+ if ( styleKey.stretch != 0 && style->key.stretch != 0 ) {
+ d += qAbs( styleKey.stretch - style->key.stretch );
+ }
+
+ if (styleKey.style != style->key.style) {
+ if (styleKey.style != QFont::StyleNormal && style->key.style != QFont::StyleNormal)
+ // one is italic, the other oblique
+ d += 0x0001;
+ else
+ d += 0x1000;
+ }
+
+ if ( d < dist ) {
+ best = i;
+ dist = d;
+ }
+ }
+
+ FM_DEBUG( " best style has distance 0x%x", dist );
+ return foundry->styles[best];
+}
+
+#if defined(Q_WS_X11)
+static QtFontEncoding *findEncoding(int script, int styleStrategy,
+ QtFontSize *size, int force_encoding_id)
+{
+ QtFontEncoding *encoding = 0;
+
+ if (force_encoding_id >= 0) {
+ encoding = size->encodingID(force_encoding_id);
+ if (!encoding)
+ FM_DEBUG(" required encoding_id not available");
+ return encoding;
+ }
+
+ if (styleStrategy & (QFont::OpenGLCompatible | QFont::PreferBitmap)) {
+ FM_DEBUG(" PreferBitmap and/or OpenGL set, skipping Freetype");
+ } else {
+ encoding = size->encodingID(-1); // -1 == prefer Freetype
+ if (encoding)
+ return encoding;
+ }
+
+ // FT not available, find an XLFD font, trying the default encoding first
+ encoding = size->encodingID(QFontPrivate::defaultEncodingID);
+ if (encoding) {
+ // does it support the requested script?
+ bool supportsScript = false;
+ for (int ws = 1; !supportsScript && ws < QFontDatabase::WritingSystemsCount; ++ws) {
+ if (scriptForWritingSystem[ws] != script)
+ continue;
+ supportsScript = writingSystems_for_xlfd_encoding[encoding->encoding][ws];
+ }
+ if (!supportsScript)
+ encoding = 0;
+ }
+ // find the first encoding that supports the requested script
+ for (int ws = 1; !encoding && ws < QFontDatabase::WritingSystemsCount; ++ws) {
+ if (scriptForWritingSystem[ws] != script)
+ continue;
+ for (int x = 0; !encoding && x < size->count; ++x) {
+ const int enc = size->encodings[x].encoding;
+ if (writingSystems_for_xlfd_encoding[enc][ws])
+ encoding = size->encodings + x;
+ }
+ }
+
+ return encoding;
+}
+#endif // Q_WS_X11
+
+#if !defined(Q_WS_MAC)
+static
+unsigned int bestFoundry(int script, unsigned int score, int styleStrategy,
+ const QtFontFamily *family, const QString &foundry_name,
+ QtFontStyle::Key styleKey, int pixelSize, char pitch,
+ QtFontDesc *desc, int force_encoding_id)
+{
+ Q_UNUSED(force_encoding_id);
+ Q_UNUSED(script);
+ Q_UNUSED(pitch);
+
+ desc->foundry = 0;
+ desc->style = 0;
+ desc->size = 0;
+ desc->encoding = 0;
+
+
+ FM_DEBUG(" REMARK: looking for best foundry for family '%s' [%d]", family->name.toLatin1().constData(), family->count);
+
+ for (int x = 0; x < family->count; ++x) {
+ QtFontFoundry *foundry = family->foundries[x];
+ if (!foundry_name.isEmpty() && foundry->name.compare(foundry_name, Qt::CaseInsensitive) != 0)
+ continue;
+
+ FM_DEBUG(" looking for matching style in foundry '%s' %d",
+ foundry->name.isEmpty() ? "-- none --" : foundry->name.toLatin1().constData(), foundry->count);
+
+ QtFontStyle *style = bestStyle(foundry, styleKey);
+
+ if (!style->smoothScalable && (styleStrategy & QFont::ForceOutline)) {
+ FM_DEBUG(" ForceOutline set, but not smoothly scalable");
+ continue;
+ }
+
+ int px = -1;
+ QtFontSize *size = 0;
+
+ // 1. see if we have an exact matching size
+ if (!(styleStrategy & QFont::ForceOutline)) {
+ size = style->pixelSize(pixelSize);
+ if (size) {
+ FM_DEBUG(" found exact size match (%d pixels)", size->pixelSize);
+ px = size->pixelSize;
+ }
+ }
+
+ // 2. see if we have a smoothly scalable font
+ if (!size && style->smoothScalable && ! (styleStrategy & QFont::PreferBitmap)) {
+ size = style->pixelSize(SMOOTH_SCALABLE);
+ if (size) {
+ FM_DEBUG(" found smoothly scalable font (%d pixels)", pixelSize);
+ px = pixelSize;
+ }
+ }
+
+ // 3. see if we have a bitmap scalable font
+ if (!size && style->bitmapScalable && (styleStrategy & QFont::PreferMatch)) {
+ size = style->pixelSize(0);
+ if (size) {
+ FM_DEBUG(" found bitmap scalable font (%d pixels)", pixelSize);
+ px = pixelSize;
+ }
+ }
+
+#ifdef Q_WS_X11
+ QtFontEncoding *encoding = 0;
+#endif
+
+ // 4. find closest size match
+ if (! size) {
+ unsigned int distance = ~0u;
+ for (int x = 0; x < style->count; ++x) {
+#ifdef Q_WS_X11
+ encoding =
+ findEncoding(script, styleStrategy, style->pixelSizes + x, force_encoding_id);
+ if (!encoding) {
+ FM_DEBUG(" size %3d does not support the script we want",
+ style->pixelSizes[x].pixelSize);
+ continue;
+ }
+#endif
+
+ unsigned int d;
+ if (style->pixelSizes[x].pixelSize < pixelSize) {
+ // penalize sizes that are smaller than the
+ // requested size, due to truncation from floating
+ // point to integer conversions
+ d = pixelSize - style->pixelSizes[x].pixelSize + 1;
+ } else {
+ d = style->pixelSizes[x].pixelSize - pixelSize;
+ }
+
+ if (d < distance) {
+ distance = d;
+ size = style->pixelSizes + x;
+ FM_DEBUG(" best size so far: %3d (%d)", size->pixelSize, pixelSize);
+ }
+ }
+
+ if (!size) {
+ FM_DEBUG(" no size supports the script we want");
+ continue;
+ }
+
+ if (style->bitmapScalable && ! (styleStrategy & QFont::PreferQuality) &&
+ (distance * 10 / pixelSize) >= 2) {
+ // the closest size is not close enough, go ahead and
+ // use a bitmap scaled font
+ size = style->pixelSize(0);
+ px = pixelSize;
+ } else {
+ px = size->pixelSize;
+ }
+ }
+
+#ifdef Q_WS_X11
+ if (size) {
+ encoding = findEncoding(script, styleStrategy, size, force_encoding_id);
+ if (!encoding) size = 0;
+ }
+ if (! encoding) {
+ FM_DEBUG(" foundry doesn't support the script we want");
+ continue;
+ }
+#endif // Q_WS_X11
+
+ unsigned int this_score = 0x0000;
+ enum {
+ PitchMismatch = 0x4000,
+ StyleMismatch = 0x2000,
+ BitmapScaledPenalty = 0x1000,
+ EncodingMismatch = 0x0002,
+ XLFDPenalty = 0x0001
+ };
+#ifdef Q_WS_X11
+ if (encoding->encoding != -1) {
+ this_score += XLFDPenalty;
+ if (encoding->encoding != QFontPrivate::defaultEncodingID)
+ this_score += EncodingMismatch;
+ }
+ if (pitch != '*') {
+ if (!(pitch == 'm' && encoding->pitch == 'c') && pitch != encoding->pitch)
+ this_score += PitchMismatch;
+ }
+#else
+ if (pitch != '*') {
+#if !defined(QWS) && defined(Q_OS_MAC)
+ qt_mac_get_fixed_pitch(const_cast<QtFontFamily*>(family));
+#endif
+ if ((pitch == 'm' && !family->fixedPitch)
+ || (pitch == 'p' && family->fixedPitch))
+ this_score += PitchMismatch;
+ }
+#endif
+ if (styleKey != style->key)
+ this_score += StyleMismatch;
+ if (!style->smoothScalable && px != size->pixelSize) // bitmap scaled
+ this_score += BitmapScaledPenalty;
+ if (px != pixelSize) // close, but not exact, size match
+ this_score += qAbs(px - pixelSize);
+
+ if (this_score < score) {
+ FM_DEBUG(" found a match: score %x best score so far %x",
+ this_score, score);
+
+ score = this_score;
+ desc->foundry = foundry;
+ desc->style = style;
+ desc->size = size;
+#ifdef Q_WS_X11
+ desc->encoding = encoding;
+#endif // Q_WS_X11
+ } else {
+ FM_DEBUG(" score %x no better than best %x", this_score, score);
+ }
+ }
+
+ return score;
+}
+#endif
+
+#if !defined(Q_WS_MAC)
+/*!
+ \internal
+
+ Tries to find the best match for a given request and family/foundry
+*/
+static void match(int script, const QFontDef &request,
+ const QString &family_name, const QString &foundry_name, int force_encoding_id,
+ QtFontDesc *desc, const QList<int> &blacklistedFamilies, bool forceXLFD)
+{
+ Q_UNUSED(force_encoding_id);
+
+ QtFontStyle::Key styleKey;
+ styleKey.style = request.style;
+ styleKey.weight = request.weight;
+ 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"
+ " weight: %d, style: %d\n"
+ " stretch: %d\n"
+ " pixelSize: %g\n"
+ " pitch: %c",
+ family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
+ foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
+ script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
+#if defined(FONT_MATCH_DEBUG) && defined(Q_WS_X11)
+ if (force_encoding_id >= 0) {
+ FM_DEBUG(" required encoding: %d", force_encoding_id);
+ }
+#endif
+
+ desc->family = 0;
+ desc->foundry = 0;
+ desc->style = 0;
+ desc->size = 0;
+ desc->encoding = 0;
+ desc->familyIndex = -1;
+
+ unsigned int score = ~0u;
+
+#ifdef Q_WS_X11
+ load(family_name, script, forceXLFD);
+#else
+ Q_UNUSED(forceXLFD);
+ load(family_name, script);
+#endif
+
+ QFontDatabasePrivate *db = privateDb();
+ for (int x = 0; x < db->count; ++x) {
+ if (blacklistedFamilies.contains(x))
+ continue;
+ QtFontDesc test;
+ test.family = db->families[x];
+ test.familyIndex = x;
+
+ if (!family_name.isEmpty()
+ && test.family->name.compare(family_name, Qt::CaseInsensitive) != 0
+#ifdef Q_WS_WIN
+ && test.family->english_name.compare(family_name, Qt::CaseInsensitive) != 0
+#endif
+ )
+ continue;
+
+ if (family_name.isEmpty())
+ load(test.family->name, script);
+
+ uint score_adjust = 0;
+
+ bool supported = (script == QUnicodeTables::Common);
+ for (int ws = 1; !supported && ws < QFontDatabase::WritingSystemsCount; ++ws) {
+ if (scriptForWritingSystem[ws] != script)
+ continue;
+ if (test.family->writingSystems[ws] & QtFontFamily::Supported)
+ supported = true;
+ }
+ if (!supported) {
+ // family not supported in the script we want
+ continue;
+ }
+
+ // as we know the script is supported, we can be sure
+ // to find a matching font here.
+ unsigned int newscore =
+ bestFoundry(script, score, request.styleStrategy,
+ test.family, foundry_name, styleKey, request.pixelSize, pitch,
+ &test, force_encoding_id);
+ if (test.foundry == 0) {
+ // the specific foundry was not found, so look for
+ // any foundry matching our requirements
+ newscore = bestFoundry(script, score, request.styleStrategy, test.family,
+ QString(), styleKey, request.pixelSize,
+ pitch, &test, force_encoding_id);
+ }
+ newscore += score_adjust;
+
+ if (newscore < score) {
+ score = newscore;
+ *desc = test;
+ }
+ if (newscore < 10) // xlfd instead of FT... just accept it
+ break;
+ }
+}
+#endif
+
+static QString styleStringHelper(int weight, QFont::Style style)
+{
+ QString result;
+ if (weight >= QFont::Black)
+ result = QApplication::translate("QFontDatabase", "Black");
+ else if (weight >= QFont::Bold)
+ result = QApplication::translate("QFontDatabase", "Bold");
+ else if (weight >= QFont::DemiBold)
+ result = QApplication::translate("QFontDatabase", "Demi Bold");
+ else if (weight < QFont::Normal)
+ result = QApplication::translate("QFontDatabase", "Light");
+
+ if (style == QFont::StyleItalic)
+ result += QLatin1Char(' ') + QApplication::translate("QFontDatabase", "Italic");
+ else if (style == QFont::StyleOblique)
+ result += QLatin1Char(' ') + QApplication::translate("QFontDatabase", "Oblique");
+
+ if (result.isEmpty())
+ result = QApplication::translate("QFontDatabase", "Normal");
+
+ return result.simplified();
+}
+
+/*!
+ Returns a string that describes the style of the \a font. For
+ example, "Bold Italic", "Bold", "Italic" or "Normal". An empty
+ string may be returned.
+*/
+QString QFontDatabase::styleString(const QFont &font)
+{
+ return styleStringHelper(font.weight(), font.style());
+}
+
+/*!
+ Returns a string that describes the style of the \a fontInfo. For
+ example, "Bold Italic", "Bold", "Italic" or "Normal". An empty
+ string may be returned.
+*/
+QString QFontDatabase::styleString(const QFontInfo &fontInfo)
+{
+ return styleStringHelper(fontInfo.weight(), fontInfo.style());
+}
+
+
+/*!
+ \class QFontDatabase
+ \threadsafe
+
+ \brief The QFontDatabase class provides information about the fonts available in the underlying window system.
+
+ \ingroup appearance
+
+ The most common uses of this class are to query the database for
+ the list of font families() and for the pointSizes() and styles()
+ that are available for each family. An alternative to pointSizes()
+ is smoothSizes() which returns the sizes at which a given family
+ and style will look attractive.
+
+ If the font family is available from two or more foundries the
+ foundry name is included in the family name; for example:
+ "Helvetica [Adobe]" and "Helvetica [Cronyx]". When you specify a
+ family, you can either use the old hyphenated "foundry-family"
+ format or the bracketed "family [foundry]" format; for example:
+ "Cronyx-Helvetica" or "Helvetica [Cronyx]". If the family has a
+ foundry it is always returned using the bracketed format, as is
+ the case with the value returned by families().
+
+ The font() function returns a QFont given a family, style and
+ point size.
+
+ A family and style combination can be checked to see if it is
+ italic() or bold(), and to retrieve its weight(). Similarly we can
+ call isBitmapScalable(), isSmoothlyScalable(), isScalable() and
+ isFixedPitch().
+
+ Use the styleString() to obtain a text version of a style.
+
+ The QFontDatabase class also supports some static functions, for
+ example, standardSizes(). You can retrieve the description of a
+ writing system using writingSystemName(), and a sample of
+ characters in a writing system with writingSystemSample().
+
+ Example:
+
+ \snippet doc/src/snippets/qfontdatabase/main.cpp 0
+ \snippet doc/src/snippets/qfontdatabase/main.cpp 1
+
+ This example gets the list of font families, the list of
+ styles for each family, and the point sizes that are available for
+ each combination of family and style, displaying this information
+ in a tree view.
+
+ \sa QFont, QFontInfo, QFontMetrics, QFontComboBox, {Character Map Example}
+*/
+
+/*!
+ Creates a font database object.
+*/
+QFontDatabase::QFontDatabase()
+{
+ QMutexLocker locker(fontDatabaseMutex());
+ createDatabase();
+ d = privateDb();
+}
+
+/*!
+ \enum QFontDatabase::WritingSystem
+
+ \value Any
+ \value Latin
+ \value Greek
+ \value Cyrillic
+ \value Armenian
+ \value Hebrew
+ \value Arabic
+ \value Syriac
+ \value Thaana
+ \value Devanagari
+ \value Bengali
+ \value Gurmukhi
+ \value Gujarati
+ \value Oriya
+ \value Tamil
+ \value Telugu
+ \value Kannada
+ \value Malayalam
+ \value Sinhala
+ \value Thai
+ \value Lao
+ \value Tibetan
+ \value Myanmar
+ \value Georgian
+ \value Khmer
+ \value SimplifiedChinese
+ \value TraditionalChinese
+ \value Japanese
+ \value Korean
+ \value Vietnamese
+ \value Symbol
+ \value Other (the same as Symbol)
+ \value Ogham
+ \value Runic
+ \value Nko
+
+ \omitvalue WritingSystemsCount
+*/
+
+/*!
+ Returns a sorted list of the available writing systems. This is
+ list generated from information about all installed fonts on the
+ system.
+
+ \sa families()
+*/
+QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems() const
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)();
+#ifdef Q_WS_X11
+ checkSymbolFonts();
+#endif
+
+ QList<WritingSystem> list;
+ for (int i = 0; i < d->count; ++i) {
+ QtFontFamily *family = d->families[i];
+ if (family->count == 0)
+ continue;
+ for (int x = Latin; x < WritingSystemsCount; ++x) {
+ const WritingSystem writingSystem = WritingSystem(x);
+ if (!(family->writingSystems[writingSystem] & QtFontFamily::Supported))
+ continue;
+ if (!list.contains(writingSystem))
+ list.append(writingSystem);
+ }
+ }
+ qSort(list);
+ return list;
+}
+
+
+/*!
+ Returns a sorted list of the writing systems supported by a given
+ font \a family.
+
+ \sa families()
+*/
+QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems(const QString &family) const
+{
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)();
+#ifdef Q_WS_X11
+ checkSymbolFonts(familyName);
+#endif
+
+ QList<WritingSystem> list;
+ QtFontFamily *f = d->family(familyName);
+ if (!f || f->count == 0)
+ return list;
+
+ for (int x = Latin; x < WritingSystemsCount; ++x) {
+ const WritingSystem writingSystem = WritingSystem(x);
+ if (f->writingSystems[writingSystem] & QtFontFamily::Supported)
+ list.append(writingSystem);
+ }
+ return list;
+}
+
+
+/*!
+ Returns a sorted list of the available font families which support
+ the \a writingSystem.
+
+ If a family exists in several foundries, the returned name for
+ that font is in the form "family [foundry]". Examples: "Times
+ [Adobe]", "Times [Cronyx]", "Palatino".
+
+ \sa writingSystems()
+*/
+QStringList QFontDatabase::families(WritingSystem writingSystem) const
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)();
+#ifdef Q_WS_X11
+ if (writingSystem != Any)
+ checkSymbolFonts();
+#endif
+
+ QStringList flist;
+ for (int i = 0; i < d->count; i++) {
+ QtFontFamily *f = d->families[i];
+ if (f->count == 0)
+ continue;
+ if (writingSystem != Any && (f->writingSystems[writingSystem] != QtFontFamily::Supported))
+ continue;
+ if (f->count == 1) {
+ flist.append(f->name);
+ } else {
+ for (int j = 0; j < f->count; j++) {
+ QString str = f->name;
+ QString foundry = f->foundries[j]->name;
+ if (!foundry.isEmpty()) {
+ str += QLatin1String(" [");
+ str += foundry;
+ str += QLatin1Char(']');
+ }
+ flist.append(str);
+ }
+ }
+ }
+ return flist;
+}
+
+/*!
+ Returns a list of the styles available for the font family \a
+ family. Some example styles: "Light", "Light Italic", "Bold",
+ "Oblique", "Demi". The list may be empty.
+
+ \sa families()
+*/
+QStringList QFontDatabase::styles(const QString &family) const
+{
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QStringList l;
+ QtFontFamily *f = d->family(familyName);
+ if (!f)
+ return l;
+
+ QtFontFoundry allStyles(foundryName);
+ for (int j = 0; j < f->count; j++) {
+ QtFontFoundry *foundry = f->foundries[j];
+ if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
+ for (int k = 0; k < foundry->count; k++) {
+ QtFontStyle::Key ke(foundry->styles[k]->key);
+ ke.stretch = 0;
+ allStyles.style(ke, true);
+ }
+ }
+ }
+
+ for (int i = 0; i < allStyles.count; i++)
+ l.append(styleStringHelper(allStyles.styles[i]->key.weight, (QFont::Style)allStyles.styles[i]->key.style));
+ return l;
+}
+
+/*!
+ Returns true if the font that has family \a family and style \a
+ style is fixed pitch; otherwise returns false.
+*/
+
+bool QFontDatabase::isFixedPitch(const QString &family,
+ const QString &style) const
+{
+ Q_UNUSED(style);
+
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QtFontFamily *f = d->family(familyName);
+#if !defined(QWS) && defined(Q_OS_MAC)
+ qt_mac_get_fixed_pitch(f);
+#endif
+ return (f && f->fixedPitch);
+}
+
+/*!
+ Returns true if the font that has family \a family and style \a
+ style is a scalable bitmap font; otherwise returns false. Scaling
+ a bitmap font usually produces an unattractive hardly readable
+ result, because the pixels of the font are scaled. If you need to
+ scale a bitmap font it is better to scale it to one of the fixed
+ sizes returned by smoothSizes().
+
+ \sa isScalable(), isSmoothlyScalable()
+*/
+bool QFontDatabase::isBitmapScalable(const QString &family,
+ const QString &style) const
+{
+ bool bitmapScalable = false;
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QtFontStyle::Key styleKey(style);
+
+ QtFontFamily *f = d->family(familyName);
+ if (!f) return bitmapScalable;
+
+ for (int j = 0; j < f->count; j++) {
+ QtFontFoundry *foundry = f->foundries[j];
+ if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
+ for (int k = 0; k < foundry->count; k++)
+ if ((style.isEmpty() || foundry->styles[k]->key == styleKey)
+ && foundry->styles[k]->bitmapScalable && !foundry->styles[k]->smoothScalable) {
+ bitmapScalable = true;
+ goto end;
+ }
+ }
+ }
+ end:
+ return bitmapScalable;
+}
+
+
+/*!
+ Returns true if the font that has family \a family and style \a
+ style is smoothly scalable; otherwise returns false. If this
+ function returns true, it's safe to scale this font to any size,
+ and the result will always look attractive.
+
+ \sa isScalable(), isBitmapScalable()
+*/
+bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &style) const
+{
+ bool smoothScalable = false;
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QtFontStyle::Key styleKey(style);
+
+ QtFontFamily *f = d->family(familyName);
+ if (!f) return smoothScalable;
+
+ for (int j = 0; j < f->count; j++) {
+ QtFontFoundry *foundry = f->foundries[j];
+ if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
+ for (int k = 0; k < foundry->count; k++)
+ if ((style.isEmpty() || foundry->styles[k]->key == styleKey) && foundry->styles[k]->smoothScalable) {
+ smoothScalable = true;
+ goto end;
+ }
+ }
+ }
+ end:
+ return smoothScalable;
+}
+
+/*!
+ Returns true if the font that has family \a family and style \a
+ style is scalable; otherwise returns false.
+
+ \sa isBitmapScalable(), isSmoothlyScalable()
+*/
+bool QFontDatabase::isScalable(const QString &family,
+ const QString &style) const
+{
+ QMutexLocker locker(fontDatabaseMutex());
+ if (isSmoothlyScalable(family, style))
+ return true;
+ return isBitmapScalable(family, style);
+}
+
+
+/*!
+ Returns a list of the point sizes available for the font that has
+ family \a family and style \a style. The list may be empty.
+
+ \sa smoothSizes(), standardSizes()
+*/
+QList<int> QFontDatabase::pointSizes(const QString &family,
+ const QString &style)
+{
+#if defined(Q_WS_WIN)
+ // windows and macosx are always smoothly scalable
+ Q_UNUSED(family);
+ Q_UNUSED(style);
+ return standardSizes();
+#else
+ bool smoothScalable = false;
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QtFontStyle::Key styleKey(style);
+
+ QList<int> sizes;
+
+ QtFontFamily *fam = d->family(familyName);
+ if (!fam) return sizes;
+
+
+#ifdef Q_WS_X11
+ int dpi = QX11Info::appDpiY();
+#else
+ const int dpi = qt_defaultDpiY(); // embedded
+#endif
+
+ for (int j = 0; j < fam->count; j++) {
+ QtFontFoundry *foundry = fam->foundries[j];
+ if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
+ QtFontStyle *style = foundry->style(styleKey);
+ if (!style) continue;
+
+ if (style->smoothScalable) {
+ smoothScalable = true;
+ goto end;
+ }
+ for (int l = 0; l < style->count; l++) {
+ const QtFontSize *size = style->pixelSizes + l;
+
+ if (size->pixelSize != 0 && size->pixelSize != USHRT_MAX) {
+ const uint pointSize = qRound(size->pixelSize * 72.0 / dpi);
+ if (! sizes.contains(pointSize))
+ sizes.append(pointSize);
+ }
+ }
+ }
+ }
+ end:
+ if (smoothScalable)
+ return standardSizes();
+
+ qSort(sizes);
+ return sizes;
+#endif
+}
+
+/*!
+ Returns a QFont object that has family \a family, style \a style
+ and point size \a pointSize. If no matching font could be created,
+ a QFont object that uses the application's default font is
+ returned.
+*/
+QFont QFontDatabase::font(const QString &family, const QString &style,
+ int pointSize) const
+{
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QtFontFoundry allStyles(foundryName);
+ QtFontFamily *f = d->family(familyName);
+ if (!f) return QApplication::font();
+
+ for (int j = 0; j < f->count; j++) {
+ QtFontFoundry *foundry = f->foundries[j];
+ if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
+ for (int k = 0; k < foundry->count; k++)
+ allStyles.style(foundry->styles[k]->key, true);
+ }
+ }
+
+ QtFontStyle::Key styleKey(style);
+ QtFontStyle *s = bestStyle(&allStyles, styleKey);
+
+ if (!s) // no styles found?
+ return QApplication::font();
+ QFont fnt(family, pointSize, s->key.weight);
+ fnt.setStyle((QFont::Style)s->key.style);
+ return fnt;
+}
+
+
+/*!
+ Returns the point sizes of a font that has family \a family and
+ style \a style that will look attractive. The list may be empty.
+ For non-scalable fonts and bitmap scalable fonts, this function
+ is equivalent to pointSizes().
+
+ \sa pointSizes(), standardSizes()
+*/
+QList<int> QFontDatabase::smoothSizes(const QString &family,
+ const QString &style)
+{
+#ifdef Q_WS_WIN
+ Q_UNUSED(family);
+ Q_UNUSED(style);
+ return QFontDatabase::standardSizes();
+#else
+ bool smoothScalable = false;
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QtFontStyle::Key styleKey(style);
+
+ QList<int> sizes;
+
+ QtFontFamily *fam = d->family(familyName);
+ if (!fam)
+ return sizes;
+
+#ifdef Q_WS_X11
+ int dpi = QX11Info::appDpiY();
+#else
+ const int dpi = qt_defaultDpiY(); // embedded
+#endif
+
+ for (int j = 0; j < fam->count; j++) {
+ QtFontFoundry *foundry = fam->foundries[j];
+ if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
+ QtFontStyle *style = foundry->style(styleKey);
+ if (!style) continue;
+
+ if (style->smoothScalable) {
+ smoothScalable = true;
+ goto end;
+ }
+ for (int l = 0; l < style->count; l++) {
+ const QtFontSize *size = style->pixelSizes + l;
+
+ if (size->pixelSize != 0 && size->pixelSize != USHRT_MAX) {
+ const uint pointSize = qRound(size->pixelSize * 72.0 / dpi);
+ if (! sizes.contains(pointSize))
+ sizes.append(pointSize);
+ }
+ }
+ }
+ }
+ end:
+ if (smoothScalable)
+ return QFontDatabase::standardSizes();
+
+ qSort(sizes);
+ return sizes;
+#endif
+}
+
+
+/*!
+ Returns a list of standard font sizes.
+
+ \sa smoothSizes(), pointSizes()
+*/
+QList<int> QFontDatabase::standardSizes()
+{
+ QList<int> ret;
+ static const unsigned short standard[] =
+ { 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72, 0 };
+ const unsigned short *sizes = standard;
+ while (*sizes) ret << *sizes++;
+ return ret;
+}
+
+
+/*!
+ Returns true if the font that has family \a family and style \a
+ style is italic; otherwise returns false.
+
+ \sa weight(), bold()
+*/
+bool QFontDatabase::italic(const QString &family, const QString &style) const
+{
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QtFontFoundry allStyles(foundryName);
+ QtFontFamily *f = d->family(familyName);
+ if (!f) return false;
+
+ for (int j = 0; j < f->count; j++) {
+ QtFontFoundry *foundry = f->foundries[j];
+ if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
+ for (int k = 0; k < foundry->count; k++)
+ allStyles.style(foundry->styles[k]->key, true);
+ }
+ }
+
+ QtFontStyle::Key styleKey(style);
+ QtFontStyle *s = allStyles.style(styleKey);
+ return s && s->key.style == QFont::StyleItalic;
+}
+
+
+/*!
+ Returns true if the font that has family \a family and style \a
+ style is bold; otherwise returns false.
+
+ \sa italic(), weight()
+*/
+bool QFontDatabase::bold(const QString &family,
+ const QString &style) const
+{
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QtFontFoundry allStyles(foundryName);
+ QtFontFamily *f = d->family(familyName);
+ if (!f) return false;
+
+ for (int j = 0; j < f->count; j++) {
+ QtFontFoundry *foundry = f->foundries[j];
+ if (foundryName.isEmpty() ||
+ foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
+ for (int k = 0; k < foundry->count; k++)
+ allStyles.style(foundry->styles[k]->key, true);
+ }
+ }
+
+ QtFontStyle::Key styleKey(style);
+ QtFontStyle *s = allStyles.style(styleKey);
+ return s && s->key.weight >= QFont::Bold;
+}
+
+
+/*!
+ Returns the weight of the font that has family \a family and style
+ \a style. If there is no such family and style combination,
+ returns -1.
+
+ \sa italic(), bold()
+*/
+int QFontDatabase::weight(const QString &family,
+ const QString &style) const
+{
+ QString familyName, foundryName;
+ parseFontName(family, foundryName, familyName);
+
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QT_PREPEND_NAMESPACE(load)(familyName);
+
+ QtFontFoundry allStyles(foundryName);
+ QtFontFamily *f = d->family(familyName);
+ if (!f) return -1;
+
+ for (int j = 0; j < f->count; j++) {
+ QtFontFoundry *foundry = f->foundries[j];
+ if (foundryName.isEmpty() ||
+ foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
+ for (int k = 0; k < foundry->count; k++)
+ allStyles.style(foundry->styles[k]->key, true);
+ }
+ }
+
+ QtFontStyle::Key styleKey(style);
+ QtFontStyle *s = allStyles.style(styleKey);
+ return s ? s->key.weight : -1;
+}
+
+
+/*!
+ Returns the names the \a writingSystem (e.g. for displaying to the
+ user in a dialog).
+*/
+QString QFontDatabase::writingSystemName(WritingSystem writingSystem)
+{
+ const char *name = 0;
+ switch (writingSystem) {
+ case Any:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Any");
+ break;
+ case Latin:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Latin");
+ break;
+ case Greek:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Greek");
+ break;
+ case Cyrillic:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Cyrillic");
+ break;
+ case Armenian:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Armenian");
+ break;
+ case Hebrew:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Hebrew");
+ break;
+ case Arabic:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Arabic");
+ break;
+ case Syriac:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Syriac");
+ break;
+ case Thaana:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Thaana");
+ break;
+ case Devanagari:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Devanagari");
+ break;
+ case Bengali:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Bengali");
+ break;
+ case Gurmukhi:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Gurmukhi");
+ break;
+ case Gujarati:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Gujarati");
+ break;
+ case Oriya:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Oriya");
+ break;
+ case Tamil:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Tamil");
+ break;
+ case Telugu:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Telugu");
+ break;
+ case Kannada:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Kannada");
+ break;
+ case Malayalam:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Malayalam");
+ break;
+ case Sinhala:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Sinhala");
+ break;
+ case Thai:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Thai");
+ break;
+ case Lao:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Lao");
+ break;
+ case Tibetan:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Tibetan");
+ break;
+ case Myanmar:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Myanmar");
+ break;
+ case Georgian:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Georgian");
+ break;
+ case Khmer:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Khmer");
+ break;
+ case SimplifiedChinese:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Simplified Chinese");
+ break;
+ case TraditionalChinese:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Traditional Chinese");
+ break;
+ case Japanese:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Japanese");
+ break;
+ case Korean:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Korean");
+ break;
+ case Vietnamese:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Vietnamese");
+ break;
+ case Symbol:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Symbol");
+ break;
+ case Ogham:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Ogham");
+ break;
+ case Runic:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "Runic");
+ break;
+ case Nko:
+ name = QT_TRANSLATE_NOOP("QFontDatabase", "N'Ko");
+ break;
+ default:
+ Q_ASSERT_X(false, "QFontDatabase::writingSystemName", "invalid 'writingSystem' parameter");
+ break;
+ }
+ return QApplication::translate("QFontDatabase", name);
+}
+
+
+/*!
+ Returns a string with sample characters from \a writingSystem.
+*/
+QString QFontDatabase::writingSystemSample(WritingSystem writingSystem)
+{
+ QString sample;
+ switch (writingSystem) {
+ case Any:
+ case Symbol:
+ // show only ascii characters
+ sample += QLatin1String("AaBbzZ");
+ break;
+ case Latin:
+ // This is cheating... we only show latin-1 characters so that we don't
+ // end up loading lots of fonts - at least on X11...
+ sample = QLatin1String("Aa");
+ sample += QChar(0x00C3);
+ sample += QChar(0x00E1);
+ sample += QLatin1String("Zz");
+ break;
+ case Greek:
+ sample += QChar(0x0393);
+ sample += QChar(0x03B1);
+ sample += QChar(0x03A9);
+ sample += QChar(0x03C9);
+ break;
+ case Cyrillic:
+ sample += QChar(0x0414);
+ sample += QChar(0x0434);
+ sample += QChar(0x0436);
+ sample += QChar(0x044f);
+ break;
+ case Armenian:
+ sample += QChar(0x053f);
+ sample += QChar(0x054f);
+ sample += QChar(0x056f);
+ sample += QChar(0x057f);
+ break;
+ case Hebrew:
+ sample += QChar(0x05D0);
+ sample += QChar(0x05D1);
+ sample += QChar(0x05D2);
+ sample += QChar(0x05D3);
+ break;
+ case Arabic:
+ sample += QChar(0x0628);
+ sample += QChar(0x0629);
+ sample += QChar(0x062A);
+ sample += QChar(0x063A);
+ break;
+ case Syriac:
+ sample += QChar(0x0715);
+ sample += QChar(0x0725);
+ sample += QChar(0x0716);
+ sample += QChar(0x0726);
+ break;
+ case Thaana:
+ sample += QChar(0x0784);
+ sample += QChar(0x0794);
+ sample += QChar(0x078c);
+ sample += QChar(0x078d);
+ break;
+ case Devanagari:
+ sample += QChar(0x0905);
+ sample += QChar(0x0915);
+ sample += QChar(0x0925);
+ sample += QChar(0x0935);
+ break;
+ case Bengali:
+ sample += QChar(0x0986);
+ sample += QChar(0x0996);
+ sample += QChar(0x09a6);
+ sample += QChar(0x09b6);
+ break;
+ case Gurmukhi:
+ sample += QChar(0x0a05);
+ sample += QChar(0x0a15);
+ sample += QChar(0x0a25);
+ sample += QChar(0x0a35);
+ break;
+ case Gujarati:
+ sample += QChar(0x0a85);
+ sample += QChar(0x0a95);
+ sample += QChar(0x0aa5);
+ sample += QChar(0x0ab5);
+ break;
+ case Oriya:
+ sample += QChar(0x0b06);
+ sample += QChar(0x0b16);
+ sample += QChar(0x0b2b);
+ sample += QChar(0x0b36);
+ break;
+ case Tamil:
+ sample += QChar(0x0b89);
+ sample += QChar(0x0b99);
+ sample += QChar(0x0ba9);
+ sample += QChar(0x0bb9);
+ break;
+ case Telugu:
+ sample += QChar(0x0c05);
+ sample += QChar(0x0c15);
+ sample += QChar(0x0c25);
+ sample += QChar(0x0c35);
+ break;
+ case Kannada:
+ sample += QChar(0x0c85);
+ sample += QChar(0x0c95);
+ sample += QChar(0x0ca5);
+ sample += QChar(0x0cb5);
+ break;
+ case Malayalam:
+ sample += QChar(0x0d05);
+ sample += QChar(0x0d15);
+ sample += QChar(0x0d25);
+ sample += QChar(0x0d35);
+ break;
+ case Sinhala:
+ sample += QChar(0x0d90);
+ sample += QChar(0x0da0);
+ sample += QChar(0x0db0);
+ sample += QChar(0x0dc0);
+ break;
+ case Thai:
+ sample += QChar(0x0e02);
+ sample += QChar(0x0e12);
+ sample += QChar(0x0e22);
+ sample += QChar(0x0e32);
+ break;
+ case Lao:
+ sample += QChar(0x0e8d);
+ sample += QChar(0x0e9d);
+ sample += QChar(0x0ead);
+ sample += QChar(0x0ebd);
+ break;
+ case Tibetan:
+ sample += QChar(0x0f00);
+ sample += QChar(0x0f01);
+ sample += QChar(0x0f02);
+ sample += QChar(0x0f03);
+ break;
+ case Myanmar:
+ sample += QChar(0x1000);
+ sample += QChar(0x1001);
+ sample += QChar(0x1002);
+ sample += QChar(0x1003);
+ break;
+ case Georgian:
+ sample += QChar(0x10a0);
+ sample += QChar(0x10b0);
+ sample += QChar(0x10c0);
+ sample += QChar(0x10d0);
+ break;
+ case Khmer:
+ sample += QChar(0x1780);
+ sample += QChar(0x1790);
+ sample += QChar(0x17b0);
+ sample += QChar(0x17c0);
+ break;
+ case SimplifiedChinese:
+ sample += QChar(0x4e2d);
+ sample += QChar(0x6587);
+ sample += QChar(0x8303);
+ sample += QChar(0x4f8b);
+ break;
+ case TraditionalChinese:
+ sample += QChar(0x4e2d);
+ sample += QChar(0x6587);
+ sample += QChar(0x7bc4);
+ sample += QChar(0x4f8b);
+ break;
+ case Japanese:
+ sample += QChar(0x30b5);
+ sample += QChar(0x30f3);
+ sample += QChar(0x30d7);
+ sample += QChar(0x30eb);
+ sample += QChar(0x3067);
+ sample += QChar(0x3059);
+ break;
+ case Korean:
+ sample += QChar(0xac00);
+ sample += QChar(0xac11);
+ sample += QChar(0xac1a);
+ sample += QChar(0xac2f);
+ break;
+ case Vietnamese:
+ {
+ static const char vietnameseUtf8[] = {
+ char(0xef), char(0xbb), char(0xbf), char(0xe1), char(0xbb), char(0x97),
+ char(0xe1), char(0xbb), char(0x99),
+ char(0xe1), char(0xbb), char(0x91),
+ char(0xe1), char(0xbb), char(0x93),
+ };
+ sample += QString::fromUtf8(vietnameseUtf8, sizeof(vietnameseUtf8));
+ break;
+ }
+ case Ogham:
+ sample += QChar(0x1681);
+ sample += QChar(0x1682);
+ sample += QChar(0x1683);
+ sample += QChar(0x1684);
+ break;
+ case Runic:
+ sample += QChar(0x16a0);
+ sample += QChar(0x16a1);
+ sample += QChar(0x16a2);
+ sample += QChar(0x16a3);
+ break;
+ case Nko:
+ sample += QChar(0x7ca);
+ sample += QChar(0x7cb);
+ sample += QChar(0x7cc);
+ sample += QChar(0x7cd);
+ break;
+ default:
+ break;
+ }
+ return sample;
+}
+
+
+void QFontDatabase::parseFontName(const QString &name, QString &foundry, QString &family)
+{
+ QT_PREPEND_NAMESPACE(parseFontName)(name, foundry, family);
+}
+
+void QFontDatabase::createDatabase()
+{ initializeDb(); }
+
+// used from qfontengine_ft.cpp
+Q_GUI_EXPORT QByteArray qt_fontdata_from_index(int index)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+ return privateDb()->applicationFonts.value(index).data;
+}
+
+int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString &fileName)
+{
+ QFontDatabasePrivate::ApplicationFont font;
+ font.data = fontData;
+ font.fileName = fileName;
+
+ int i;
+ for (i = 0; i < applicationFonts.count(); ++i)
+ if (applicationFonts.at(i).families.isEmpty())
+ break;
+ if (i >= applicationFonts.count()) {
+ applicationFonts.append(ApplicationFont());
+ i = applicationFonts.count() - 1;
+ }
+
+ if (font.fileName.isEmpty() && !fontData.isEmpty())
+ font.fileName = QString::fromLatin1(":qmemoryfonts/") + QString::number(i);
+
+ registerFont(&font);
+ if (font.families.isEmpty())
+ return -1;
+
+ applicationFonts[i] = font;
+
+ invalidate();
+ return i;
+}
+
+bool QFontDatabasePrivate::isApplicationFont(const QString &fileName)
+{
+ for (int i = 0; i < applicationFonts.count(); ++i)
+ if (applicationFonts.at(i).fileName == fileName)
+ return true;
+ return false;
+}
+
+/*!
+ \since 4.2
+
+ Loads the font from the file specified by \a fileName and makes it available to
+ the application. An ID is returned that can be used to remove the font again
+ with removeApplicationFont() or to retrieve the list of family names contained
+ in the font.
+
+ The function returns -1 if the font could not be loaded.
+
+ Currently only TrueType fonts, TrueType font collections, and OpenType fonts are
+ supported.
+
+ \note Adding application fonts on Unix/X11 platforms without fontconfig is
+ currently not supported.
+
+ \note On Symbian, the font family names get truncated to a length of 20 characters.
+
+ \sa addApplicationFontFromData(), applicationFontFamilies(), removeApplicationFont()
+*/
+int QFontDatabase::addApplicationFont(const QString &fileName)
+{
+ QByteArray data;
+ QFile f(fileName);
+ if (!(f.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
+ if (!f.open(QIODevice::ReadOnly))
+ return -1;
+ data = f.readAll();
+ }
+ QMutexLocker locker(fontDatabaseMutex());
+ return privateDb()->addAppFont(data, fileName);
+}
+
+/*!
+ \since 4.2
+
+ Loads the font from binary data specified by \a fontData and makes it available to
+ the application. An ID is returned that can be used to remove the font again
+ with removeApplicationFont() or to retrieve the list of family names contained
+ in the font.
+
+ The function returns -1 if the font could not be loaded.
+
+ Currently only TrueType fonts and TrueType font collections are supported.
+
+ \bold{Note:} Adding application fonts on Unix/X11 platforms without fontconfig is
+ currently not supported.
+
+ \note On Symbian, the font family names get truncated to a length of 20 characters.
+
+ \sa addApplicationFont(), applicationFontFamilies(), removeApplicationFont()
+*/
+int QFontDatabase::addApplicationFontFromData(const QByteArray &fontData)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+ return privateDb()->addAppFont(fontData, QString() /* fileName */);
+}
+
+/*!
+ \since 4.2
+
+ Returns a list of font families for the given application font identified by
+ \a id.
+
+ \sa addApplicationFont(), addApplicationFontFromData()
+*/
+QStringList QFontDatabase::applicationFontFamilies(int id)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+ return privateDb()->applicationFonts.value(id).families;
+}
+
+/*!
+ \fn bool QFontDatabase::removeApplicationFont(int id)
+ \since 4.2
+
+ Removes the previously loaded application font identified by \a
+ id. Returns true if unloading of the font succeeded; otherwise
+ returns false.
+
+ \sa removeAllApplicationFonts(), addApplicationFont(),
+ addApplicationFontFromData()
+*/
+
+/*!
+ \fn bool QFontDatabase::removeAllApplicationFonts()
+ \since 4.2
+
+ Removes all application-local fonts previously added using addApplicationFont()
+ and addApplicationFontFromData().
+
+ Returns true if unloading of the fonts succeeded; otherwise
+ returns false.
+
+ \sa removeApplicationFont(), addApplicationFont(), addApplicationFontFromData()
+*/
+
+/*!
+ \fn bool QFontDatabase::supportsThreadedFontRendering()
+ \since 4.4
+
+ Returns true if font rendering is supported outside the GUI
+ thread, false otherwise. In other words, a return value of false
+ means that all QPainter::drawText() calls outside the GUI thread
+ will not produce readable output.
+
+ \sa {Thread-Support in Qt Modules#Painting In Threads}{Painting In Threads}
+*/
+
+
+QT_END_NAMESPACE
+
diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h
new file mode 100644
index 0000000000..ae1130eadc
--- /dev/null
+++ b/src/gui/text/qfontdatabase.h
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QFONTDATABASE_H
+#define QFONTDATABASE_H
+
+#include <QtGui/qwindowdefs.h>
+#include <QtCore/qstring.h>
+#include <QtGui/qfont.h>
+#ifdef QT3_SUPPORT
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QStringList;
+template <class T> class QList;
+struct QFontDef;
+class QFontEngine;
+
+class QFontDatabasePrivate;
+
+class Q_GUI_EXPORT QFontDatabase
+{
+ Q_GADGET
+ Q_ENUMS(WritingSystem)
+public:
+ // do not re-order or delete entries from this enum without updating the
+ // QPF2 format and makeqpf!!
+ enum WritingSystem {
+ Any,
+
+ Latin,
+ Greek,
+ Cyrillic,
+ Armenian,
+ Hebrew,
+ Arabic,
+ Syriac,
+ Thaana,
+ Devanagari,
+ Bengali,
+ Gurmukhi,
+ Gujarati,
+ Oriya,
+ Tamil,
+ Telugu,
+ Kannada,
+ Malayalam,
+ Sinhala,
+ Thai,
+ Lao,
+ Tibetan,
+ Myanmar,
+ Georgian,
+ Khmer,
+ SimplifiedChinese,
+ TraditionalChinese,
+ Japanese,
+ Korean,
+ Vietnamese,
+
+ Symbol,
+ Other = Symbol,
+
+ Ogham,
+ Runic,
+ Nko,
+
+ WritingSystemsCount
+ };
+
+ static QList<int> standardSizes();
+
+ QFontDatabase();
+
+ QList<WritingSystem> writingSystems() const;
+ QList<WritingSystem> writingSystems(const QString &family) const;
+
+ QStringList families(WritingSystem writingSystem = Any) const;
+ QStringList styles(const QString &family) const;
+ QList<int> pointSizes(const QString &family, const QString &style = QString());
+ QList<int> smoothSizes(const QString &family, const QString &style);
+ QString styleString(const QFont &font);
+ QString styleString(const QFontInfo &fontInfo);
+
+ QFont font(const QString &family, const QString &style, int pointSize) const;
+
+ bool isBitmapScalable(const QString &family, const QString &style = QString()) const;
+ bool isSmoothlyScalable(const QString &family, const QString &style = QString()) const;
+ bool isScalable(const QString &family, const QString &style = QString()) const;
+ bool isFixedPitch(const QString &family, const QString &style = QString()) const;
+
+ bool italic(const QString &family, const QString &style) const;
+ bool bold(const QString &family, const QString &style) const;
+ int weight(const QString &family, const QString &style) const;
+
+ static QString writingSystemName(WritingSystem writingSystem);
+ static QString writingSystemSample(WritingSystem writingSystem);
+
+ static int addApplicationFont(const QString &fileName);
+ static int addApplicationFontFromData(const QByteArray &fontData);
+ static QStringList applicationFontFamilies(int id);
+ static bool removeApplicationFont(int id);
+ static bool removeAllApplicationFonts();
+
+ static bool supportsThreadedFontRendering();
+
+private:
+ static void createDatabase();
+ static void parseFontName(const QString &name, QString &foundry, QString &family);
+ static QString resolveFontFamilyAlias(const QString &family);
+#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN)
+ static QFontEngine *findFont(int script, const QFontPrivate *fp, const QFontDef &request);
+#endif
+ static void load(const QFontPrivate *d, int script);
+#ifdef Q_WS_X11
+ static QFontEngine *loadXlfd(int screen, int script, const QFontDef &request, int force_encoding_id = -1);
+#endif
+
+ friend struct QFontDef;
+ friend class QFontPrivate;
+ friend class QFontDialog;
+ friend class QFontDialogPrivate;
+ friend class QFontEngineMultiXLFD;
+ friend class QFontEngineMultiQWS;
+ friend class QFontEngineMultiS60;
+ friend class QFontEngineMultiQPA;
+
+ QFontDatabasePrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFONTDATABASE_H
diff --git a/src/gui/text/qfontdatabase_mac.cpp b/src/gui/text/qfontdatabase_mac.cpp
new file mode 100644
index 0000000000..5ba236b5f7
--- /dev/null
+++ b/src/gui/text/qfontdatabase_mac.cpp
@@ -0,0 +1,466 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 <private/qt_mac_p.h>
+#include "qfontengine_p.h"
+#include <qfile.h>
+#include <qabstractfileengine.h>
+#include <stdlib.h>
+#include <qendian.h>
+#include <private/qfontengine_coretext_p.h>
+#include <private/qfontengine_mac_p.h>
+
+QT_BEGIN_NAMESPACE
+
+int qt_mac_pixelsize(const QFontDef &def, int dpi); //qfont_mac.cpp
+int qt_mac_pointsize(const QFontDef &def, int dpi); //qfont_mac.cpp
+
+#ifndef QT_MAC_USE_COCOA
+static void initWritingSystems(QtFontFamily *family, ATSFontRef atsFont)
+{
+ ByteCount length = 0;
+ if (ATSFontGetTable(atsFont, MAKE_TAG('O', 'S', '/', '2'), 0, 0, 0, &length) != noErr)
+ return;
+ QVarLengthArray<uchar> os2Table(length);
+ if (length < 86
+ || ATSFontGetTable(atsFont, MAKE_TAG('O', 'S', '/', '2'), 0, length, os2Table.data(), &length) != noErr)
+ return;
+
+ // See also qfontdatabase_win.cpp, offsets taken from OS/2 table in the TrueType spec
+ quint32 unicodeRange[4] = {
+ qFromBigEndian<quint32>(os2Table.data() + 42),
+ qFromBigEndian<quint32>(os2Table.data() + 46),
+ qFromBigEndian<quint32>(os2Table.data() + 50),
+ qFromBigEndian<quint32>(os2Table.data() + 54)
+ };
+ quint32 codePageRange[2] = { qFromBigEndian<quint32>(os2Table.data() + 78), qFromBigEndian<quint32>(os2Table.data() + 82) };
+ QList<QFontDatabase::WritingSystem> systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange);
+#if 0
+ QCFString name;
+ ATSFontGetName(atsFont, kATSOptionFlagsDefault, &name);
+ qDebug() << systems.count() << "writing systems for" << QString(name);
+qDebug() << "first char" << hex << unicodeRange[0];
+ for (int i = 0; i < systems.count(); ++i)
+ qDebug() << QFontDatabase::writingSystemName(systems.at(i));
+#endif
+ for (int i = 0; i < systems.count(); ++i)
+ family->writingSystems[systems.at(i)] = QtFontFamily::Supported;
+}
+#endif
+
+static void initializeDb()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if(!db || db->count)
+ return;
+
+#if defined(QT_MAC_USE_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
+ QCFType<CTFontCollectionRef> collection = CTFontCollectionCreateFromAvailableFonts(0);
+ if(!collection)
+ return;
+ QCFType<CFArrayRef> fonts = CTFontCollectionCreateMatchingFontDescriptors(collection);
+ if(!fonts)
+ return;
+ QString foundry_name = "CoreText";
+ const int numFonts = CFArrayGetCount(fonts);
+ for(int i = 0; i < numFonts; ++i) {
+ CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fonts, i);
+
+ QCFString family_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
+ QtFontFamily *family = db->family(family_name, true);
+ for(int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws)
+ family->writingSystems[ws] = QtFontFamily::Supported;
+ QtFontFoundry *foundry = family->foundry(foundry_name, true);
+
+ QtFontStyle::Key styleKey;
+ if(QCFType<CFDictionaryRef> styles = (CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute)) {
+ if(CFNumberRef weight = (CFNumberRef)CFDictionaryGetValue(styles, kCTFontWeightTrait)) {
+ Q_ASSERT(CFNumberIsFloatType(weight));
+ double d;
+ if(CFNumberGetValue(weight, kCFNumberDoubleType, &d)) {
+ //qDebug() << "BOLD" << (QString)family_name << d;
+ styleKey.weight = (d > 0.0) ? QFont::Bold : QFont::Normal;
+ }
+ }
+ if(CFNumberRef italic = (CFNumberRef)CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
+ Q_ASSERT(CFNumberIsFloatType(italic));
+ double d;
+ if(CFNumberGetValue(italic, kCFNumberDoubleType, &d)) {
+ //qDebug() << "ITALIC" << (QString)family_name << d;
+ if (d > 0.0)
+ styleKey.style = QFont::StyleItalic;
+ }
+ }
+ }
+
+ QtFontStyle *style = foundry->style(styleKey, true);
+ style->smoothScalable = true;
+ if(QCFType<CFNumberRef> size = (CFNumberRef)CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) {
+ //qDebug() << "WHEE";
+ int pixel_size=0;
+ if(CFNumberIsFloatType(size)) {
+ double d;
+ CFNumberGetValue(size, kCFNumberDoubleType, &d);
+ pixel_size = d;
+ } else {
+ CFNumberGetValue(size, kCFNumberIntType, &pixel_size);
+ }
+ //qDebug() << "SIZE" << (QString)family_name << pixel_size;
+ if(pixel_size)
+ style->pixelSize(pixel_size, true);
+ } else {
+ //qDebug() << "WTF?";
+ }
+ }
+} else
+#endif
+ {
+#ifndef QT_MAC_USE_COCOA
+ FMFontIterator it;
+ if (!FMCreateFontIterator(0, 0, kFMUseGlobalScopeOption, &it)) {
+ while (true) {
+ FMFont fmFont;
+ if (FMGetNextFont(&it, &fmFont) != noErr)
+ break;
+
+ FMFontFamily fmFamily;
+ FMFontStyle fmStyle;
+ QString familyName;
+
+ QtFontStyle::Key styleKey;
+
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(fmFont);
+
+ if (!FMGetFontFamilyInstanceFromFont(fmFont, &fmFamily, &fmStyle)) {
+ { //sanity check the font, and see if we can use it at all! --Sam
+ ATSUFontID fontID;
+ if(ATSUFONDtoFontID(fmFamily, 0, &fontID) != noErr)
+ continue;
+ }
+
+ if (fmStyle & ::italic)
+ styleKey.style = QFont::StyleItalic;
+ if (fmStyle & ::bold)
+ styleKey.weight = QFont::Bold;
+
+ ATSFontFamilyRef familyRef = FMGetATSFontFamilyRefFromFontFamily(fmFamily);
+ QCFString cfFamilyName;;
+ ATSFontFamilyGetName(familyRef, kATSOptionFlagsDefault, &cfFamilyName);
+ familyName = cfFamilyName;
+ } else {
+ QCFString cfFontName;
+ ATSFontGetName(atsFont, kATSOptionFlagsDefault, &cfFontName);
+ familyName = cfFontName;
+ quint16 macStyle = 0;
+ {
+ uchar data[4];
+ ByteCount len = 4;
+ if (ATSFontGetTable(atsFont, MAKE_TAG('h', 'e', 'a', 'd'), 44, 4, &data, &len) == noErr)
+ macStyle = qFromBigEndian<quint16>(data);
+ }
+ if (macStyle & 1)
+ styleKey.weight = QFont::Bold;
+ if (macStyle & 2)
+ styleKey.style = QFont::StyleItalic;
+ }
+
+ QtFontFamily *family = db->family(familyName, true);
+ QtFontFoundry *foundry = family->foundry(QString(), true);
+ QtFontStyle *style = foundry->style(styleKey, true);
+ style->pixelSize(0, true);
+ style->smoothScalable = true;
+
+ initWritingSystems(family, atsFont);
+ }
+ FMDisposeFontIterator(&it);
+ }
+#endif
+ }
+
+}
+
+static inline void load(const QString & = QString(), int = -1)
+{
+ initializeDb();
+}
+
+static const char *styleHint(const QFontDef &request)
+{
+ const char *stylehint = 0;
+ switch (request.styleHint) {
+ case QFont::SansSerif:
+ stylehint = "Arial";
+ break;
+ case QFont::Serif:
+ stylehint = "Times New Roman";
+ break;
+ case QFont::TypeWriter:
+ stylehint = "Courier New";
+ break;
+ default:
+ if (request.fixedPitch)
+ stylehint = "Courier New";
+ break;
+ }
+ return stylehint;
+}
+
+static inline float weightToFloat(unsigned int weight)
+{
+ return (weight - 50) / 100.0;
+}
+
+void QFontDatabase::load(const QFontPrivate *d, int script)
+{
+ // sanity checks
+ if(!qApp)
+ qWarning("QFont: Must construct a QApplication before a QFont");
+
+ Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
+ Q_UNUSED(script);
+
+ QFontDef req = d->request;
+ req.pixelSize = qt_mac_pixelsize(req, d->dpi);
+
+ // set the point size to 0 to get better caching
+ req.pointSize = 0;
+ QFontCache::Key key = QFontCache::Key(req, QUnicodeTables::Common, d->screen);
+
+ if(!(d->engineData = QFontCache::instance()->findEngineData(key))) {
+ d->engineData = new QFontEngineData;
+ QFontCache::instance()->insertEngineData(key, d->engineData);
+ } else {
+ d->engineData->ref.ref();
+ }
+ if(d->engineData->engine) // already loaded
+ return;
+
+ // set it to the actual pointsize, so QFontInfo will do the right thing
+ req.pointSize = qRound(qt_mac_pointsize(d->request, d->dpi));
+
+ QFontEngine *e = QFontCache::instance()->findEngine(key);
+ if(!e && qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
+ e = new QTestFontEngine(req.pixelSize);
+ e->fontDef = req;
+ }
+
+ if(e) {
+ e->ref.ref();
+ d->engineData->engine = e;
+ return; // the font info and fontdef should already be filled
+ }
+
+ //find the font
+ QStringList family_list = familyList(req);
+
+ const char *stylehint = styleHint(req);
+ if (stylehint)
+ family_list << QLatin1String(stylehint);
+
+ // add QFont::defaultFamily() to the list, for compatibility with
+ // previous versions
+ family_list << QApplication::font().defaultFamily();
+
+#if defined(QT_MAC_USE_COCOA)
+ QCFString fontName = NULL, familyName = NULL;
+#else
+ ATSFontFamilyRef familyRef = 0;
+ ATSFontRef fontRef = 0;
+#endif
+
+ QMutexLocker locker(fontDatabaseMutex());
+ QFontDatabasePrivate *db = privateDb();
+ if (!db->count)
+ initializeDb();
+ for(int i = 0; i < family_list.size(); ++i) {
+ for (int k = 0; k < db->count; ++k) {
+ if (db->families[k]->name.compare(family_list.at(i), Qt::CaseInsensitive) == 0) {
+ QByteArray family_name = db->families[k]->name.toUtf8();
+#if defined(QT_MAC_USE_COCOA)
+ QCFType<CTFontRef> ctFont = CTFontCreateWithName(QCFString(db->families[k]->name), 12, NULL);
+ if (ctFont) {
+ fontName = CTFontCopyFullName(ctFont);
+ familyName = CTFontCopyFamilyName(ctFont);
+ goto FamilyFound;
+ }
+#else
+ familyRef = ATSFontFamilyFindFromName(QCFString(db->families[k]->name), kATSOptionFlagsDefault);
+ if (familyRef) {
+ fontRef = ATSFontFindFromName(QCFString(db->families[k]->name), kATSOptionFlagsDefault);
+ goto FamilyFound;
+ }
+#endif
+ }
+ }
+ }
+FamilyFound:
+ //fill in the engine's font definition
+ QFontDef fontDef = d->request; //copy..
+ if(fontDef.pointSize < 0)
+ fontDef.pointSize = qt_mac_pointsize(fontDef, d->dpi);
+ else
+ fontDef.pixelSize = qt_mac_pixelsize(fontDef, d->dpi);
+
+#ifdef QT_MAC_USE_COCOA
+ fontDef.family = familyName;
+ QFontEngine *engine = new QCoreTextFontEngineMulti(fontName, fontDef, d->kerning);
+#else
+ QCFString actualName;
+ if (ATSFontFamilyGetName(familyRef, kATSOptionFlagsDefault, &actualName) == noErr)
+ fontDef.family = actualName;
+ QFontEngine *engine = new QFontEngineMacMulti(familyRef, fontRef, fontDef, d->kerning);
+#endif
+ d->engineData->engine = engine;
+ engine->ref.ref(); //a ref for the engineData->engine
+ QFontCache::instance()->insertEngine(key, engine);
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
+{
+ ATSFontContainerRef handle;
+ OSStatus e = noErr;
+
+ if(fnt->data.isEmpty()) {
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
+ extern OSErr qt_mac_create_fsref(const QString &, FSRef *); // qglobal.cpp
+ FSRef ref;
+ if(qt_mac_create_fsref(fnt->fileName, &ref) != noErr)
+ return;
+
+ ATSFontActivateFromFileReference(&ref, kATSFontContextLocal, kATSFontFormatUnspecified, 0, kATSOptionFlagsDefault, &handle);
+ } else
+#endif
+ {
+#ifndef Q_WS_MAC64
+ extern Q_CORE_EXPORT OSErr qt_mac_create_fsspec(const QString &, FSSpec *); // global.cpp
+ FSSpec spec;
+ if(qt_mac_create_fsspec(fnt->fileName, &spec) != noErr)
+ return;
+
+ e = ATSFontActivateFromFileSpecification(&spec, kATSFontContextLocal, kATSFontFormatUnspecified,
+ 0, kATSOptionFlagsDefault, &handle);
+#endif
+ }
+ } else {
+ e = ATSFontActivateFromMemory((void *)fnt->data.constData(), fnt->data.size(), kATSFontContextLocal,
+ kATSFontFormatUnspecified, 0, kATSOptionFlagsDefault, &handle);
+
+ fnt->data = QByteArray();
+ }
+
+ if(e != noErr)
+ return;
+
+ ItemCount fontCount = 0;
+ e = ATSFontFindFromContainer(handle, kATSOptionFlagsDefault, 0, 0, &fontCount);
+ if(e != noErr)
+ return;
+
+ QVarLengthArray<ATSFontRef> containedFonts(fontCount);
+ e = ATSFontFindFromContainer(handle, kATSOptionFlagsDefault, fontCount, containedFonts.data(), &fontCount);
+ if(e != noErr)
+ return;
+
+ fnt->families.clear();
+#if defined(QT_MAC_USE_COCOA)
+ // Make sure that the family name set on the font matches what
+ // kCTFontFamilyNameAttribute returns in initializeDb().
+ // So far the best solution seems find the installed font
+ // using CoreText and get the family name from it.
+ // (ATSFontFamilyGetName appears to be the correct API, but also
+ // returns the font display name.)
+ for(int i = 0; i < containedFonts.size(); ++i) {
+ QCFString fontPostScriptName;
+ ATSFontGetPostScriptName(containedFonts[i], kATSOptionFlagsDefault, &fontPostScriptName);
+ QCFType<CTFontDescriptorRef> font = CTFontDescriptorCreateWithNameAndSize(fontPostScriptName, 14);
+ QCFString familyName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
+ fnt->families.append(familyName);
+ }
+#else
+ for(int i = 0; i < containedFonts.size(); ++i) {
+ QCFString family;
+ ATSFontGetName(containedFonts[i], kATSOptionFlagsDefault, &family);
+ fnt->families.append(family);
+ }
+#endif
+
+ fnt->handle = handle;
+}
+
+bool QFontDatabase::removeApplicationFont(int handle)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ if(handle < 0 || handle >= db->applicationFonts.count())
+ return false;
+
+ OSStatus e = ATSFontDeactivate(db->applicationFonts.at(handle).handle,
+ /*iRefCon=*/0, kATSOptionFlagsDefault);
+ if(e != noErr)
+ return false;
+
+ db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
+
+ db->invalidate();
+ return true;
+}
+
+bool QFontDatabase::removeAllApplicationFonts()
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ for(int i = 0; i < db->applicationFonts.count(); ++i) {
+ if(!removeApplicationFont(i))
+ return false;
+ }
+ return true;
+}
+
+bool QFontDatabase::supportsThreadedFontRendering()
+{
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp
new file mode 100644
index 0000000000..7bcce56ac8
--- /dev/null
+++ b/src/gui/text/qfontdatabase_qpa.cpp
@@ -0,0 +1,394 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 QFont::StyleHint &styleHint, const QUnicodeTables::Script &script)
+{
+ QStringList retList = QApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,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();
+ 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) {
+ QFont::Style fontStyle = QFont::Style(style->key.style);
+ QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint);
+ if (styleHint == QFont::AnyStyle && request.fixedPitch)
+ styleHint = QFont::TypeWriter;
+ family->fallbackFamilies = fallbackFamilies(family->name,fontStyle,styleHint,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();
+
+ fnt->families = 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),QFont::StyleHint(request.styleHint),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/qfontdatabase_qws.cpp b/src/gui/text/qfontdatabase_qws.cpp
new file mode 100644
index 0000000000..d076de05d3
--- /dev/null
+++ b/src/gui/text/qfontdatabase_qws.cpp
@@ -0,0 +1,975 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qdir.h"
+#if defined(Q_WS_QWS)
+#include "qscreen_qws.h" //so we can check for rotation
+#include "qwindowsystem_qws.h"
+#endif
+#include "qlibraryinfo.h"
+#include "qabstractfileengine.h"
+#include <QtCore/qsettings.h>
+#if !defined(QT_NO_FREETYPE)
+#include "qfontengine_ft_p.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#endif
+#include "qfontengine_qpf_p.h"
+#include "private/qfactoryloader_p.h"
+#include "private/qcore_unix_p.h" // overrides QT_OPEN
+#include "qabstractfontengine_qws.h"
+#include "qabstractfontengine_p.h"
+#include <qdatetime.h>
+#include "qplatformdefs.h"
+
+// for mmap
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef QT_FONTS_ARE_RESOURCES
+#include <qresource.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QFontEngineFactoryInterface_iid, QLatin1String("/fontengines"), Qt::CaseInsensitive))
+#endif
+
+const quint8 DatabaseVersion = 4;
+
+// QFontDatabasePrivate::addFont() went into qfontdatabase.cpp
+
+#ifndef QT_NO_QWS_QPF2
+void QFontDatabasePrivate::addQPF2File(const QByteArray &file)
+{
+#ifndef QT_FONTS_ARE_RESOURCES
+ struct stat st;
+ if (stat(file.constData(), &st))
+ return;
+ int f = QT_OPEN(file, O_RDONLY, 0);
+ if (f < 0)
+ return;
+ const uchar *data = (const uchar *)mmap(0, st.st_size, PROT_READ, MAP_SHARED, f, 0);
+ const int dataSize = st.st_size;
+#else
+ QResource res(QLatin1String(file.constData()));
+ const uchar *data = res.data();
+ const int dataSize = res.size();
+ //qDebug() << "addQPF2File" << file << data;
+#endif
+ if (data && data != (const uchar *)MAP_FAILED) {
+ if (QFontEngineQPF::verifyHeader(data, dataSize)) {
+ QString fontName = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_FontName).toString();
+ int pixelSize = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_PixelSize).toInt();
+ QVariant weight = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_Weight);
+ QVariant style = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_Style);
+ QByteArray writingSystemBits = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_WritingSystems).toByteArray();
+
+ if (!fontName.isEmpty() && pixelSize) {
+ int fontWeight = 50;
+ if (weight.type() == QVariant::Int || weight.type() == QVariant::UInt)
+ fontWeight = weight.toInt();
+
+ bool italic = static_cast<QFont::Style>(style.toInt()) & QFont::StyleItalic;
+
+ QList<QFontDatabase::WritingSystem> 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 << QFontDatabase::WritingSystem(i * 8 + j);
+ currentByte >>= 1;
+ }
+ }
+
+ addFont(fontName, /*foundry*/ "prerendered", fontWeight, italic,
+ pixelSize, file, /*fileIndex*/ 0,
+ /*antialiased*/ true, writingSystems);
+ }
+ } else {
+ qDebug() << "header verification of QPF2 font" << file << "failed. maybe it is corrupt?";
+ }
+#ifndef QT_FONTS_ARE_RESOURCES
+ munmap((void *)data, st.st_size);
+#endif
+ }
+#ifndef QT_FONTS_ARE_RESOURCES
+ QT_CLOSE(f);
+#endif
+}
+#endif // QT_NO_QWS_QPF2
+
+// QFontDatabasePrivate::addTTFile() went into qfontdatabase.cpp
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
+
+extern QString qws_fontCacheDir();
+
+#ifndef QT_FONTS_ARE_RESOURCES
+bool QFontDatabasePrivate::loadFromCache(const QString &fontPath)
+{
+#ifdef Q_WS_QWS
+ const bool weAreTheServer = QWSServer::instance();
+#else
+ const bool weAreTheServer = true; // assume single-process
+#endif
+
+ QString fontDirFile = fontPath + QLatin1String("/fontdir");
+
+ QFile binaryDb(qws_fontCacheDir() + QLatin1String("/fontdb"));
+
+ if (weAreTheServer) {
+ QDateTime dbTimeStamp = QFileInfo(binaryDb.fileName()).lastModified();
+
+ QDateTime fontPathTimeStamp = QFileInfo(fontPath).lastModified();
+ if (dbTimeStamp < fontPathTimeStamp)
+ return false; // let the caller create the cache
+
+ if (QFile::exists(fontDirFile)) {
+ QDateTime fontDirTimeStamp = QFileInfo(fontDirFile).lastModified();
+ if (dbTimeStamp < fontDirTimeStamp)
+ return false;
+ }
+ }
+
+ if (!binaryDb.open(QIODevice::ReadOnly)) {
+ if (weAreTheServer)
+ return false; // let the caller create the cache
+ qFatal("QFontDatabase::loadFromCache: Could not open font database cache!");
+ }
+
+ QDataStream stream(&binaryDb);
+ quint8 version = 0;
+ quint8 dataStreamVersion = 0;
+ stream >> version >> dataStreamVersion;
+ if (version != DatabaseVersion || dataStreamVersion != stream.version()) {
+ if (weAreTheServer)
+ return false; // let the caller create the cache
+ qFatal("QFontDatabase::loadFromCache: Wrong version of the font database cache detected. Found %d/%d expected %d/%d",
+ version, dataStreamVersion, DatabaseVersion, stream.version());
+ }
+
+ QString originalFontPath;
+ stream >> originalFontPath;
+ if (originalFontPath != fontPath) {
+ if (weAreTheServer)
+ return false; // let the caller create the cache
+ qFatal("QFontDatabase::loadFromCache: Font path doesn't match. Found %s in database, expected %s", qPrintable(originalFontPath), qPrintable(fontPath));
+ }
+
+ QString familyname;
+ stream >> familyname;
+ //qDebug() << "populating database from" << binaryDb.fileName();
+ while (!familyname.isEmpty() && !stream.atEnd()) {
+ QString foundryname;
+ int weight;
+ quint8 italic;
+ int pixelSize;
+ QByteArray file;
+ int fileIndex;
+ quint8 antialiased;
+ quint8 writingSystemCount;
+
+ QList<QFontDatabase::WritingSystem> writingSystems;
+
+ stream >> foundryname >> weight >> italic >> pixelSize
+ >> file >> fileIndex >> antialiased >> writingSystemCount;
+
+ for (quint8 i = 0; i < writingSystemCount; ++i) {
+ quint8 ws;
+ stream >> ws;
+ writingSystems.append(QFontDatabase::WritingSystem(ws));
+ }
+
+ addFont(familyname, foundryname.toLatin1().constData(), weight, italic, pixelSize, file, fileIndex, antialiased,
+ writingSystems);
+
+ stream >> familyname;
+ }
+
+ stream >> fallbackFamilies;
+ //qDebug() << "fallback families from cache:" << fallbackFamilies;
+ return true;
+}
+#endif // QT_FONTS_ARE_RESOURCES
+
+/*!
+ \internal
+*/
+
+static QString qwsFontPath()
+{
+ QString fontpath = QString::fromLocal8Bit(qgetenv("QT_QWS_FONTDIR"));
+ if (fontpath.isEmpty()) {
+#ifdef QT_FONTS_ARE_RESOURCES
+ fontpath = QLatin1String(":/qt/fonts");
+#else
+#ifndef QT_NO_SETTINGS
+ fontpath = QLibraryInfo::location(QLibraryInfo::LibrariesPath);
+ fontpath += QLatin1String("/fonts");
+#else
+ fontpath = QLatin1String("/lib/fonts");
+#endif
+#endif //QT_FONTS_ARE_RESOURCES
+ }
+
+ return fontpath;
+}
+
+#if defined(QFONTDATABASE_DEBUG) && defined(QT_FONTS_ARE_RESOURCES)
+class FriendlyResource : public QResource
+{
+public:
+ bool isDir () const { return QResource::isDir(); }
+ bool isFile () const { return QResource::isFile(); }
+ QStringList children () const { return QResource::children(); }
+};
+#endif
+/*!
+ \internal
+*/
+static void initializeDb()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db || db->count)
+ return;
+
+ QString fontpath = qwsFontPath();
+#ifndef QT_FONTS_ARE_RESOURCES
+ QString fontDirFile = fontpath + QLatin1String("/fontdir");
+
+ if(!QFile::exists(fontpath)) {
+ qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
+ fontpath.toLocal8Bit().constData());
+ }
+
+ const bool loaded = db->loadFromCache(fontpath);
+
+ if (db->reregisterAppFonts) {
+ db->reregisterAppFonts = false;
+ for (int i = 0; i < db->applicationFonts.count(); ++i)
+ if (!db->applicationFonts.at(i).families.isEmpty()) {
+ registerFont(&db->applicationFonts[i]);
+ }
+ }
+
+ if (loaded)
+ return;
+
+ QString dbFileName = qws_fontCacheDir() + QLatin1String("/fontdb");
+
+ QFile binaryDb(dbFileName + QLatin1String(".tmp"));
+ binaryDb.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ db->stream = new QDataStream(&binaryDb);
+ *db->stream << DatabaseVersion << quint8(db->stream->version()) << fontpath;
+// qDebug() << "creating binary database at" << binaryDb.fileName();
+
+ // Load in font definition file
+ FILE* fontdef=fopen(fontDirFile.toLocal8Bit().constData(),"r");
+ if (fontdef) {
+ char buf[200]="";
+ char name[200]="";
+ char render[200]="";
+ char file[200]="";
+ char isitalic[10]="";
+ char flags[10]="";
+ do {
+ fgets(buf,200,fontdef);
+ if (buf[0] != '#') {
+ int weight=50;
+ int size=0;
+ sscanf(buf,"%s %s %s %s %d %d %s",name,file,render,isitalic,&weight,&size,flags);
+ QString filename;
+ if (file[0] != '/')
+ filename.append(fontpath).append(QLatin1Char('/'));
+ filename += QLatin1String(file);
+ bool italic = isitalic[0] == 'y';
+ bool smooth = QByteArray(flags).contains('s');
+ if (file[0] && QFile::exists(filename))
+ db->addFont(QString::fromUtf8(name), /*foundry*/"", weight, italic, size/10, QFile::encodeName(filename), /*fileIndex*/ 0, smooth);
+ }
+ } while (!feof(fontdef));
+ fclose(fontdef);
+ }
+
+
+ QDir dir(fontpath, QLatin1String("*.qpf"));
+ for (int i=0; i<int(dir.count()); i++) {
+ int u0 = dir[i].indexOf(QLatin1Char('_'));
+ int u1 = dir[i].indexOf(QLatin1Char('_'), u0+1);
+ int u2 = dir[i].indexOf(QLatin1Char('_'), u1+1);
+ int u3 = dir[i].indexOf(QLatin1Char('.'), u1+1);
+ if (u2 < 0) u2 = u3;
+
+ QString familyname = dir[i].left(u0);
+ int pixelSize = dir[i].mid(u0+1,u1-u0-1).toInt()/10;
+ bool italic = dir[i].mid(u2-1,1) == QLatin1String("i");
+ int weight = dir[i].mid(u1+1,u2-u1-1-(italic?1:0)).toInt();
+
+ db->addFont(familyname, /*foundry*/ "qt", weight, italic, pixelSize, QFile::encodeName(dir.absoluteFilePath(dir[i])),
+ /*fileIndex*/ 0, /*antialiased*/ true);
+ }
+
+#ifndef QT_NO_FREETYPE
+ 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;
+ db->addTTFile(file);
+ }
+#endif
+
+#ifndef QT_NO_QWS_QPF2
+ dir.setNameFilters(QStringList() << QLatin1String("*.qpf2"));
+ dir.refresh();
+ for (int i = 0; i < int(dir.count()); ++i) {
+ const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
+// qDebug() << "looking at" << file;
+ db->addQPF2File(file);
+ }
+#endif
+
+#else //QT_FONTS_ARE_RESOURCES
+#ifdef QFONTDATABASE_DEBUG
+ {
+ QResource fontdir(fontpath);
+ FriendlyResource *fr = static_cast<FriendlyResource*>(&fontdir);
+ qDebug() << "fontdir" << fr->isValid() << fr->isDir() << fr->children();
+
+ }
+#endif
+#ifndef QT_NO_QWS_QPF2
+ QDir dir(fontpath, QLatin1String("*.qpf2"));
+ for (int i = 0; i < int(dir.count()); ++i) {
+ const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
+ //qDebug() << "looking at" << file;
+ db->addQPF2File(file);
+ }
+#endif
+#endif //QT_FONTS_ARE_RESOURCES
+
+
+#ifdef QFONTDATABASE_DEBUG
+ // print the database
+ for (int f = 0; f < db->count; f++) {
+ QtFontFamily *family = db->families[f];
+ FD_DEBUG("'%s' %s", qPrintable(family->name), (family->fixedPitch ? "fixed" : ""));
+#if 0
+ for (int i = 0; i < QFont::LastPrivateScript; ++i) {
+ FD_DEBUG("\t%s: %s", qPrintable(QFontDatabase::scriptName((QFont::Script) i)),
+ ((family->scripts[i] & QtFontFamily::Supported) ? "Supported" :
+ (family->scripts[i] & QtFontFamily::UnSupported) == QtFontFamily::UnSupported ?
+ "UnSupported" : "Unknown"));
+ }
+#endif
+
+ for (int fd = 0; fd < family->count; fd++) {
+ QtFontFoundry *foundry = family->foundries[fd];
+ FD_DEBUG("\t\t'%s'", qPrintable(foundry->name));
+ for (int s = 0; s < foundry->count; s++) {
+ QtFontStyle *style = foundry->styles[s];
+ FD_DEBUG("\t\t\tstyle: style=%d weight=%d\n"
+ "\t\t\tstretch=%d",
+ style->key.style, style->key.weight,
+ style->key.stretch);
+ if (style->smoothScalable)
+ FD_DEBUG("\t\t\t\tsmooth scalable");
+ else if (style->bitmapScalable)
+ FD_DEBUG("\t\t\t\tbitmap scalable");
+ if (style->pixelSizes) {
+ FD_DEBUG("\t\t\t\t%d pixel sizes", style->count);
+ for (int z = 0; z < style->count; ++z) {
+ QtFontSize *size = style->pixelSizes + z;
+ FD_DEBUG("\t\t\t\t size %5d",
+ size->pixelSize);
+ }
+ }
+ }
+ }
+ }
+#endif // QFONTDATABASE_DEBUG
+
+#ifndef QT_NO_LIBRARY
+ QStringList pluginFoundries = loader()->keys();
+// qDebug() << "plugin foundries:" << pluginFoundries;
+ for (int i = 0; i < pluginFoundries.count(); ++i) {
+ const QString foundry(pluginFoundries.at(i));
+
+ QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry));
+ if (!factory) {
+ qDebug() << "Could not load plugin for foundry" << foundry;
+ continue;
+ }
+
+ QList<QFontEngineInfo> fonts = factory->availableFontEngines();
+ for (int i = 0; i < fonts.count(); ++i) {
+ QFontEngineInfo info = fonts.at(i);
+
+ int weight = info.weight();
+ if (weight <= 0)
+ weight = QFont::Normal;
+
+ db->addFont(info.family(), foundry.toLatin1().constData(),
+ weight, info.style() != QFont::StyleNormal,
+ qRound(info.pixelSize()), /*file*/QByteArray(),
+ /*fileIndex*/0, /*antiAliased*/true,
+ info.writingSystems());
+ }
+ }
+#endif
+
+#ifndef QT_FONTS_ARE_RESOURCES
+ // the empty string/familyname signifies the end of the font list.
+ *db->stream << QString();
+#endif
+ {
+ bool coveredWritingSystems[QFontDatabase::WritingSystemsCount] = { 0 };
+
+ db->fallbackFamilies.clear();
+
+ for (int i = 0; i < db->count; ++i) {
+ QtFontFamily *family = db->families[i];
+ bool add = false;
+ if (family->count == 0)
+ continue;
+ if (family->bogusWritingSystems)
+ continue;
+ for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
+ if (coveredWritingSystems[ws])
+ continue;
+ if (family->writingSystems[ws] & QtFontFamily::Supported) {
+ coveredWritingSystems[ws] = true;
+ add = true;
+ }
+ }
+ if (add)
+ db->fallbackFamilies << family->name;
+ }
+ //qDebug() << "fallbacks on the server:" << db->fallbackFamilies;
+#ifndef QT_FONTS_ARE_RESOURCES
+ *db->stream << db->fallbackFamilies;
+#endif
+ }
+#ifndef QT_FONTS_ARE_RESOURCES
+ delete db->stream;
+ db->stream = 0;
+ QFile::remove(dbFileName);
+ binaryDb.rename(dbFileName);
+#endif
+}
+
+// called from qwindowsystem_qws.cpp
+void qt_qws_init_fontdb()
+{
+ initializeDb();
+}
+
+#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();
+}
+
+#ifndef QT_NO_FREETYPE
+
+#if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
+#define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
+#define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
+#else
+#define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
+#define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
+#endif
+
+#endif // QT_NO_FREETYPE
+
+static
+QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp,
+ const QFontDef &request,
+ QtFontFamily *family, QtFontFoundry *foundry,
+ QtFontStyle *style, QtFontSize *size)
+{
+ Q_UNUSED(script);
+ Q_UNUSED(fp);
+#ifdef QT_NO_FREETYPE
+ Q_UNUSED(foundry);
+#endif
+#ifdef QT_NO_QWS_QPF
+ Q_UNUSED(family);
+#endif
+ Q_ASSERT(size);
+
+ int pixelSize = size->pixelSize;
+ if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE))
+ pixelSize = request.pixelSize;
+
+#ifndef QT_NO_QWS_QPF2
+ if (foundry->name == QLatin1String("prerendered")) {
+#ifdef QT_FONTS_ARE_RESOURCES
+ QResource res(QLatin1String(size->fileName.constData()));
+ if (res.isValid()) {
+ QFontEngineQPF *fe = new QFontEngineQPF(request, res.data(), res.size());
+ if (fe->isValid())
+ return fe;
+ delete fe;
+ qDebug() << "fontengine is not valid! " << size->fileName;
+ } else {
+ qDebug() << "Resource not valid" << size->fileName;
+ }
+#else
+ int f = ::open(size->fileName, O_RDONLY, 0);
+ if (f >= 0) {
+ QFontEngineQPF *fe = new QFontEngineQPF(request, f);
+ if (fe->isValid())
+ return fe;
+ delete fe; // will close f
+ qDebug() << "fontengine is not valid!";
+ }
+#endif
+ } else
+#endif
+ if ( foundry->name != QLatin1String("qt") ) { ///#### is this the best way????
+ QString file = QFile::decodeName(size->fileName);
+
+ QFontDef def = request;
+ def.pixelSize = pixelSize;
+
+#ifdef QT_NO_QWS_SHARE_FONTS
+ bool shareFonts = false;
+#else
+ static bool dontShareFonts = !qgetenv("QWS_NO_SHARE_FONTS").isEmpty();
+ bool shareFonts = !dontShareFonts;
+#endif
+
+ QScopedPointer<QFontEngine> engine;
+
+#ifndef QT_NO_LIBRARY
+ QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry->name));
+ if (factory) {
+ QFontEngineInfo info;
+ info.setFamily(request.family);
+ info.setPixelSize(request.pixelSize);
+ info.setStyle(QFont::Style(request.style));
+ info.setWeight(request.weight);
+ // #### antialiased
+
+ QAbstractFontEngine *customEngine = factory->create(info);
+ if (customEngine) {
+ engine.reset(new QProxyFontEngine(customEngine, def));
+
+ if (shareFonts) {
+ QVariant hint = customEngine->fontProperty(QAbstractFontEngine::CacheGlyphsHint);
+ if (hint.isValid())
+ shareFonts = hint.toBool();
+ else
+ shareFonts = (pixelSize < 64);
+ }
+ }
+ }
+#endif // QT_NO_LIBRARY
+ if ((engine.isNull() && !file.isEmpty() && QFile::exists(file)) || privateDb()->isApplicationFont(file)) {
+ QFontEngine::FaceId faceId;
+ faceId.filename = file.toLocal8Bit();
+ faceId.index = size->fileIndex;
+
+#ifndef QT_NO_FREETYPE
+
+ QScopedPointer<QFontEngineFT> fte(new QFontEngineFT(def));
+ bool antialias = style->antialiased && !(request.styleStrategy & QFont::NoAntialias);
+ if (fte->init(faceId, antialias,
+ antialias ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono)) {
+#ifdef QT_NO_QWS_QPF2
+ return fte.take();
+#else
+ // try to distinguish between bdf and ttf fonts we can pre-render
+ // and don't try to share outline fonts
+ shareFonts = shareFonts
+ && !fte->defaultGlyphs()->outline_drawing
+ && !fte->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd')).isEmpty();
+ engine.reset(fte.take());
+#endif
+ }
+#endif // QT_NO_FREETYPE
+ }
+ if (!engine.isNull()) {
+#if !defined(QT_NO_QWS_QPF2) && !defined(QT_FONTS_ARE_RESOURCES)
+ if (shareFonts) {
+ QScopedPointer<QFontEngineQPF> fe(new QFontEngineQPF(def, -1, engine.data()));
+ engine.take();
+ if (fe->isValid())
+ return fe.take();
+ qWarning("Initializing QFontEngineQPF failed for %s", qPrintable(file));
+ engine.reset(fe->takeRenderingEngine());
+ }
+#endif
+ return engine.take();
+ }
+ } else
+ {
+#ifndef QT_NO_QWS_QPF
+ QString fn = qwsFontPath();
+ fn += QLatin1Char('/');
+ fn += family->name.toLower()
+ + QLatin1Char('_') + QString::number(pixelSize*10)
+ + QLatin1Char('_') + QString::number(style->key.weight)
+ + (style->key.style == QFont::StyleItalic ?
+ QLatin1String("i.qpf") : QLatin1String(".qpf"));
+ //###rotation ###
+
+ QFontEngine *fe = new QFontEngineQPF1(request, fn);
+ return fe;
+#endif // QT_NO_QWS_QPF
+ }
+ return new QFontEngineBox(pixelSize);
+}
+
+static
+QFontEngine *loadEngine(int script, const QFontPrivate *fp,
+ const QFontDef &request,
+ QtFontFamily *family, QtFontFoundry *foundry,
+ QtFontStyle *style, QtFontSize *size)
+{
+ QScopedPointer<QFontEngine> engine(loadSingleEngine(script, fp, request, family, foundry,
+ style, size));
+#ifndef QT_NO_QWS_QPF
+ if (!engine.isNull()
+ && script == QUnicodeTables::Common
+ && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
+
+ QStringList fallbacks = privateDb()->fallbackFamilies;
+
+ if (family && !family->fallbackFamilies.isEmpty())
+ fallbacks = family->fallbackFamilies;
+
+ QFontEngine *fe = new QFontEngineMultiQWS(engine.data(), script, fallbacks);
+ engine.take();
+ engine.reset(fe);
+ }
+#endif
+ return engine.take();
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
+{
+ QFontDatabasePrivate *db = privateDb();
+#ifdef QT_NO_FREETYPE
+ Q_UNUSED(fnt);
+#else
+ fnt->families = db->addTTFile(QFile::encodeName(fnt->fileName), fnt->data);
+ db->fallbackFamilies += fnt->families;
+#endif
+ 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();
+
+ QScopedPointer<QFontEngine> fe;
+ if (fp) {
+ if (fp->rawMode) {
+ fe.reset(loadEngine(script, fp, request, 0, 0, 0, 0));
+
+ // if we fail to load the rawmode font, use a 12pixel box engine instead
+ if (fe.isNull())
+ fe.reset(new QFontEngineBox(12));
+ return fe.take();
+ }
+
+ QFontCache::Key key(request, script);
+ fe.reset(QFontCache::instance()->findEngine(key));
+ if (! fe.isNull())
+ return fe.take();
+ }
+
+ QString family_name, foundry_name;
+ QtFontStyle::Key styleKey;
+ styleKey.style = request.style;
+ styleKey.weight = request.weight;
+ styleKey.stretch = request.stretch;
+ char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
+
+ parseFontName(request.family, foundry_name, family_name);
+
+ FM_DEBUG("QFontDatabase::findFont\n"
+ " request:\n"
+ " family: %s [%s], script: %d\n"
+ " weight: %d, style: %d\n"
+ " stretch: %d\n"
+ " pixelSize: %g\n"
+ " pitch: %c",
+ family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
+ foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
+ script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
+
+ if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
+ fe.reset(new QTestFontEngine(request.pixelSize));
+ fe->fontDef = request;
+ }
+
+ if (fe.isNull())
+ {
+ QtFontDesc desc;
+ match(script, request, family_name, foundry_name, force_encoding_id, &desc);
+
+ if (desc.family != 0 && desc.foundry != 0 && desc.style != 0
+ ) {
+ FM_DEBUG(" BEST:\n"
+ " family: %s [%s]\n"
+ " weight: %d, style: %d\n"
+ " stretch: %d\n"
+ " pixelSize: %d\n"
+ " pitch: %c\n"
+ " encoding: %d\n",
+ desc.family->name.toLatin1().constData(),
+ desc.foundry->name.isEmpty() ? "-- none --" : desc.foundry->name.toLatin1().constData(),
+ desc.style->key.weight, desc.style->key.style,
+ desc.style->key.stretch, desc.size ? desc.size->pixelSize : 0xffff,
+ 'p', 0
+ );
+
+ fe.reset(loadEngine(script, fp, request, desc.family, desc.foundry, desc.style, desc.size
+ ));
+ } else {
+ FM_DEBUG(" NO MATCH FOUND\n");
+ }
+ if (! fe.isNull())
+ initFontDef(desc, request, &fe->fontDef);
+ }
+
+#ifndef QT_NO_FREETYPE
+ if (! fe.isNull()) {
+ if (scriptRequiresOpenType(script) && fe->type() == QFontEngine::Freetype) {
+ HB_Face hbFace = static_cast<QFontEngineFT *>(fe.data())->harfbuzzFace();
+ if (!hbFace || !hbFace->supported_scripts[script]) {
+ FM_DEBUG(" OpenType support missing for script\n");
+ fe.reset(0);
+ }
+ }
+ }
+#endif
+
+ if (! fe.isNull()) {
+ if (fp) {
+ QFontDef def = request;
+ if (def.family.isEmpty()) {
+ def.family = fp->request.family;
+ def.family = def.family.left(def.family.indexOf(QLatin1Char(',')));
+ }
+ QFontCache::Key key(def, script);
+ QFontCache::instance()->insertEngine(key, fe.data());
+ }
+ }
+
+ if (fe.isNull()) {
+ if (!request.family.isEmpty())
+ return 0;
+
+ FM_DEBUG("returning box engine");
+
+ fe.reset(new QFontEngineBox(request.pixelSize));
+
+ if (fp) {
+ QFontCache::Key key(request, script);
+ QFontCache::instance()->insertEngine(key, fe.data());
+ }
+ }
+
+ if (fp && fp->dpi > 0) {
+ fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / fp->dpi));
+ } else {
+ fe->fontDef.pointSize = request.pointSize;
+ }
+
+ return fe.take();
+}
+
+void QFontDatabase::load(const QFontPrivate *d, int script)
+{
+ QFontDef req = d->request;
+
+ if (req.pixelSize == -1)
+ req.pixelSize = qRound(req.pointSize*d->dpi/72);
+ if (req.pointSize < 0)
+ req.pointSize = req.pixelSize*72.0/d->dpi;
+
+ if (!d->engineData) {
+ QFontCache::Key key(req, script);
+
+ // look for the requested font in the engine data cache
+ d->engineData = QFontCache::instance()->findEngineData(key);
+
+ if (!d->engineData) {
+ // create a new one
+ d->engineData = new QFontEngineData;
+ QT_TRY {
+ QFontCache::instance()->insertEngineData(key, d->engineData);
+ } QT_CATCH(...) {
+ delete d->engineData;
+ d->engineData = 0;
+ QT_RETHROW;
+ }
+ } else {
+ d->engineData->ref.ref();
+ }
+ }
+
+ // the cached engineData could have already loaded the engine we want
+ if (d->engineData->engines[script]) return;
+
+ // double scale = 1.0; // ### TODO: fix the scale calculations
+
+ // list of families to try
+ QStringList family_list;
+
+ if (!req.family.isEmpty()) {
+ family_list = req.family.split(QLatin1Char(','));
+
+ // append the substitute list for each family in family_list
+ QStringList subs_list;
+ QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
+ for (; it != end; ++it)
+ subs_list += QFont::substitutes(*it);
+ family_list += subs_list;
+
+ // append the default fallback font for the specified script
+ // family_list << ... ; ###########
+
+ // add the default family
+ QString defaultFamily = QApplication::font().family();
+ if (! family_list.contains(defaultFamily))
+ family_list << defaultFamily;
+
+ // add QFont::defaultFamily() to the list, for compatibility with
+ // previous versions
+ family_list << QApplication::font().defaultFamily();
+ }
+
+ // null family means find the first font matching the specified script
+ family_list << QString();
+
+ // load the font
+ QFontEngine *engine = 0;
+ QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
+ for (; !engine && it != end; ++it) {
+ req.family = *it;
+
+ engine = QFontDatabase::findFont(script, d, req);
+ if (engine && (engine->type()==QFontEngine::Box) && !req.family.isEmpty())
+ engine = 0;
+ }
+
+ engine->ref.ref();
+ d->engineData->engines[script] = engine;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp
new file mode 100644
index 0000000000..1db4a7d359
--- /dev/null
+++ b/src/gui/text/qfontdatabase_s60.cpp
@@ -0,0 +1,1091 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 <private/qapplication_p.h>
+#include "qdir.h"
+#include "qfont_p.h"
+#include "qfontengine_s60_p.h"
+#include "qabstractfileengine.h"
+#include "qdesktopservices.h"
+#include "qtemporaryfile.h"
+#include "qtextcodec.h"
+#include <private/qpixmap_s60_p.h>
+#include <private/qt_s60_p.h>
+#include "qendian.h"
+#include <private/qcore_symbian_p.h>
+#ifdef QT_NO_FREETYPE
+#include <openfont.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <graphics/openfontrasterizer.h> // COpenFontRasterizer has moved to a new header file
+#endif // SYMBIAN_ENABLE_SPLIT_HEADERS
+#endif // QT_NO_FREETYPE
+
+QT_BEGIN_NAMESPACE
+
+QStringList qt_symbian_fontFamiliesOnFontServer() // Also used in qfont_s60.cpp
+{
+ QStringList result;
+ QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
+ const int numTypeFaces = S60->screenDevice()->NumTypefaces();
+ for (int i = 0; i < numTypeFaces; i++) {
+ TTypefaceSupport typefaceSupport;
+ S60->screenDevice()->TypefaceSupport(typefaceSupport, i);
+ const QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
+ result.append(familyName);
+ }
+ lock.relock();
+ return result;
+}
+
+QFileInfoList alternativeFilePaths(const QString &path, const QStringList &nameFilters,
+ QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort,
+ bool uniqueFileNames = true)
+{
+ QFileInfoList result;
+
+ // Prepare a 'soft to hard' drive list: W:, X: ... A:, Z:
+ QStringList driveStrings;
+ foreach (const QFileInfo &drive, QDir::drives())
+ driveStrings.append(drive.absolutePath());
+ driveStrings.sort();
+ const QString zDriveString(QLatin1String("Z:/"));
+ driveStrings.removeAll(zDriveString);
+ driveStrings.prepend(zDriveString);
+
+ QStringList uniqueFileNameList;
+ for (int i = driveStrings.count() - 1; i >= 0; --i) {
+ const QDir dirOnDrive(driveStrings.at(i) + path);
+ const QFileInfoList entriesOnDrive = dirOnDrive.entryInfoList(nameFilters, filters, sort);
+ if (uniqueFileNames) {
+ foreach(const QFileInfo &entry, entriesOnDrive) {
+ if (!uniqueFileNameList.contains(entry.fileName())) {
+ uniqueFileNameList.append(entry.fileName());
+ result.append(entry);
+ }
+ }
+ } else {
+ result.append(entriesOnDrive);
+ }
+ }
+ return result;
+}
+
+#ifdef QT_NO_FREETYPE
+class QSymbianFontDatabaseExtrasImplementation : public QSymbianFontDatabaseExtras
+{
+public:
+ QSymbianFontDatabaseExtrasImplementation();
+ ~QSymbianFontDatabaseExtrasImplementation();
+
+ const QSymbianTypeFaceExtras *extras(const QString &typeface, bool bold, bool italic) const;
+ void removeAppFontData(QFontDatabasePrivate::ApplicationFont *fnt);
+ static inline bool appFontLimitReached();
+ TUid addFontFileToFontStore(const QFileInfo &fontFileInfo);
+ static void clear();
+
+ static inline QString tempAppFontFolder();
+ static const QString appFontMarkerPrefix;
+ static QString appFontMarker(); // 'qaf<shortUid[+shortPid]>'
+
+ struct CFontFromFontStoreReleaser {
+ static inline void cleanup(CFont *font)
+ {
+ if (!font)
+ return;
+ const QSymbianFontDatabaseExtrasImplementation *dbExtras =
+ static_cast<const QSymbianFontDatabaseExtrasImplementation*>(privateDb()->symbianExtras);
+ dbExtras->m_store->ReleaseFont(font);
+ }
+ };
+
+ struct CFontFromScreenDeviceReleaser {
+ static inline void cleanup(CFont *font)
+ {
+ if (!font)
+ return;
+ S60->screenDevice()->ReleaseFont(font);
+ }
+ };
+
+// m_heap, m_store, m_rasterizer and m_extras are used if Symbian
+// does not provide the Font Table API
+ RHeap* m_heap;
+ CFontStore *m_store;
+ COpenFontRasterizer *m_rasterizer;
+ mutable QList<const QSymbianTypeFaceExtras *> m_extras;
+
+ mutable QHash<QString, const QSymbianTypeFaceExtras *> m_extrasHash;
+ mutable QSet<QString> m_applicationFontFamilies;
+};
+
+const QString QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix =
+ QLatin1String("Q");
+
+inline QString QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
+{
+ return QDir::toNativeSeparators(QDir::tempPath()) + QLatin1Char('\\');
+}
+
+QString QSymbianFontDatabaseExtrasImplementation::appFontMarker()
+{
+ static QString result;
+ if (result.isEmpty()) {
+ quint16 id = 0;
+ if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
+ // We are allowed to load app fonts even from previous, crashed runs
+ // of this application, since we can access the font tables.
+ const quint32 uid = RProcess().Type().MostDerived().iUid;
+ id = static_cast<quint16>(uid + (uid >> 16));
+ } else {
+ // If no font table Api is available, we must not even load a font
+ // from a previous (crashed) run of this application. Reason: we
+ // won't get the font tables, they are not in the CFontStore.
+ // So, we use the pid, for more uniqueness.
+ id = static_cast<quint16>(RProcess().Id().Id());
+ }
+ result = appFontMarkerPrefix + QString::fromLatin1("%1").arg(id & 0x7fff, 3, 32, QLatin1Char('0'));
+ Q_ASSERT(appFontMarkerPrefix.length() == 1 && result.length() == 4);
+ }
+ return result;
+}
+
+static inline bool qt_symbian_fontNameHasAppFontMarker(const QString &fontName)
+{
+ const int idLength = 3; // Keep in sync with id length in appFontMarker().
+ const QString &prefix = QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix;
+ if (fontName.length() < prefix.length() + idLength
+ || fontName.mid(fontName.length() - idLength - prefix.length(), prefix.length()) != prefix)
+ return false;
+ // Testing if the the id is base32 data
+ for (int i = fontName.length() - idLength; i < fontName.length(); ++i) {
+ const QChar &c = fontName.at(i);
+ if (!(c >= QLatin1Char('0') && c <= QLatin1Char('9')
+ || c >= QLatin1Char('a') && c <= QLatin1Char('v')))
+ return false;
+ }
+ return true;
+}
+
+// If fontName is an application font of this app, prepend the app font marker
+QString qt_symbian_fontNameWithAppFontMarker(const QString &fontName)
+{
+ QFontDatabasePrivate *db = privateDb();
+ Q_ASSERT(db);
+ const QSymbianFontDatabaseExtrasImplementation *dbExtras =
+ static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
+ return dbExtras->m_applicationFontFamilies.contains(fontName) ?
+ fontName + QSymbianFontDatabaseExtrasImplementation::appFontMarker()
+ : fontName;
+}
+
+static inline QString qt_symbian_appFontNameWithoutMarker(const QString &markedFontName)
+{
+ return markedFontName.left(markedFontName.length()
+ - QSymbianFontDatabaseExtrasImplementation::appFontMarker().length());
+}
+
+QSymbianFontDatabaseExtrasImplementation::QSymbianFontDatabaseExtrasImplementation()
+{
+ if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
+ QStringList filters;
+ filters.append(QLatin1String("*.ttf"));
+ filters.append(QLatin1String("*.ccc"));
+ filters.append(QLatin1String("*.ltt"));
+ const QFileInfoList fontFiles = alternativeFilePaths(QLatin1String("resource\\Fonts"), filters);
+
+ const TInt heapMinLength = 0x1000;
+ const TInt heapMaxLength = qMax(0x20000 * fontFiles.count(), heapMinLength);
+ m_heap = User::ChunkHeap(NULL, heapMinLength, heapMaxLength);
+ QT_TRAP_THROWING(
+ m_store = CFontStore::NewL(m_heap);
+ m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E));
+ CleanupStack::PushL(m_rasterizer);
+ m_store->InstallRasterizerL(m_rasterizer);
+ CleanupStack::Pop(m_rasterizer););
+
+ foreach (const QFileInfo &fontFileInfo, fontFiles)
+ addFontFileToFontStore(fontFileInfo);
+ }
+}
+
+void QSymbianFontDatabaseExtrasImplementation::clear()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db)
+ return;
+ const QSymbianFontDatabaseExtrasImplementation *dbExtras =
+ static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
+ if (!dbExtras)
+ return; // initializeDb() has never been called
+ if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
+ qDeleteAll(dbExtras->m_extrasHash);
+ } else {
+ typedef QList<const QSymbianTypeFaceExtras *>::iterator iterator;
+ for (iterator p = dbExtras->m_extras.begin(); p != dbExtras->m_extras.end(); ++p) {
+ dbExtras->m_store->ReleaseFont((*p)->fontOwner());
+ delete *p;
+ }
+ dbExtras->m_extras.clear();
+ }
+ dbExtras->m_extrasHash.clear();
+}
+
+void qt_cleanup_symbianFontDatabase()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db)
+ return;
+
+ QSymbianFontDatabaseExtrasImplementation::clear();
+
+ if (!db->applicationFonts.isEmpty()) {
+ QFontDatabase::removeAllApplicationFonts();
+ // We remove the left over temporary font files of Qt application.
+ // Active fonts are undeletable since the font server holds a handle
+ // on them, so we do not need to worry to delete other running
+ // applications' fonts.
+ const QDir dir(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder());
+ const QStringList filter(
+ QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix + QLatin1String("*.ttf"));
+ foreach (const QFileInfo &ttfFile, dir.entryInfoList(filter))
+ QFile(ttfFile.absoluteFilePath()).remove();
+ db->applicationFonts.clear();
+ }
+}
+
+QSymbianFontDatabaseExtrasImplementation::~QSymbianFontDatabaseExtrasImplementation()
+{
+ qt_cleanup_symbianFontDatabase();
+ if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
+ delete m_store;
+ m_heap->Close();
+ }
+}
+
+#ifndef FNTSTORE_H_INLINES_SUPPORT_FMM
+/*
+ Workaround: fntstore.h has an inlined function 'COpenFont* CBitmapFont::OpenFont()'
+ that returns a private data member. The header will change between SDKs. But Qt has
+ to build on any SDK version and run on other versions of Symbian OS.
+ This function performs the needed pointer arithmetic to get the right COpenFont*
+*/
+COpenFont* OpenFontFromBitmapFont(const CBitmapFont* aBitmapFont)
+{
+ const TInt offsetIOpenFont = 92; // '_FOFF(CBitmapFont, iOpenFont)' ..if iOpenFont weren't private
+ const TUint valueIOpenFont = *(TUint*)PtrAdd(aBitmapFont, offsetIOpenFont);
+ return (valueIOpenFont & 1) ?
+ (COpenFont*)PtrAdd(aBitmapFont, valueIOpenFont & ~1) : // New behavior: iOpenFont is offset
+ (COpenFont*)valueIOpenFont; // Old behavior: iOpenFont is pointer
+}
+#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
+
+const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &aTypeface,
+ bool bold, bool italic) const
+{
+ const QString typeface = qt_symbian_fontNameWithAppFontMarker(aTypeface);
+ const QString searchKey = typeface + QString::number(int(bold)) + QString::number(int(italic));
+ if (!m_extrasHash.contains(searchKey)) {
+ TFontSpec searchSpec(qt_QString2TPtrC(typeface), 1);
+ if (bold)
+ searchSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
+ if (italic)
+ searchSpec.iFontStyle.SetPosture(EPostureItalic);
+
+ CFont* font = NULL;
+ if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
+ const TInt err = S60->screenDevice()->GetNearestFontToDesignHeightInPixels(font, searchSpec);
+ Q_ASSERT(err == KErrNone && font);
+ QScopedPointer<CFont, CFontFromScreenDeviceReleaser> sFont(font);
+ QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font);
+ sFont.take();
+ m_extrasHash.insert(searchKey, extras);
+ } else {
+ const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, searchSpec);
+ Q_ASSERT(err == KErrNone && font);
+ const CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font);
+ COpenFont *openFont =
+#ifdef FNTSTORE_H_INLINES_SUPPORT_FMM
+ bitmapFont->OpenFont();
+#else // FNTSTORE_H_INLINES_SUPPORT_FMM
+ OpenFontFromBitmapFont(bitmapFont);
+#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
+ const TOpenFontFaceAttrib* const attrib = openFont->FaceAttrib();
+ const QString foundKey =
+ QString((const QChar*)attrib->FullName().Ptr(), attrib->FullName().Length());
+ if (!m_extrasHash.contains(foundKey)) {
+ QScopedPointer<CFont, CFontFromFontStoreReleaser> sFont(font);
+ QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font, openFont);
+ sFont.take();
+ m_extras.append(extras);
+ m_extrasHash.insert(searchKey, extras);
+ m_extrasHash.insert(foundKey, extras);
+ } else {
+ m_store->ReleaseFont(font);
+ m_extrasHash.insert(searchKey, m_extrasHash.value(foundKey));
+ }
+ }
+ }
+ return m_extrasHash.value(searchKey);
+}
+
+void QSymbianFontDatabaseExtrasImplementation::removeAppFontData(
+ QFontDatabasePrivate::ApplicationFont *fnt)
+{
+ clear();
+ if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()
+ && fnt->fontStoreFontFileUid.iUid != 0)
+ m_store->RemoveFile(fnt->fontStoreFontFileUid);
+ if (!fnt->families.isEmpty())
+ m_applicationFontFamilies.remove(fnt->families.first());
+ if (fnt->screenDeviceFontFileId != 0)
+ S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId);
+ QFile::remove(fnt->temporaryFileName);
+ *fnt = QFontDatabasePrivate::ApplicationFont();
+}
+
+bool QSymbianFontDatabaseExtrasImplementation::appFontLimitReached()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db)
+ return false;
+ const int maxAppFonts = 5;
+ int registeredAppFonts = 0;
+ foreach (const QFontDatabasePrivate::ApplicationFont &appFont, db->applicationFonts)
+ if (!appFont.families.isEmpty() && ++registeredAppFonts == maxAppFonts)
+ return true;
+ return false;
+}
+
+TUid QSymbianFontDatabaseExtrasImplementation::addFontFileToFontStore(const QFileInfo &fontFileInfo)
+{
+ Q_ASSERT(!QSymbianTypeFaceExtras::symbianFontTableApiAvailable());
+ const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath());
+ const TPtrC fontFilePtr(qt_QString2TPtrC(fontFile));
+ TUid fontUid = {0};
+ TRAP_IGNORE(fontUid = m_store->AddFileL(fontFilePtr));
+ return fontUid;
+}
+
+#else // QT_NO_FREETYPE
+class QFontEngineFTS60 : public QFontEngineFT
+{
+public:
+ QFontEngineFTS60(const QFontDef &fd);
+};
+
+QFontEngineFTS60::QFontEngineFTS60(const QFontDef &fd)
+ : QFontEngineFT(fd)
+{
+ default_hint_style = HintFull;
+}
+#endif // QT_NO_FREETYPE
+
+/*
+ QFontEngineS60::pixelsToPoints, QFontEngineS60::pointsToPixels, QFontEngineMultiS60::QFontEngineMultiS60
+ and QFontEngineMultiS60::QFontEngineMultiS60 should be in qfontengine_s60.cpp. But since also the
+ Freetype based font rendering need them, they are here.
+*/
+qreal QFontEngineS60::pixelsToPoints(qreal pixels, Qt::Orientation orientation)
+{
+ CWsScreenDevice* device = S60->screenDevice();
+ return (orientation == Qt::Horizontal?
+ device->HorizontalPixelsToTwips(pixels)
+ :device->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint;
+}
+
+qreal QFontEngineS60::pointsToPixels(qreal points, Qt::Orientation orientation)
+{
+ CWsScreenDevice* device = S60->screenDevice();
+ const int twips = points * KTwipsPerPoint;
+ return orientation == Qt::Horizontal?
+ device->HorizontalTwipsToPixels(twips)
+ :device->VerticalTwipsToPixels(twips);
+}
+
+QFontEngineMultiS60::QFontEngineMultiS60(QFontEngine *first, int script, const QStringList &fallbackFamilies)
+ : QFontEngineMulti(fallbackFamilies.size() + 1)
+ , m_script(script)
+ , m_fallbackFamilies(fallbackFamilies)
+{
+ engines[0] = first;
+ first->ref.ref();
+ fontDef = engines[0]->fontDef;
+}
+
+void QFontEngineMultiS60::loadEngine(int at)
+{
+ Q_ASSERT(at < engines.size());
+ Q_ASSERT(engines.at(at) == 0);
+
+ QFontDef request = fontDef;
+ request.styleStrategy |= QFont::NoFontMerging;
+ request.family = m_fallbackFamilies.at(at-1);
+ engines[at] = QFontDatabase::findFont(m_script,
+ /*fontprivate*/0,
+ request);
+ Q_ASSERT(engines[at]);
+}
+
+#ifdef QT_NO_FREETYPE
+static bool registerScreenDeviceFont(int screenDeviceFontIndex,
+ const QSymbianFontDatabaseExtrasImplementation *dbExtras)
+{
+ TTypefaceSupport typefaceSupport;
+ S60->screenDevice()->TypefaceSupport(typefaceSupport, screenDeviceFontIndex);
+
+ QString familyName((const QChar*)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
+ if (qt_symbian_fontNameHasAppFontMarker(familyName)) {
+ const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker();
+ if (familyName.endsWith(marker)) {
+ familyName = qt_symbian_appFontNameWithoutMarker(familyName);
+ dbExtras->m_applicationFontFamilies.insert(familyName);
+ } else {
+ return false; // This was somebody else's application font. Skip it.
+ }
+ }
+
+ CFont *font; // We have to get a font instance in order to know all the details
+ TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11);
+ if (S60->screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone)
+ return false;
+ QScopedPointer<CFont, QSymbianFontDatabaseExtrasImplementation::CFontFromScreenDeviceReleaser> sFont(font);
+ if (font->TypeUid() != KCFbsFontUid)
+ return false;
+ TOpenFontFaceAttrib faceAttrib;
+ const CFbsFont *cfbsFont = static_cast<const CFbsFont *>(font);
+ cfbsFont->GetFaceAttrib(faceAttrib);
+
+ QtFontStyle::Key styleKey;
+ styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal;
+ styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal;
+
+ QtFontFamily *family = privateDb()->family(familyName, true);
+ family->fixedPitch = faceAttrib.IsMonoWidth();
+ QtFontFoundry *foundry = family->foundry(QString(), true);
+ QtFontStyle *style = foundry->style(styleKey, true);
+ style->smoothScalable = typefaceSupport.iIsScalable;
+ style->pixelSize(0, true);
+
+ const QSymbianTypeFaceExtras *typeFaceExtras =
+ dbExtras->extras(familyName, faceAttrib.IsBold(), faceAttrib.IsItalic());
+ const QByteArray os2Table = typeFaceExtras->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
+ const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData());
+ const unsigned char* ulUnicodeRange = data + 42;
+ quint32 unicodeRange[4] = {
+ qFromBigEndian<quint32>(ulUnicodeRange),
+ qFromBigEndian<quint32>(ulUnicodeRange + 4),
+ qFromBigEndian<quint32>(ulUnicodeRange + 8),
+ qFromBigEndian<quint32>(ulUnicodeRange + 12)
+ };
+ const unsigned char* ulCodePageRange = data + 78;
+ quint32 codePageRange[2] = {
+ qFromBigEndian<quint32>(ulCodePageRange),
+ qFromBigEndian<quint32>(ulCodePageRange + 4)
+ };
+ const QList<QFontDatabase::WritingSystem> writingSystems =
+ qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange);
+ foreach (const QFontDatabase::WritingSystem system, writingSystems)
+ family->writingSystems[system] = QtFontFamily::Supported;
+ return true;
+}
+#endif
+
+static void initializeDb()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if(!db || db->count)
+ return;
+
+#ifdef QT_NO_FREETYPE
+ if (!db->symbianExtras)
+ db->symbianExtras = new QSymbianFontDatabaseExtrasImplementation;
+
+ QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
+
+ const int numTypeFaces = S60->screenDevice()->NumTypefaces();
+ const QSymbianFontDatabaseExtrasImplementation *dbExtras =
+ static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
+ for (int i = 0; i < numTypeFaces; i++)
+ registerScreenDeviceFont(i, dbExtras);
+
+ // We have to clear/release all CFonts, here, in case one of the fonts is
+ // an application font of another running Qt app. Otherwise the other Qt app
+ // cannot remove it's application font, anymore -> "Zombie Font".
+ QSymbianFontDatabaseExtrasImplementation::clear();
+
+ lock.relock();
+
+#else // QT_NO_FREETYPE
+ QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation));
+ dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
+ << QLatin1String("*.ttc") << QLatin1String("*.pfa")
+ << QLatin1String("*.pfb"));
+ for (int i = 0; i < int(dir.count()); ++i) {
+ const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
+ db->addTTFile(file);
+ }
+#endif // QT_NO_FREETYPE
+}
+
+static inline void load(const QString &family = QString(), int script = -1)
+{
+ Q_UNUSED(family)
+ Q_UNUSED(script)
+ initializeDb();
+}
+
+struct OffsetTable {
+ quint32 sfntVersion;
+ quint16 numTables, searchRange, entrySelector, rangeShift;
+};
+
+struct TableRecord {
+ quint32 tag, checkSum, offset, length;
+};
+
+struct NameTableHead {
+ quint16 format, count, stringOffset;
+};
+
+struct NameRecord {
+ quint16 platformID, encodingID, languageID, nameID, length, offset;
+};
+
+static quint32 ttfCalcChecksum(const char *data, quint32 bytesCount)
+{
+ quint32 result = 0;
+ const quint32 *ptr = reinterpret_cast<const quint32*>(data);
+ const quint32 *endPtr =
+ ptr + (bytesCount + sizeof(quint32) - 1) / sizeof(quint32);
+ while (ptr < endPtr) {
+ const quint32 unit32Value = *ptr++;
+ result += qFromBigEndian(unit32Value);
+ }
+ return result;
+}
+
+static inline quint32 toDWordBoundary(quint32 value)
+{
+ return (value + 3) & ~3;
+}
+
+static inline quint32 dWordPadding(quint32 value)
+{
+ return (4 - (value & 3)) & 3;
+}
+
+static inline bool ttfMarkNameTable(QByteArray &table, const QString &marker)
+{
+ const quint32 tableLength = static_cast<quint32>(table.size());
+
+ if (tableLength > 50000 // hard limit
+ || tableLength < sizeof(NameTableHead)) // corrupt name table
+ return false;
+
+ const NameTableHead *head = reinterpret_cast<const NameTableHead*>(table.constData());
+ const quint16 count = qFromBigEndian(head->count);
+ const quint16 stringOffset = qFromBigEndian(head->stringOffset);
+ if (count > 200 // hard limit
+ || stringOffset >= tableLength // corrupt name table
+ || sizeof(NameTableHead) + count * sizeof(NameRecord) >= tableLength) // corrupt name table
+ return false;
+
+ QTextEncoder encoder(QTextCodec::codecForName("UTF-16BE"), QTextCodec::IgnoreHeader);
+ const QByteArray markerUtf16BE = encoder.fromUnicode(marker);
+ const QByteArray markerAscii = marker.toAscii();
+
+ QByteArray markedTable;
+ markedTable.reserve(tableLength + marker.length() * 20); // Original size plus some extra
+ markedTable.append(table, stringOffset);
+ QByteArray markedStrings;
+ quint32 stringDataCount = stringOffset;
+ for (quint16 i = 0; i < count; ++i) {
+ const quint32 nameRecordOffset = sizeof(NameTableHead) + sizeof(NameRecord) * i;
+ NameRecord *nameRecord =
+ reinterpret_cast<NameRecord*>(markedTable.data() + nameRecordOffset);
+ const quint16 nameID = qFromBigEndian(nameRecord->nameID);
+ const quint16 platformID = qFromBigEndian(nameRecord->platformID);
+ const quint16 encodingID = qFromBigEndian(nameRecord->encodingID);
+ const quint16 offset = qFromBigEndian(nameRecord->offset);
+ const quint16 length = qFromBigEndian(nameRecord->length);
+ stringDataCount += length;
+ if (stringDataCount > 80000 // hard limit. String data may be > name table size. Multiple records can reference the same string.
+ || static_cast<quint32>(stringOffset + offset + length) > tableLength) // String outside bounds
+ return false;
+ const bool needsMarker =
+ nameID == 1 || nameID == 3 || nameID == 4 || nameID == 16 || nameID == 21;
+ const bool isUnicode =
+ platformID == 0 || platformID == 3 && encodingID == 1;
+ const QByteArray originalString =
+ QByteArray::fromRawData(table.constData() + stringOffset + offset, length);
+ QByteArray markedString;
+ if (needsMarker) {
+ const int maxBytesLength = (KMaxTypefaceNameLength - marker.length()) * (isUnicode ? 2 : 1);
+ markedString = originalString.left(maxBytesLength) + (isUnicode ? markerUtf16BE : markerAscii);
+ } else {
+ markedString = originalString;
+ }
+ nameRecord->offset = qToBigEndian(static_cast<quint16>(markedStrings.length()));
+ nameRecord->length = qToBigEndian(static_cast<quint16>(markedString.length()));
+ markedStrings.append(markedString);
+ }
+ markedTable.append(markedStrings);
+ table = markedTable;
+ return true;
+}
+
+const quint32 ttfMaxFileSize = 3500000;
+
+static inline bool ttfMarkAppFont(QByteArray &ttf, const QString &marker)
+{
+ const quint32 ttfChecksumNumber = 0xb1b0afba;
+ const quint32 alignment = 4;
+ const quint32 ttfLength = static_cast<quint32>(ttf.size());
+ if (ttfLength > ttfMaxFileSize // hard limit
+ || ttfLength % alignment != 0 // ttf sizes are always factors of 4
+ || ttfLength <= sizeof(OffsetTable) // ttf too short
+ || ttfCalcChecksum(ttf.constData(), ttf.size()) != ttfChecksumNumber) // ttf checksum is invalid
+ return false;
+
+ const OffsetTable *offsetTable = reinterpret_cast<const OffsetTable*>(ttf.constData());
+ const quint16 numTables = qFromBigEndian(offsetTable->numTables);
+ const quint32 recordsLength =
+ toDWordBoundary(sizeof(OffsetTable) + numTables * sizeof(TableRecord));
+ if (numTables > 30 // hard limit
+ || recordsLength + numTables * alignment > ttfLength) // Corrupt ttf. Tables would not fit, even if empty.
+ return false;
+
+ QByteArray markedTtf;
+ markedTtf.reserve(ttfLength + marker.length() * 20); // Original size plus some extra
+ markedTtf.append(ttf.constData(), recordsLength);
+
+ const quint32 ttfCheckSumAdjustmentOffset = 8; // Offset from the start of 'head'
+ int indexOfHeadTable = -1;
+ quint32 ttfDataSize = recordsLength;
+ typedef QPair<quint32, quint32> Range;
+ QList<Range> memoryRanges;
+ memoryRanges.reserve(numTables);
+ for (int i = 0; i < numTables; ++i) {
+ TableRecord *tableRecord =
+ reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord));
+ const quint32 offset = qFromBigEndian(tableRecord->offset);
+ const quint32 length = qFromBigEndian(tableRecord->length);
+ const quint32 lengthAligned = toDWordBoundary(length);
+ ttfDataSize += lengthAligned;
+ if (offset < recordsLength // must not intersect ttf header/records
+ || offset % alignment != 0 // must be aligned
+ || offset > ttfLength - alignment // table out of bounds
+ || offset + lengthAligned > ttfLength // table out of bounds
+ || ttfDataSize > ttfLength) // tables would not fit into the ttf
+ return false;
+
+ foreach (const Range &range, memoryRanges)
+ if (offset < range.first + range.second && offset + lengthAligned > range.first)
+ return false; // Overlaps with another table
+ memoryRanges.append(Range(offset, lengthAligned));
+
+ quint32 checkSum = qFromBigEndian(tableRecord->checkSum);
+ if (tableRecord->tag == qToBigEndian(static_cast<quint32>('head'))) {
+ if (length < ttfCheckSumAdjustmentOffset + sizeof(quint32))
+ return false; // Invalid 'head' table
+ const quint32 *checkSumAdjustmentTag =
+ reinterpret_cast<const quint32*>(ttf.constData() + offset + ttfCheckSumAdjustmentOffset);
+ const quint32 checkSumAdjustment = qFromBigEndian(*checkSumAdjustmentTag);
+ checkSum += checkSumAdjustment;
+ indexOfHeadTable = i; // For the ttf checksum re-calculation, later
+ }
+ if (checkSum != ttfCalcChecksum(ttf.constData() + offset, length))
+ return false; // Table checksum is invalid
+
+ bool updateTableChecksum = false;
+ QByteArray table;
+ if (tableRecord->tag == qToBigEndian(static_cast<quint32>('name'))) {
+ table = QByteArray(ttf.constData() + offset, length);
+ if (!ttfMarkNameTable(table, marker))
+ return false; // Name table was not markable.
+ updateTableChecksum = true;
+ } else {
+ table = QByteArray::fromRawData(ttf.constData() + offset, length);
+ }
+
+ tableRecord->offset = qToBigEndian(markedTtf.size());
+ tableRecord->length = qToBigEndian(table.size());
+ markedTtf.append(table);
+ markedTtf.append(QByteArray(dWordPadding(table.size()), 0)); // 0-padding
+ if (updateTableChecksum) {
+ TableRecord *tableRecord = // Need to recalculate, since markedTtf changed
+ reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord));
+ const quint32 offset = qFromBigEndian(tableRecord->offset);
+ const quint32 length = qFromBigEndian(tableRecord->length);
+ tableRecord->checkSum = qToBigEndian(ttfCalcChecksum(markedTtf.constData() + offset, length));
+ }
+ }
+ if (indexOfHeadTable == -1 // 'head' table is mandatory
+ || ttfDataSize != ttfLength) // We do not allow ttf data "holes". Neither does Symbian.
+ return false;
+ TableRecord *headRecord =
+ reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + indexOfHeadTable * sizeof(TableRecord));
+ quint32 *checkSumAdjustmentTag =
+ reinterpret_cast<quint32*>(markedTtf.data() + qFromBigEndian(headRecord->offset) + ttfCheckSumAdjustmentOffset);
+ *checkSumAdjustmentTag = 0;
+ const quint32 ttfChecksum = ttfCalcChecksum(markedTtf.constData(), markedTtf.count());
+ *checkSumAdjustmentTag = qToBigEndian(ttfChecksumNumber - ttfChecksum);
+ ttf = markedTtf;
+ return true;
+}
+
+static inline bool ttfCanSymbianLoadFont(const QByteArray &data, const QString &fileName)
+{
+ bool result = false;
+ QString ttfFileName;
+ QFile tempFileGuard;
+ QFileInfo info(fileName);
+ if (!data.isEmpty()) {
+ QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
+ + QSymbianFontDatabaseExtrasImplementation::appFontMarker()
+ + QLatin1String("XXXXXX.ttf"));
+ if (!tempfile.open() || tempfile.write(data) == -1)
+ return false;
+ ttfFileName = QDir::toNativeSeparators(QFileInfo(tempfile).canonicalFilePath());
+ tempfile.setAutoRemove(false);
+ tempfile.close();
+ tempFileGuard.setFileName(ttfFileName);
+ if (!tempFileGuard.open(QIODevice::ReadOnly))
+ return false;
+ } else if (info.isFile()) {
+ ttfFileName = QDir::toNativeSeparators(info.canonicalFilePath());
+ } else {
+ return false;
+ }
+
+ CFontStore *store = 0;
+ RHeap* heap = User::ChunkHeap(NULL, 0x1000, 0x20000);
+ if (heap) {
+ QT_TRAP_THROWING(
+ CleanupClosePushL(*heap);
+ store = CFontStore::NewL(heap);
+ CleanupStack::PushL(store);
+ COpenFontRasterizer *rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E));
+ CleanupStack::PushL(rasterizer);
+ store->InstallRasterizerL(rasterizer);
+ CleanupStack::Pop(rasterizer);
+ TUid fontUid = {-1};
+ TRAP_IGNORE(fontUid = store->AddFileL(qt_QString2TPtrC(ttfFileName)));
+ if (fontUid.iUid != -1)
+ result = true;
+ CleanupStack::PopAndDestroy(2, heap); // heap, store
+ );
+ }
+
+ if (tempFileGuard.isOpen())
+ tempFileGuard.remove();
+
+ return result;
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
+{
+ if (QSymbianFontDatabaseExtrasImplementation::appFontLimitReached()
+ || fnt->data.size() > ttfMaxFileSize // hard limit
+ || fnt->data.isEmpty() && (!fnt->fileName.endsWith(QLatin1String(".ttf"), Qt::CaseInsensitive) // Only buffer or .ttf
+ || QFileInfo(fnt->fileName).size() > ttfMaxFileSize)) // hard limit
+ return;
+
+// Using ttfCanSymbianLoadFont() causes crashes on app destruction (Symbian^3|PR1 and lower).
+// Therefore, not using it for now, but eventually in a later version.
+// if (!ttfCanSymbianLoadFont(fnt->data, fnt->fileName))
+// return;
+
+ QFontDatabasePrivate *db = privateDb();
+ if (!db)
+ return;
+
+ if (!db->count)
+ initializeDb();
+
+ QSymbianFontDatabaseExtrasImplementation *dbExtras =
+ static_cast<QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
+ if (!dbExtras)
+ return;
+
+ const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker();
+
+ // The QTemporaryFile object being used in the following section must be
+ // destructed before letting Symbian load the TTF file. Symbian would not
+ // load it otherwise, because QTemporaryFile will still keep some handle
+ // on it. The scope is used to reduce the life time of the QTemporaryFile.
+ // In order to prevent other processes from modifying the file between the
+ // moment where the QTemporaryFile is destructed and the file is loaded by
+ // Symbian, we have a QFile "tempFileGuard" outside the scope which opens
+ // the file in ReadOnly mode while the QTemporaryFile is still alive.
+ QFile tempFileGuard;
+ {
+ QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
+ + marker + QLatin1String("XXXXXX.ttf"));
+ if (!tempfile.open())
+ return;
+ const QString tempFileName = QFileInfo(tempfile).canonicalFilePath();
+ if (fnt->data.isEmpty()) {
+ QFile sourceFile(fnt->fileName);
+ if (!sourceFile.open(QIODevice::ReadOnly))
+ return;
+ fnt->data = sourceFile.readAll();
+ }
+ if (!ttfMarkAppFont(fnt->data, marker) || tempfile.write(fnt->data) == -1)
+ return;
+ tempfile.setAutoRemove(false);
+ tempfile.close(); // Tempfile still keeps a file handle, forbidding write access
+ fnt->data.clear(); // The TTF data was marked and saved. Not needed in memory, anymore.
+ tempFileGuard.setFileName(tempFileName);
+ if (!tempFileGuard.open(QIODevice::ReadOnly))
+ return;
+ fnt->temporaryFileName = tempFileName;
+ }
+
+ const QString fullFileName = QDir::toNativeSeparators(fnt->temporaryFileName);
+ QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
+ const QStringList fontsOnServerBefore = qt_symbian_fontFamiliesOnFontServer();
+ const TInt err =
+ S60->screenDevice()->AddFile(qt_QString2TPtrC(fullFileName), fnt->screenDeviceFontFileId);
+ tempFileGuard.close(); // Did its job
+ const QStringList fontsOnServerAfter = qt_symbian_fontFamiliesOnFontServer();
+ if (err == KErrNone && fontsOnServerBefore.count() < fontsOnServerAfter.count()) { // Added to screen device?
+ int fontOnServerIndex = fontsOnServerAfter.count() - 1;
+ for (int i = 0; i < fontsOnServerBefore.count(); i++) {
+ if (fontsOnServerBefore.at(i) != fontsOnServerAfter.at(i)) {
+ fontOnServerIndex = i;
+ break;
+ }
+ }
+
+ // Must remove all font engines with their CFonts, first.
+ QFontCache::instance()->clear();
+ db->free();
+ QSymbianFontDatabaseExtrasImplementation::clear();
+
+ if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable())
+ fnt->fontStoreFontFileUid = dbExtras->addFontFileToFontStore(QFileInfo(fullFileName));
+
+ const QString &appFontName = fontsOnServerAfter.at(fontOnServerIndex);
+ fnt->families.append(qt_symbian_appFontNameWithoutMarker(appFontName));
+ if (!qt_symbian_fontNameHasAppFontMarker(appFontName)
+ || !registerScreenDeviceFont(fontOnServerIndex, dbExtras))
+ dbExtras->removeAppFontData(fnt);
+ } else {
+ if (fnt->screenDeviceFontFileId > 0)
+ S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId); // May still have the file open!
+ QFile::remove(fnt->temporaryFileName);
+ *fnt = QFontDatabasePrivate::ApplicationFont();
+ }
+ lock.relock();
+}
+
+bool QFontDatabase::removeApplicationFont(int handle)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ if (!db || handle < 0 || handle >= db->applicationFonts.count())
+ return false;
+ QSymbianFontDatabaseExtrasImplementation *dbExtras =
+ static_cast<QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
+ if (!dbExtras)
+ return false;
+
+ QFontDatabasePrivate::ApplicationFont *fnt = &db->applicationFonts[handle];
+ if (fnt->families.isEmpty())
+ return true; // Nothing to remove. Return peacefully.
+
+ // Must remove all font engines with their CFonts, first
+ QFontCache::instance()->clear();
+ db->free();
+ dbExtras->removeAppFontData(fnt);
+
+ db->invalidate(); // This will just emit 'fontDatabaseChanged()'
+ return true;
+}
+
+bool QFontDatabase::removeAllApplicationFonts()
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ const int applicationFontsCount = privateDb()->applicationFonts.count();
+ for (int i = 0; i < applicationFontsCount; ++i)
+ if (!removeApplicationFont(i))
+ return false;
+ return true;
+}
+
+bool QFontDatabase::supportsThreadedFontRendering()
+{
+ return false;
+}
+
+static
+QFontDef cleanedFontDef(const QFontDef &req)
+{
+ QFontDef result = req;
+ if (result.pixelSize <= 0) {
+ result.pixelSize = QFontEngineS60::pointsToPixels(qMax(qreal(1.0), result.pointSize));
+ result.pointSize = 0;
+ }
+ return result;
+}
+
+QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *d, const QFontDef &req)
+{
+ const QFontCache::Key key(cleanedFontDef(req), script);
+
+ if (!privateDb()->count)
+ initializeDb();
+
+ QFontEngine *fe = QFontCache::instance()->findEngine(key);
+ if (!fe) {
+ // Making sure that fe->fontDef.family will be an existing font.
+ initializeDb();
+ QFontDatabasePrivate *db = privateDb();
+ QtFontDesc desc;
+ QList<int> blacklistedFamilies;
+ match(script, key.def, key.def.family, QString(), -1, &desc, blacklistedFamilies);
+ if (!desc.family) // falling back to application font
+ desc.family = db->family(QApplication::font().defaultFamily());
+ Q_ASSERT(desc.family);
+
+ // Making sure that desc.family supports the requested script
+ QtFontDesc mappedDesc;
+ bool supportsScript = false;
+ do {
+ match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
+ if (mappedDesc.family == desc.family) {
+ supportsScript = true;
+ break;
+ }
+ blacklistedFamilies.append(mappedDesc.familyIndex);
+ } while (mappedDesc.family);
+ if (!supportsScript) {
+ blacklistedFamilies.clear();
+ match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies);
+ if (mappedDesc.family)
+ desc = mappedDesc;
+ }
+
+ const QString fontFamily = desc.family->name;
+ QFontDef request = req;
+ request.family = fontFamily;
+#ifdef QT_NO_FREETYPE
+ const QSymbianFontDatabaseExtrasImplementation *dbExtras =
+ static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
+ const QSymbianTypeFaceExtras *typeFaceExtras =
+ dbExtras->extras(fontFamily, request.weight > QFont::Normal, request.style != QFont::StyleNormal);
+
+ // We need a valid pixelSize, e.g. for lineThickness()
+ if (request.pixelSize < 0)
+ request.pixelSize = request.pointSize * d->dpi / 72;
+
+ fe = new QFontEngineS60(request, typeFaceExtras);
+#else // QT_NO_FREETYPE
+ Q_UNUSED(d)
+ QFontEngine::FaceId faceId;
+ const QtFontFamily * const reqQtFontFamily = db->family(fontFamily);
+ faceId.filename = reqQtFontFamily->fontFilename;
+ faceId.index = reqQtFontFamily->fontFileIndex;
+
+ QFontEngineFTS60 *fte = new QFontEngineFTS60(cleanedFontDef(request));
+ if (fte->init(faceId, true, QFontEngineFT::Format_A8))
+ fe = fte;
+ else
+ delete fte;
+#endif // QT_NO_FREETYPE
+
+ Q_ASSERT(fe);
+ if (script == QUnicodeTables::Common
+ && !(req.styleStrategy & QFont::NoFontMerging)
+ && !fe->symbol) {
+
+ QStringList commonFonts;
+ for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
+ if (scriptForWritingSystem[ws] != script)
+ continue;
+ for (int i = 0; i < db->count; ++i) {
+ if (db->families[i]->writingSystems[ws] & QtFontFamily::Supported)
+ commonFonts.append(db->families[i]->name);
+ }
+ }
+
+ // Hack: Prioritize .ccc fonts
+ const QString niceEastAsianFont(QLatin1String("Sans MT 936_S60"));
+ if (commonFonts.removeAll(niceEastAsianFont) > 0)
+ commonFonts.prepend(niceEastAsianFont);
+
+ fe = new QFontEngineMultiS60(fe, script, commonFonts);
+ }
+ }
+ fe->ref.ref();
+ QFontCache::instance()->insertEngine(key, fe);
+ return fe;
+}
+
+void QFontDatabase::load(const QFontPrivate *d, int script)
+{
+ QFontEngine *fe = 0;
+ QFontDef req = d->request;
+
+ if (!d->engineData) {
+ const QFontCache::Key key(cleanedFontDef(req), script);
+ getEngineData(d, key);
+ }
+
+ // the cached engineData could have already loaded the engine we want
+ if (d->engineData->engines[script])
+ fe = d->engineData->engines[script];
+
+ if (!fe) {
+ if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
+ fe = new QTestFontEngine(req.pixelSize);
+ fe->fontDef = req;
+ } else {
+ fe = findFont(script, d, req);
+ }
+ d->engineData->engines[script] = fe;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qfontdatabase_win.cpp b/src/gui/text/qfontdatabase_win.cpp
new file mode 100644
index 0000000000..05b7509bf6
--- /dev/null
+++ b/src/gui/text/qfontdatabase_win.cpp
@@ -0,0 +1,1348 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qt_windows.h"
+#include <qmath.h>
+#include <private/qapplication_p.h>
+#include "qfont_p.h"
+#include "qfontengine_p.h"
+#include "qpaintdevice.h"
+#include <private/qsystemlibrary_p.h>
+#include "qabstractfileengine.h"
+#include "qendian.h"
+
+#if !defined(QT_NO_DIRECTWRITE)
+# include "qsettings.h"
+# include "qfontenginedirectwrite_p.h"
+#endif
+
+#ifdef Q_OS_WINCE
+# include <QTemporaryFile>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern HDC shared_dc(); // common dc for all fonts
+
+#ifdef MAKE_TAG
+#undef MAKE_TAG
+#endif
+// GetFontData expects the tags in little endian ;(
+#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
+ (((quint32)(ch4)) << 24) | \
+ (((quint32)(ch3)) << 16) | \
+ (((quint32)(ch2)) << 8) | \
+ ((quint32)(ch1)) \
+ )
+
+static HFONT stock_sysfont = 0;
+
+static bool localizedName(const QString &name)
+{
+ const QChar *c = name.unicode();
+ for(int i = 0; i < name.length(); ++i) {
+ if(c[i].unicode() >= 0x100)
+ return true;
+ }
+ return false;
+}
+
+static inline quint16 getUShort(const unsigned char *p)
+{
+ quint16 val;
+ val = *p++ << 8;
+ val |= *p;
+
+ return val;
+}
+
+static QString getEnglishName(const uchar *table, quint32 bytes)
+{
+ QString i18n_name;
+ enum {
+ NameRecordSize = 12,
+ FamilyId = 1,
+ MS_LangIdEnglish = 0x009
+ };
+
+ // get the name table
+ quint16 count;
+ quint16 string_offset;
+ const unsigned char *names;
+
+ int microsoft_id = -1;
+ int apple_id = -1;
+ int unicode_id = -1;
+
+ if(getUShort(table) != 0)
+ goto error;
+
+ count = getUShort(table+2);
+ string_offset = getUShort(table+4);
+ names = table + 6;
+
+ if(string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
+ goto error;
+
+ for(int i = 0; i < count; ++i) {
+ // search for the correct name entry
+
+ quint16 platform_id = getUShort(names + i*NameRecordSize);
+ quint16 encoding_id = getUShort(names + 2 + i*NameRecordSize);
+ quint16 language_id = getUShort(names + 4 + i*NameRecordSize);
+ quint16 name_id = getUShort(names + 6 + i*NameRecordSize);
+
+ if(name_id != FamilyId)
+ continue;
+
+ enum {
+ PlatformId_Unicode = 0,
+ PlatformId_Apple = 1,
+ PlatformId_Microsoft = 3
+ };
+
+ quint16 length = getUShort(names + 8 + i*NameRecordSize);
+ quint16 offset = getUShort(names + 10 + i*NameRecordSize);
+ if(DWORD(string_offset + offset + length) >= bytes)
+ continue;
+
+ if ((platform_id == PlatformId_Microsoft
+ && (encoding_id == 0 || encoding_id == 1))
+ && (language_id & 0x3ff) == MS_LangIdEnglish
+ && microsoft_id == -1)
+ microsoft_id = i;
+ // not sure if encoding id 4 for Unicode is utf16 or ucs4...
+ else if(platform_id == PlatformId_Unicode && encoding_id < 4 && unicode_id == -1)
+ unicode_id = i;
+ else if(platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0)
+ apple_id = i;
+ }
+ {
+ bool unicode = false;
+ int id = -1;
+ if(microsoft_id != -1) {
+ id = microsoft_id;
+ unicode = true;
+ } else if(apple_id != -1) {
+ id = apple_id;
+ unicode = false;
+ } else if (unicode_id != -1) {
+ id = unicode_id;
+ unicode = true;
+ }
+ if(id != -1) {
+ quint16 length = getUShort(names + 8 + id*NameRecordSize);
+ quint16 offset = getUShort(names + 10 + id*NameRecordSize);
+ if(unicode) {
+ // utf16
+
+ length /= 2;
+ i18n_name.resize(length);
+ QChar *uc = (QChar *) i18n_name.unicode();
+ const unsigned char *string = table + string_offset + offset;
+ for(int i = 0; i < length; ++i)
+ uc[i] = getUShort(string + 2*i);
+ } else {
+ // Apple Roman
+
+ i18n_name.resize(length);
+ QChar *uc = (QChar *) i18n_name.unicode();
+ const unsigned char *string = table + string_offset + offset;
+ for(int i = 0; i < length; ++i)
+ uc[i] = QLatin1Char(string[i]);
+ }
+ }
+ }
+ error:
+ //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
+ return i18n_name;
+}
+
+static QString getEnglishName(const QString &familyName)
+{
+ QString i18n_name;
+
+ HDC hdc = GetDC( 0 );
+ LOGFONT lf;
+ memset(&lf, 0, sizeof(LOGFONT));
+ memcpy(lf.lfFaceName, familyName.utf16(), qMin(LF_FACESIZE, familyName.length()) * sizeof(wchar_t));
+ lf.lfCharSet = DEFAULT_CHARSET;
+ HFONT hfont = CreateFontIndirect(&lf);
+
+ if(!hfont) {
+ ReleaseDC(0, hdc);
+ return QString();
+ }
+
+ HGDIOBJ oldobj = SelectObject( hdc, hfont );
+
+ const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
+
+ // get the name table
+ unsigned char *table = 0;
+
+ DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
+ if ( bytes == GDI_ERROR ) {
+ // ### Unused variable
+ /* int err = GetLastError(); */
+ goto error;
+ }
+
+ table = new unsigned char[bytes];
+ GetFontData(hdc, name_tag, 0, table, bytes);
+ if ( bytes == GDI_ERROR )
+ goto error;
+
+ i18n_name = getEnglishName(table, bytes);
+error:
+ delete [] table;
+ SelectObject( hdc, oldobj );
+ DeleteObject( hfont );
+ ReleaseDC( 0, hdc );
+
+ //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
+ return i18n_name;
+}
+
+extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
+
+stati