summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>2012-02-15 15:06:00 +0100
committerQt by Nokia <qt-info@nokia.com>2012-02-17 05:26:34 +0100
commit2801db558c56e98753e297c1aeabd4fd2975e09a (patch)
tree14726483adef27b2e19f67ee0a4a0d2ef1a577a9 /src
parent4212898822f1798dac0167e4f6a147bd8a3b3dcc (diff)
Avoid loading and keeping unused fallback font engines
When we request glyphs from fallback fonts, we would potentially load all fonts on the system into memory. This is especially true for glyphs that are not supported by any font (or by the last in the list) in any "Common" script (which e.g. includes CJK). This would make any application which tried to display unsupported glyphs use huge amounts of memory for keeping unused fonts cached, only limited by the number of fonts on the system. The patch contains two solutions: First, before loading the font, the multi font engine will be asked whether it needs to be tried for the given character. By default, this will always be true, so all fonts will be tried, but with the new font config multi engine in the platform plugin, it will ask FontConfig whether the font contains a glyph for the character. Should the font be loaded and still fail to resolve the character (which could be the case for other platforms), we will simply delete it again immediately instead keeping it cached. Change-Id: I92dfb39289a359f49caa02c2caf8baf66098fb59 Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/gui/text/qfont.cpp14
-rw-r--r--src/gui/text/qfont_p.h1
-rw-r--r--src/gui/text/qfontdatabase_qpa.cpp3
-rw-r--r--src/gui/text/qfontengine.cpp37
-rw-r--r--src/gui/text/qfontengine_ft_p.h1
-rw-r--r--src/gui/text/qfontengine_p.h3
-rw-r--r--src/gui/text/qfontengine_qpa_p.h5
-rw-r--r--src/gui/text/qplatformfontdatabase_qpa.cpp12
-rw-r--r--src/gui/text/qplatformfontdatabase_qpa.h2
-rw-r--r--src/platformsupport/fontdatabases/fontconfig/fontconfig.pri6
-rw-r--r--src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp11
-rw-r--r--src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h1
-rw-r--r--src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp87
-rw-r--r--src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h60
14 files changed, 235 insertions, 8 deletions
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index a347c62629..ee833a06cf 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -2729,6 +2729,20 @@ QFontEngine *QFontCache::findEngine(const Key &key)
return it.value().data;
}
+void QFontCache::removeEngine(QFontEngine *engine)
+{
+ EngineCache::iterator it = engineCache.begin();
+ while (it != engineCache.end()) {
+ if (it.value().data == engine) {
+ it = engineCache.erase(it);
+ if (--engine->cache_count == 0)
+ decreaseCost(engine->cache_cost);
+ } else {
+ ++it;
+ }
+ }
+}
+
void QFontCache::insertEngine(const Key &key, QFontEngine *engine)
{
FC_DEBUG("QFontCache: inserting new engine %p", engine);
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index e26a98aaf2..d10249201a 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -243,6 +243,7 @@ public:
QFontEngine *findEngine(const Key &key);
void insertEngine(const Key &key, QFontEngine *engine);
+ void removeEngine(QFontEngine *engine);
private:
diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp
index 2a9c37fb13..1a1f08f73d 100644
--- a/src/gui/text/qfontdatabase_qpa.cpp
+++ b/src/gui/text/qfontdatabase_qpa.cpp
@@ -206,7 +206,8 @@ QFontEngine *loadEngine(int script, const QFontDef &request,
if (family && !family->fallbackFamilies.isEmpty())
fallbacks = family->fallbackFamilies;
- engine = new QFontEngineMultiQPA(engine, script, fallbacks);
+ QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
+ engine = pfdb->fontEngineMulti(engine, QUnicodeTables::Script(script), fallbacks);
// Cache Multi font engine as well in case we got the FT single
// font engine when we are actually looking for a Multi one
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 156a4a1e59..a084a3dd8c 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1379,18 +1379,24 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
int glyph_pos = 0;
for (int i = 0; i < len; ++i) {
bool surrogate = (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate());
-
+ uint ucs4 = surrogate ? QChar::surrogateToUcs4(str[i], str[i+1]) : str[i].unicode();
if (glyphs->glyphs[glyph_pos] == 0 && str[i].category() != QChar::Separator_Line) {
QGlyphLayoutInstance tmp = glyphs->instance(glyph_pos);
- for (int x = 1; x < engines.size(); ++x) {
+ for (int x=1; x < engines.size(); ++x) {
+ if (!shouldLoadFontEngineForCharacter(x, ucs4))
+ continue;
+
QFontEngine *engine = engines.at(x);
+ bool deleteThisEngine = false;
if (!engine) {
const_cast<QFontEngineMulti *>(this)->loadEngine(x);
engine = engines.at(x);
+ deleteThisEngine = true;
}
Q_ASSERT(engine != 0);
if (engine->type() == Box)
continue;
+
glyphs->advances_x[glyph_pos] = glyphs->advances_y[glyph_pos] = 0;
glyphs->offsets[glyph_pos] = QFixedPoint();
int num = 2;
@@ -1401,13 +1407,17 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
// set the high byte to indicate which engine the glyph came from
glyphs->glyphs[glyph_pos] |= (x << 24);
break;
+ } else if (deleteThisEngine) {
+ const_cast<QFontEngineMulti *>(this)->unloadEngine(x);
}
}
+
// ensure we use metrics from the 1st font when we use the fallback image.
if (!glyphs->glyphs[glyph_pos]) {
glyphs->setInstance(glyph_pos, tmp);
}
}
+
if (surrogate)
++i;
++glyph_pos;
@@ -1418,6 +1428,29 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
return true;
}
+bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
+{
+ Q_UNUSED(at);
+ Q_UNUSED(ucs4);
+ return true;
+}
+
+void QFontEngineMulti::unloadEngine(int at)
+{
+ QFontEngine *fontEngine = engines.at(at);
+ if (fontEngine == 0)
+ return;
+
+ // If there are other references to the engine, keep it around and keep the reference
+ if (fontEngine->ref.load() == 1) {
+ QFontCache::instance()->removeEngine(fontEngine);
+ if (fontEngine->cache_count == 0) {
+ delete fontEngine;
+ engines[at] = 0;
+ }
+ }
+}
+
glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs)
{
if (glyphs.numGlyphs <= 0)
diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h
index a9e67c10e8..83b51685c0 100644
--- a/src/gui/text/qfontengine_ft_p.h
+++ b/src/gui/text/qfontengine_ft_p.h
@@ -328,6 +328,7 @@ protected:
private:
friend class QFontEngineFTRawFont;
friend class QFontconfigDatabase;
+ friend class QFontEngineMultiFontConfig;
int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index c0bd1afb80..023882d560 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -392,11 +392,14 @@ public:
loadEngine(at);
}
+ virtual bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const;
+
protected:
friend class QPSPrintEnginePrivate;
friend class QPSPrintEngineFontMulti;
friend class QRawFont;
virtual void loadEngine(int at) = 0;
+ virtual void unloadEngine(int at);
QVector<QFontEngine *> engines;
};
diff --git a/src/gui/text/qfontengine_qpa_p.h b/src/gui/text/qfontengine_qpa_p.h
index 6a73b9d309..ed2e071ac2 100644
--- a/src/gui/text/qfontengine_qpa_p.h
+++ b/src/gui/text/qfontengine_qpa_p.h
@@ -243,13 +243,16 @@ struct QPAGenerator
QFontEngine *fe;
};
-class QFontEngineMultiQPA : public QFontEngineMulti
+class Q_GUI_EXPORT QFontEngineMultiQPA : public QFontEngineMulti
{
public:
QFontEngineMultiQPA(QFontEngine *fe, int script, const QStringList &fallbacks);
void loadEngine(int at);
+ int fallbackFamilyCount() const { return fallbackFamilies.size(); }
+ QString fallbackFamilyAt(int at) const { return fallbackFamilies.at(at); }
+
private:
QStringList fallbackFamilies;
int script;
diff --git a/src/gui/text/qplatformfontdatabase_qpa.cpp b/src/gui/text/qplatformfontdatabase_qpa.cpp
index f9cc97cbc7..8fcf421330 100644
--- a/src/gui/text/qplatformfontdatabase_qpa.cpp
+++ b/src/gui/text/qplatformfontdatabase_qpa.cpp
@@ -271,6 +271,18 @@ void QPlatformFontDatabase::populateFontDatabase()
}
/*!
+ Returns a multi font engine in the specified \a script to encapsulate \a fontEngine with the
+ option to fall back to to the fonts given by \a fallbacks if \a fontEngine does not support
+ a certain character.
+*/
+QFontEngineMulti *QPlatformFontDatabase::fontEngineMulti(QFontEngine *fontEngine,
+ QUnicodeTables::Script script,
+ const QStringList &fallbacks)
+{
+ return new QFontEngineMultiQPA(fontEngine, script, fallbacks);
+}
+
+/*!
Returns the font engine that can be used to render the font described by
the font definition, \a fontDef, in the specified \a script.
*/
diff --git a/src/gui/text/qplatformfontdatabase_qpa.h b/src/gui/text/qplatformfontdatabase_qpa.h
index 151442c5e1..6a58a3106c 100644
--- a/src/gui/text/qplatformfontdatabase_qpa.h
+++ b/src/gui/text/qplatformfontdatabase_qpa.h
@@ -82,12 +82,14 @@ Q_GUI_EXPORT bool operator==(const QSupportedWritingSystems &, const QSupportedW
Q_GUI_EXPORT bool operator!=(const QSupportedWritingSystems &, const QSupportedWritingSystems &);
class QFontRequestPrivate;
+class QFontEngineMulti;
class Q_GUI_EXPORT QPlatformFontDatabase
{
public:
virtual ~QPlatformFontDatabase();
virtual void populateFontDatabase();
+ virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QUnicodeTables::Script script, const QStringList &fallbacks);
virtual QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle);
virtual QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const;
virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName);
diff --git a/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri b/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri
index 7ea1c64e33..2c896ef2cc 100644
--- a/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri
+++ b/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri
@@ -1,3 +1,5 @@
-HEADERS += $$PWD/qfontconfigdatabase_p.h
-SOURCES += $$PWD/qfontconfigdatabase.cpp
+HEADERS += $$PWD/qfontconfigdatabase_p.h \
+ fontdatabases/fontconfig/qfontenginemultifontconfig_p.h
+SOURCES += $$PWD/qfontconfigdatabase.cpp \
+ fontdatabases/fontconfig/qfontenginemultifontconfig.cpp
DEFINES -= QT_NO_FONTCONFIG
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
index f048ed91de..8a9670118f 100644
--- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qfontconfigdatabase_p.h"
+#include "qfontenginemultifontconfig_p.h"
#include <QtCore/QList>
#include <QtGui/private/qfont_p.h>
@@ -50,8 +51,7 @@
#include <QtGui/private/qfontengine_ft_p.h>
#include <QtGui/private/qfontengine_p.h>
-
-
+#include <QtGui/private/qfontengine_qpa_p.h>
#include <ft2build.h>
#include FT_TRUETYPE_TABLES_H
@@ -471,6 +471,13 @@ void QFontconfigDatabase::populateFontDatabase()
// QApplication::setFont(font);
}
+QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine,
+ QUnicodeTables::Script script,
+ const QStringList &fallbacks)
+{
+ return new QFontEngineMultiFontConfig(fontEngine, script, fallbacks);
+}
+
QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QUnicodeTables::Script script, void *usrPtr)
{
if (!usrPtr)
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h
index 77509f76e5..d4742167e9 100644
--- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h
@@ -51,6 +51,7 @@ class QFontconfigDatabase : public QBasicFontDatabase
{
public:
void populateFontDatabase();
+ QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QUnicodeTables::Script script, const QStringList &fallbacks);
QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle);
QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const;
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName);
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp
new file mode 100644
index 0000000000..7b28b20bcb
--- /dev/null
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfontenginemultifontconfig_p.h"
+
+#include <QtGui/private/qfontengine_ft_p.h>
+#include <fontconfig/fontconfig.h>
+#include <QtGui/private/qfontengine_ft_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QFontEngineMultiFontConfig::QFontEngineMultiFontConfig(QFontEngine *fe, int script,
+ const QStringList &fallbacks)
+ : QFontEngineMultiQPA(fe, script, fallbacks)
+{
+}
+
+bool QFontEngineMultiFontConfig::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
+{
+ QFontEngineFT *fontEngine = static_cast<QFontEngineFT *>(engines.at(at));
+ bool charSetHasChar = true;
+ if (fontEngine != 0) {
+ FcCharSet *charSet = fontEngine->freetype->charset;
+ charSetHasChar = FcCharSetHasChar(charSet, ucs4);
+ } else {
+ FcPattern *requestPattern = FcPatternCreate();
+
+ FcValue value;
+ value.type = FcTypeString;
+ QByteArray cs = fallbackFamilyAt(at-1).toUtf8();
+ value.u.s = reinterpret_cast<const FcChar8 *>(cs.data());
+ FcPatternAdd(requestPattern, FC_FAMILY, value, true);
+
+ FcResult result;
+ FcPattern *matchPattern = FcFontMatch(0, requestPattern, &result);
+ if (matchPattern != 0) {
+ FcCharSet *charSet;
+ FcPatternGetCharSet(matchPattern, FC_CHARSET, 0, &charSet);
+ charSetHasChar = FcCharSetHasChar(charSet, ucs4);
+ FcPatternDestroy(matchPattern);
+ }
+
+ FcPatternDestroy(requestPattern);
+ }
+
+ return charSetHasChar;
+}
+
+QT_END_NAMESPACE
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h
new file mode 100644
index 0000000000..4323cb7d2e
--- /dev/null
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFONTENGINEMULTIFONTCONFIG_H
+#define QFONTENGINEMULTIFONTCONFIG_H
+
+#include <QtGui/private/qfontengine_qpa_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFontEngineMultiFontConfig : public QFontEngineMultiQPA
+{
+ Q_OBJECT
+public:
+ explicit QFontEngineMultiFontConfig(QFontEngine *fe, int script, const QStringList &fallbacks);
+
+ bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFONTENGINEMULTIFONTCONFIG_H