summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Rossi <pierre.rossi@nokia.com>2012-01-16 17:40:21 +0100
committerQt by Nokia <qt-info@nokia.com>2012-03-01 15:47:24 +0100
commitcc78f47778de0feda95d7a85440d03ad7dcf40bd (patch)
tree9dd229f840ae887d2199bdf937a9371a8bfbfab7
parent10ac80708555cd0cca181e637d3a95c80826ec69 (diff)
Allow using multi fontengine in QTextLayout with QRawFont.
This change enables us to instantiate a QFontEngineMulti that takes the raw font's font engine as its primary engine but can use fallback engines based on the platform. Since this can be quite expensive, we defer the query for fallback families' names until it's needed and we cache the resulting multi font engine. Change-Id: I390dbc1cb2fe61d56867f29a03f313eb3eb49dc3 Reviewed-by: Simon Hausmann <simon.hausmann@nokia.com>
-rw-r--r--src/gui/text/qfont.cpp27
-rw-r--r--src/gui/text/qfont_p.h5
-rw-r--r--src/gui/text/qfontdatabase.h1
-rw-r--r--src/gui/text/qfontengine_p.h2
-rw-r--r--src/gui/text/qfontengine_qpa.cpp85
-rw-r--r--src/gui/text/qfontengine_qpa_p.h5
-rw-r--r--src/gui/text/qtextengine.cpp5
7 files changed, 108 insertions, 22 deletions
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index ee833a06cf..3515c7dc3c 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -2715,18 +2715,22 @@ 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;
+ updateHitCountAndTimeStamp(it.value());
+
+ return it.value().data;
+}
+
+void QFontCache::updateHitCountAndTimeStamp(Engine &value)
+{
+ value.hits++;
+ 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,
- it.value().data->ref.load(), it.value().data->cache_count,
- it.value().data->name());
-
- return it.value().data;
+ value.data, value.timestamp, value.hits,
+ value.data->ref.load(), value.data->cache_count,
+ value.data->name());
}
void QFontCache::removeEngine(QFontEngine *engine)
@@ -2743,14 +2747,17 @@ void QFontCache::removeEngine(QFontEngine *engine)
}
}
-void QFontCache::insertEngine(const Key &key, QFontEngine *engine)
+void QFontCache::insertEngine(const Key &key, QFontEngine *engine, bool insertMulti)
{
FC_DEBUG("QFontCache: inserting new engine %p", engine);
Engine data(engine);
data.timestamp = ++current_timestamp;
- engineCache.insert(key, data);
+ if (insertMulti)
+ engineCache.insertMulti(key, data);
+ else
+ engineCache.insert(key, data);
// only increase the cost if this is the first time we insert the engine
if (engine->cache_count == 0)
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index d10249201a..06cf787880 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -242,9 +242,10 @@ public:
EngineCache engineCache;
QFontEngine *findEngine(const Key &key);
- void insertEngine(const Key &key, QFontEngine *engine);
- void removeEngine(QFontEngine *engine);
+ void updateHitCountAndTimeStamp(Engine &value);
+ void insertEngine(const Key &key, QFontEngine *engine, bool insertMulti = false);
+ void removeEngine(QFontEngine *engine);
private:
void increaseCost(uint cost);
diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h
index b5697990f8..b30f7da48d 100644
--- a/src/gui/text/qfontdatabase.h
+++ b/src/gui/text/qfontdatabase.h
@@ -162,7 +162,6 @@ private:
friend class QFontEngineMultiXLFD;
friend class QFontEngineMultiQWS;
friend class QFontEngineMultiQPA;
- friend class QTextEngine;
#ifdef QT_BUILD_INTERNAL
friend class ::tst_QFont;
#endif
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 023882d560..fed135ea87 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -85,6 +85,7 @@ struct QGlyphLayout;
class Q_GUI_EXPORT QFontEngine : public QObject
{
+ Q_OBJECT
public:
enum Type {
Box,
@@ -344,6 +345,7 @@ private:
class Q_GUI_EXPORT QFontEngineMulti : public QFontEngine
{
+ Q_OBJECT
public:
explicit QFontEngineMulti(int engineCount);
~QFontEngineMulti();
diff --git a/src/gui/text/qfontengine_qpa.cpp b/src/gui/text/qfontengine_qpa.cpp
index 33657367fa..48679824a4 100644
--- a/src/gui/text/qfontengine_qpa.cpp
+++ b/src/gui/text/qfontengine_qpa.cpp
@@ -46,8 +46,10 @@
#include <QtCore/QDir>
#include <QtCore/QBuffer>
-#include <QtGui/QPlatformFontDatabase>
#include <QtGui/private/qpaintengine_raster_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/QPlatformFontDatabase>
+#include <QtGui/QPlatformIntegration>
QT_BEGIN_NAMESPACE
@@ -662,6 +664,20 @@ void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value
QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks)
: QFontEngineMulti(fallbacks.size() + 1),
fallbackFamilies(fallbacks), script(_script)
+ , fallbacksQueried(true)
+{
+ init(fe);
+}
+
+QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script)
+ : QFontEngineMulti(2)
+ , script(_script)
+ , fallbacksQueried(false)
+{
+ init(fe);
+}
+
+void QFontEngineMultiQPA::init(QFontEngine *fe)
{
Q_ASSERT(fe && fe->type() != QFontEngine::Multi);
engines[0] = fe;
@@ -672,18 +688,73 @@ QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QSt
void QFontEngineMultiQPA::loadEngine(int at)
{
+ bool canLoadFallbackEngine = true;
+ if (!fallbacksQueried) {
+ // Original FontEngine to restore after the fill.
+ QFontEngine *fe = engines[0];
+ fallbackFamilies = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fallbacksForFamily(fe->fontDef.family, QFont::Style(fe->fontDef.style)
+ , QFont::AnyStyle, QUnicodeTables::Script(script));
+ if (fallbackFamilies.size() > 1) {
+ engines.fill(0, fallbackFamilies.size() + 1);
+ engines[0] = fe;
+ } else {
+ // Turns out we lied about having any fallback at all.
+ canLoadFallbackEngine = false;
+ engines[1] = fe;
+ }
+ fallbacksQueried = true;
+ }
Q_ASSERT(at < engines.size());
Q_ASSERT(engines.at(at) == 0);
-
QFontDef request = fontDef;
- request.styleStrategy |= QFont::NoFontMerging;
- request.family = fallbackFamilies.at(at-1);
- engines[at] = QFontDatabase::findFont(script,
- /*fontprivate*/0,
- request, false);
+ if (canLoadFallbackEngine) {
+ request.styleStrategy |= QFont::NoFontMerging;
+ request.family = fallbackFamilies.at(at-1);
+ engines[at] = QFontDatabase::findFont(script,
+ /*fontprivate = */0,
+ request, /*multi = */false);
+ }
Q_ASSERT(engines[at]);
engines[at]->ref.ref();
engines[at]->fontDef = request;
}
+/*
+ This is used indirectly by QtWebKit when using QTextLayout::setRawFont
+
+ The purpose of this is to provide the necessary font fallbacks when drawing complex
+ text. Since QtWebKit ends up repeatedly creating QTextLayout instances and passing them
+ the same raw font over and over again, we want to cache the corresponding multi font engine
+ as it may contain fallback font engines already.
+*/
+QFontEngine* QFontEngineMultiQPA::createMultiFontEngine(QFontEngine *fe, int script)
+{
+ QFontEngine *engine = 0;
+ QFontCache::Key key(fe->fontDef, script, /*multi = */true);
+ QFontCache *fc = QFontCache::instance();
+ // We can't rely on the fontDef (and hence the cache Key)
+ // alone to distinguish webfonts, since these should not be
+ // accidentally shared, even if the resulting fontcache key
+ // is strictly identical. See:
+ // http://www.w3.org/TR/css3-fonts/#font-face-rule
+ const bool faceIsLocal = !fe->faceId().filename.isEmpty();
+ QFontCache::EngineCache::Iterator it = fc->engineCache.find(key),
+ end = fc->engineCache.end();
+ while (it != end && it.key() == key) {
+ QFontEngineMulti *cachedEngine = qobject_cast<QFontEngineMulti *>(it.value().data);
+ if (faceIsLocal || (cachedEngine && fe == cachedEngine->engine(0))) {
+ engine = cachedEngine;
+ fc->updateHitCountAndTimeStamp(it.value());
+ break;
+ }
+ it++;
+ }
+ if (!engine) {
+ engine = new QFontEngineMultiQPA(fe, script);
+ QFontCache::instance()->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);
+ }
+ Q_ASSERT(engine);
+ return engine;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/text/qfontengine_qpa_p.h b/src/gui/text/qfontengine_qpa_p.h
index ed2e071ac2..16991ad2ca 100644
--- a/src/gui/text/qfontengine_qpa_p.h
+++ b/src/gui/text/qfontengine_qpa_p.h
@@ -249,13 +249,18 @@ public:
QFontEngineMultiQPA(QFontEngine *fe, int script, const QStringList &fallbacks);
void loadEngine(int at);
+ static QFontEngine* createMultiFontEngine(QFontEngine *fe, int script);
int fallbackFamilyCount() const { return fallbackFamilies.size(); }
QString fallbackFamilyAt(int at) const { return fallbackFamilies.at(at); }
private:
+ QFontEngineMultiQPA(QFontEngine *fe, int script);
+ void init(QFontEngine *fe);
+
QStringList fallbackFamilies;
int script;
+ bool fallbacksQueried;
};
QT_END_NAMESPACE
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index a95e61342d..0460db14d5 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -59,6 +59,7 @@
#include <qinputmethod.h>
#include <stdlib.h>
+#include "qfontengine_qpa_p.h"
QT_BEGIN_NAMESPACE
@@ -1708,7 +1709,7 @@ QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFix
if (feCache.prevFontEngine && feCache.prevFontEngine->type() == QFontEngine::Multi && feCache.prevScript == script) {
engine = feCache.prevFontEngine;
} else {
- engine = QFontDatabase::findFont(script, /*fontPrivate*/0, rawFont.d->fontEngine->fontDef, true);
+ engine = QFontEngineMultiQPA::createMultiFontEngine(rawFont.d->fontEngine, script);
feCache.prevFontEngine = engine;
feCache.prevScript = script;
engine->ref.ref();
@@ -1720,7 +1721,7 @@ QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFix
scaledEngine = feCache.prevScaledFontEngine;
} else {
QFontEngine *scEngine = rawFont.d->fontEngine->cloneWithSize(smallCapsFraction * rawFont.pixelSize());
- scaledEngine = QFontDatabase::findFont(script, /*fontPrivate*/0, scEngine->fontDef, true);
+ scaledEngine = QFontEngineMultiQPA::createMultiFontEngine(scEngine, script);
scaledEngine->ref.ref();
feCache.prevScaledFontEngine = scaledEngine;
}