summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qdistancefield.cpp17
-rw-r--r--src/gui/text/qfont.cpp8
-rw-r--r--src/gui/text/qfont_p.h22
-rw-r--r--src/gui/text/qfontdatabase.cpp424
-rw-r--r--src/gui/text/qfontdatabase_qpa.cpp472
-rw-r--r--src/gui/text/qfontengine.cpp221
-rw-r--r--src/gui/text/qfontengine_ft.cpp87
-rw-r--r--src/gui/text/qfontengine_ft_p.h8
-rw-r--r--src/gui/text/qfontengine_p.h53
-rw-r--r--src/gui/text/qfontengine_qpa.cpp115
-rw-r--r--src/gui/text/qfontengine_qpa_p.h8
-rw-r--r--src/gui/text/qfontmetrics.cpp104
-rw-r--r--src/gui/text/qfontsubset.cpp16
-rw-r--r--src/gui/text/qharfbuzzng.cpp44
-rw-r--r--src/gui/text/qplatformfontdatabase.cpp10
-rw-r--r--src/gui/text/qplatformfontdatabase.h2
-rw-r--r--src/gui/text/qrawfont.cpp2
-rw-r--r--src/gui/text/qtextengine.cpp172
-rw-r--r--src/gui/text/qtextengine_p.h39
19 files changed, 804 insertions, 1020 deletions
diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp
index f2b88c4692..17116ee2d0 100644
--- a/src/gui/text/qdistancefield.cpp
+++ b/src/gui/text/qdistancefield.cpp
@@ -739,20 +739,11 @@ bool qt_fontHasNarrowOutlines(QFontEngine *fontEngine)
if (!fe)
return false;
- const QChar uc(QLatin1Char('O'));
+ QImage im;
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
- int numGlyphs = 1;
-
- if (!fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(numGlyphs == 1);
-
- QImage im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform());
+ const glyph_t glyph = fe->glyphIndex('O');
+ if (glyph != 0)
+ im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform());
Q_ASSERT(fe->ref.load() == 0);
delete fe;
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 83f2d7190b..2e21a81187 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -2770,10 +2770,10 @@ void QFontCache::updateHitCountAndTimeStamp(Engine &value)
value.timestamp = ++current_timestamp;
FC_DEBUG("QFontCache: found font engine\n"
- " %p: timestamp %4u hits %3u ref %2d/%2d, type '%s'",
+ " %p: timestamp %4u hits %3u ref %2d/%2d, type %d",
value.data, value.timestamp, value.hits,
value.data->ref.load(), engineCacheCount.value(value.data),
- value.data->name());
+ value.data->type());
}
void QFontCache::insertEngine(const Key &key, QFontEngine *engine, bool insertMulti)
@@ -2969,10 +2969,10 @@ void QFontCache::timerEvent(QTimerEvent *)
it = jt;
if (it != end) {
- FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type '%s'",
+ FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type %d",
it.value().data, it.value().timestamp, it.value().hits,
it.value().data->ref.load(), engineCacheCount.value(it.value().data),
- it.value().data->name());
+ it.value().data->type());
QFontEngine *fontEngine = it.value().data;
// get rid of all occurrences
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index 6165554388..b78d6692b4 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -228,22 +228,32 @@ public:
void clear();
struct Key {
- Key() : script(0), screen(0) { }
- Key(const QFontDef &d, int c, int s = 0)
- : def(d), script(c), screen(s) { }
+ Key() : script(0), multi(0), screen(0) { }
+ Key(const QFontDef &d, uchar c, bool m = 0, uchar s = 0)
+ : def(d), script(c), multi(m), screen(s) { }
QFontDef def;
- int script;
- int screen;
+ uchar script;
+ uchar multi: 1;
+ uchar screen: 7;
inline bool operator<(const Key &other) const
{
if (script != other.script) return script < other.script;
if (screen != other.screen) return screen < other.screen;
+ if (multi != other.multi) return multi < other.multi;
+ if (multi && def.fallBackFamilies.size() != other.def.fallBackFamilies.size())
+ return def.fallBackFamilies.size() < other.def.fallBackFamilies.size();
return def < other.def;
}
inline bool operator==(const Key &other) const
- { return def == other.def && script == other.script && screen == other.screen; }
+ {
+ return script == other.script
+ && screen == other.screen
+ && multi == other.multi
+ && (!multi || def.fallBackFamilies.size() == other.def.fallBackFamilies.size())
+ && def == other.def;
+ }
};
// QFontEngineData cache
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 61c93dc2ac..02b9e6d25c 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -55,6 +55,8 @@
#include <qpa/qplatformfontdatabase.h>
#include <qpa/qplatformtheme.h>
+#include <QtCore/qmath.h>
+
#include <stdlib.h>
#include <limits.h>
#include <algorithm>
@@ -418,6 +420,7 @@ void QFontDatabasePrivate::invalidate()
{
QFontCache::instance()->clear();
free();
+ QGuiApplicationPrivate::platformIntegration()->fontDatabase()->invalidate();
emit static_cast<QGuiApplication *>(QCoreApplication::instance())->fontDatabaseChanged();
}
@@ -654,9 +657,201 @@ QMutex *qt_fontdatabase_mutex()
return fontDatabaseMutex();
}
-QT_BEGIN_INCLUDE_NAMESPACE
-# include "qfontdatabase_qpa.cpp"
-QT_END_INCLUDE_NAMESPACE
+
+void qt_registerFont(const QString &familyName, const QString &stylename,
+ const QString &foundryname, int weight,
+ QFont::Style style, int stretch, bool antialiased,
+ bool scalable, int pixelSize, bool fixedPitch,
+ const QSupportedWritingSystems &writingSystems, void *handle)
+{
+ QFontDatabasePrivate *d = privateDb();
+// qDebug() << "Adding font" << familyName << weight << style << pixelSize << antialiased;
+ QtFontStyle::Key styleKey;
+ styleKey.style = style;
+ styleKey.weight = weight;
+ styleKey.stretch = stretch;
+ QtFontFamily *f = d->family(familyName, true);
+ f->fixedPitch = fixedPitch;
+
+ for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
+ if (writingSystems.supported(QFontDatabase::WritingSystem(i)))
+ f->writingSystems[i] = QtFontFamily::Supported;
+ }
+
+ QtFontFoundry *foundry = f->foundry(foundryname, true);
+ QtFontStyle *fontStyle = foundry->style(styleKey, stylename, true);
+ fontStyle->smoothScalable = scalable;
+ fontStyle->antialiased = antialiased;
+ QtFontSize *size = fontStyle->pixelSize(pixelSize ? pixelSize : SMOOTH_SCALABLE, true);
+ if (size->handle) {
+ QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
+ if (integration)
+ integration->fontDatabase()->releaseHandle(size->handle);
+ }
+ size->handle = handle;
+}
+
+void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
+{
+ if (alias.isEmpty())
+ return;
+
+ QFontDatabasePrivate *d = privateDb();
+ QtFontFamily *f = d->family(familyName, false);
+ if (!f)
+ return;
+
+ if (f->aliases.contains(alias, Qt::CaseInsensitive))
+ return;
+
+ f->aliases.push_back(alias);
+}
+
+QString qt_resolveFontFamilyAlias(const QString &alias)
+{
+ if (!alias.isEmpty()) {
+ const QFontDatabasePrivate *d = privateDb();
+ for (int i = 0; i < d->count; ++i)
+ if (d->families[i]->matchesFamilyName(alias))
+ return d->families[i]->name;
+ }
+ return alias;
+}
+
+static QStringList fallbackFamilies(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
+{
+ QStringList retList = QGuiApplicationPrivate::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++) {
+ if (db->families[j]->matchesFamilyName(*i)) {
+ contains = true;
+ break;
+ }
+ }
+ if (!contains) {
+ i = retList.erase(i);
+ i--;
+ }
+ }
+ return retList;
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
+
+static void initializeDb()
+{
+ QFontDatabasePrivate *db = privateDb();
+
+ // init by asking for the platformfontdb for the first time or after invalidation
+ if (!db->count)
+ QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase();
+
+ if (db->reregisterAppFonts) {
+ for (int i = 0; i < db->applicationFonts.count(); i++) {
+ if (!db->applicationFonts.at(i).families.isEmpty())
+ registerFont(&db->applicationFonts[i]);
+ }
+ db->reregisterAppFonts = false;
+ }
+}
+
+static inline void load(const QString & = QString(), int = -1)
+{
+ // Only initialize the database if it has been cleared or not initialized yet
+ if (!privateDb()->count)
+ initializeDb();
+}
+
+static
+QFontEngine *loadSingleEngine(int script,
+ const QFontDef &request,
+ QtFontFoundry *foundry,
+ QtFontStyle *style, QtFontSize *size)
+{
+ Q_UNUSED(foundry);
+
+ Q_ASSERT(size);
+ QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
+ int pixelSize = size->pixelSize;
+ if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE)
+ || pfdb->fontsAlwaysScalable()) {
+ pixelSize = request.pixelSize;
+ }
+
+ QFontDef def = request;
+ def.pixelSize = pixelSize;
+
+ QFontCache::Key key(def,script);
+ QFontEngine *engine = QFontCache::instance()->findEngine(key);
+ if (!engine) {
+ engine = pfdb->fontEngine(def, size->handle);
+ if (engine) {
+ Q_ASSERT(engine->type() != QFontEngine::Multi);
+ // Also check for OpenType tables when using complex scripts
+ if (!engine->supportsScript(QChar::Script(script))) {
+ qWarning(" OpenType support missing for script %d", script);
+ if (engine->ref.load() == 0)
+ delete engine;
+ return 0;
+ }
+
+ QFontCache::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);
+ Q_ASSERT(!engine || engine->type() != QFontEngine::Multi);
+ if (engine && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
+ // make sure that the db has all fallback families
+ 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, QChar::Script(script));
+
+ family->askedForFallback = true;
+ }
+
+ QStringList fallbacks = request.fallBackFamilies;
+ if (family && !family->fallbackFamilies.isEmpty())
+ fallbacks += family->fallbackFamilies;
+ else
+ fallbacks += privateDb()->fallbackFamilies;
+
+ QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
+ QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QChar::Script(script));
+ pfMultiEngine->setFallbackFamiliesList(fallbacks);
+ engine = pfMultiEngine;
+
+ // Cache Multi font engine as well in case we got the single
+ // font engine when we are actually looking for a Multi one
+ QFontCache::Key key(request, script, 1);
+ QFontCache::instance()->insertEngine(key, engine);
+ }
+
+ return engine;
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
+{
+ QFontDatabasePrivate *db = privateDb();
+
+ fnt->families = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data,fnt->fileName);
+
+ db->reregisterAppFonts = true;
+}
static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey,
const QString &styleName = QString())
@@ -1032,6 +1227,9 @@ QString QFontDatabase::styleString(const QFontInfo &fontInfo)
*/
QFontDatabase::QFontDatabase()
{
+ if (!qApp || !QGuiApplicationPrivate::platformIntegration())
+ qFatal("QFontDatabase: Must construct a QGuiApplication before accessing QFontDatabase");
+
QMutexLocker locker(fontDatabaseMutex());
createDatabase();
d = privateDb();
@@ -2146,6 +2344,20 @@ QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type)
\sa removeAllApplicationFonts(), addApplicationFont(),
addApplicationFontFromData()
*/
+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;
+}
/*!
\fn bool QFontDatabase::removeAllApplicationFonts()
@@ -2159,6 +2371,18 @@ QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type)
\sa removeApplicationFont(), addApplicationFont(), addApplicationFontFromData()
*/
+bool QFontDatabase::removeAllApplicationFonts()
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ if (db->applicationFonts.isEmpty())
+ return false;
+
+ db->applicationFonts.clear();
+ db->invalidate();
+ return true;
+}
/*!
\fn bool QFontDatabase::supportsThreadedFontRendering()
@@ -2174,6 +2398,200 @@ QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type)
\sa {Thread-Support in Qt Modules#Painting In Threads}{Painting In Threads}
*/
+// QT_DEPRECATED_SINCE(5, 2)
+bool QFontDatabase::supportsThreadedFontRendering()
+{
+ return true;
+}
+
+/*!
+ \internal
+*/
+QFontEngine *
+QFontDatabase::findFont(int script, const QFontPrivate *fp,
+ const QFontDef &request, bool multi)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ const int force_encoding_id = -1;
+
+ if (!privateDb()->count)
+ initializeDb();
+
+ QFontEngine *engine;
+ QFontCache::Key key(request, script, multi ? 1 : 0);
+ engine = QFontCache::instance()->findEngine(key);
+ if (engine) {
+ FM_DEBUG("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;
+ QList<int> blackListed;
+ int index = match(script, request, family_name, foundry_name, force_encoding_id, &desc, blackListed);
+ if (index >= 0) {
+ engine = loadEngine(script, request, desc.family, desc.foundry, desc.style, desc.size);
+ if (!engine)
+ blackListed.append(index);
+ } else {
+ FM_DEBUG(" NO MATCH FOUND\n");
+ }
+
+ if (engine && engine->type() != QFontEngine::TestFontEngine) {
+ initFontDef(desc, request, &engine->fontDef, engine->type() == QFontEngine::Multi);
+
+ 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 = request.fallBackFamilies
+ + fallbackFamilies(request.family,
+ QFont::Style(request.style),
+ QFont::StyleHint(request.styleHint),
+ QChar::Script(script));
+ if (script > QChar::Script_Common)
+ fallbacks += QString(); // Find the first font matching the specified script.
+
+ for (int i = 0; !engine && i < fallbacks.size(); i++) {
+ QFontDef def = request;
+ def.family = fallbacks.at(i);
+ QFontCache::Key key(def, script, multi ? 1 : 0);
+ engine = QFontCache::instance()->findEngine(key);
+ if (!engine) {
+ QtFontDesc desc;
+ do {
+ index = match(script, def, def.family, QLatin1String(""), 0, &desc, blackListed);
+ if (index >= 0) {
+ QFontDef loadDef = def;
+ if (loadDef.family.isEmpty())
+ loadDef.family = desc.family->name;
+ engine = loadEngine(script, loadDef, desc.family, desc.foundry, desc.style, desc.size);
+ if (engine)
+ initFontDef(desc, loadDef, &engine->fontDef, engine->type() == QFontEngine::Multi);
+ else
+ blackListed.append(index);
+ }
+ } while (index >= 0 && !engine);
+ }
+ }
+ }
+
+ 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;
+
+ // Until we specifically asked not to, try looking for Multi font engine
+ // first, the last '1' indicates that we want Multi font engine instead
+ // of single ones
+ bool multi = !(req.styleStrategy & QFont::NoFontMerging);
+ QFontCache::Key key(req, script, multi ? 1 : 0);
+
+ if (!d->engineData)
+ getEngineData(d, req);
+
+ // 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()) {
+ QStringList familiesForRequest = familyList(req);
+
+ // Add primary selection
+ family_list << familiesForRequest.takeFirst();
+
+ // Fallbacks requested in font request
+ req.fallBackFamilies = familiesForRequest;
+
+ // add the default family
+ QString defaultFamily = QGuiApplication::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, multi);
+ if (fe && (fe->type()==QFontEngine::Box) && !req.family.isEmpty()) {
+ if (fe->ref.load() == 0)
+ delete fe;
+
+ fe = 0;
+ }
+
+ // No need to check requested fallback families again
+ req.fallBackFamilies.clear();
+ }
+
+ if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
+ for (int i = 0; i < QChar::ScriptCount; ++i) {
+ if (!d->engineData->engines[i]) {
+ d->engineData->engines[i] = fe;
+ fe->ref.ref();
+ }
+ }
+ } else {
+ d->engineData->engines[script] = fe;
+ fe->ref.ref();
+ }
+}
+
+QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
+{
+ return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family);
+}
QT_END_NAMESPACE
diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp
deleted file mode 100644
index 1972f5d58c..0000000000
--- a/src/gui/text/qfontdatabase_qpa.cpp
+++ /dev/null
@@ -1,472 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** 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, Digia gives you certain additional
-** rights. These rights are described in the Digia 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.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qlibraryinfo.h"
-#include <QtCore/qsettings.h>
-
-#include "qfontengine_qpa_p.h"
-#include "qplatformdefs.h"
-
-#include <QtGui/private/qguiapplication_p.h>
-#include <qpa/qplatformfontdatabase.h>
-
-#include <QtCore/qmath.h>
-
-QT_BEGIN_NAMESPACE
-
-void qt_registerFont(const QString &familyName, const QString &stylename,
- const QString &foundryname, int weight,
- QFont::Style style, int stretch, bool antialiased,
- bool scalable, int pixelSize, bool fixedPitch,
- const QSupportedWritingSystems &writingSystems, void *handle)
-{
- QFontDatabasePrivate *d = privateDb();
-// qDebug() << "Adding font" << familyName << weight << style << pixelSize << antialiased;
- QtFontStyle::Key styleKey;
- styleKey.style = style;
- styleKey.weight = weight;
- styleKey.stretch = stretch;
- QtFontFamily *f = d->family(familyName, true);
- f->fixedPitch = fixedPitch;
-
- for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
- if (writingSystems.supported(QFontDatabase::WritingSystem(i)))
- f->writingSystems[i] = QtFontFamily::Supported;
- }
-
- QtFontFoundry *foundry = f->foundry(foundryname, true);
- QtFontStyle *fontStyle = foundry->style(styleKey, stylename, true);
- fontStyle->smoothScalable = scalable;
- fontStyle->antialiased = antialiased;
- QtFontSize *size = fontStyle->pixelSize(pixelSize ? pixelSize : SMOOTH_SCALABLE, true);
- if (size->handle) {
- QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
- if (integration)
- integration->fontDatabase()->releaseHandle(size->handle);
- }
- size->handle = handle;
-}
-
-void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
-{
- if (alias.isEmpty())
- return;
-
- QFontDatabasePrivate *d = privateDb();
- QtFontFamily *f = d->family(familyName, false);
- if (!f)
- return;
-
- if (f->aliases.contains(alias, Qt::CaseInsensitive))
- return;
-
- f->aliases.push_back(alias);
-}
-
-QString qt_resolveFontFamilyAlias(const QString &alias)
-{
- if (!alias.isEmpty()) {
- const QFontDatabasePrivate *d = privateDb();
- for (int i = 0; i < d->count; ++i)
- if (d->families[i]->matchesFamilyName(alias))
- return d->families[i]->name;
- }
- return alias;
-}
-
-static QStringList fallbackFamilies(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
-{
- QStringList retList = QGuiApplicationPrivate::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++) {
- if (db->families[j]->matchesFamilyName(*i)) {
- contains = true;
- break;
- }
- }
- if (!contains) {
- i = retList.erase(i);
- i--;
- }
- }
- return retList;
-}
-
-static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
-
-static void initializeDb()
-{
- QFontDatabasePrivate *db = privateDb();
-
- // init by asking for the platformfontdb for the first time or after invalidation
- if (!db->count)
- QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase();
-
- if (db->reregisterAppFonts) {
- for (int i = 0; i < db->applicationFonts.count(); i++) {
- if (!db->applicationFonts.at(i).families.isEmpty())
- registerFont(&db->applicationFonts[i]);
- }
- db->reregisterAppFonts = false;
- }
-}
-
-static inline void load(const QString & = QString(), int = -1)
-{
- // Only initialize the database if it has been cleared or not initialized yet
- if (!privateDb()->count)
- initializeDb();
-}
-
-static
-QFontEngine *loadSingleEngine(int script,
- const QFontDef &request,
- QtFontFoundry *foundry,
- QtFontStyle *style, QtFontSize *size)
-{
- Q_UNUSED(foundry);
-
- Q_ASSERT(size);
- QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
- int pixelSize = size->pixelSize;
- if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE)
- || pfdb->fontsAlwaysScalable()) {
- pixelSize = request.pixelSize;
- }
-
- QFontDef def = request;
- def.pixelSize = pixelSize;
-
- QFontCache::Key key(def,script);
- QFontEngine *engine = QFontCache::instance()->findEngine(key);
- if (!engine) {
- engine = pfdb->fontEngine(def, size->handle);
- if (engine) {
- // Also check for OpenType tables when using complex scripts
- if (!engine->supportsScript(QChar::Script(script))) {
- qWarning(" OpenType support missing for script %d", script);
- if (engine->ref.load() == 0)
- delete engine;
- return 0;
- }
-
- QFontCache::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 && engine->type() != QFontEngine::Multi
- && !(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, QChar::Script(script));
-
- family->askedForFallback = true;
- }
-
- QStringList fallbacks = privateDb()->fallbackFamilies;
- if (family && !family->fallbackFamilies.isEmpty())
- fallbacks = family->fallbackFamilies;
-
- QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
- QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QChar::Script(script));
- pfMultiEngine->setFallbackFamiliesList(fallbacks);
- engine = pfMultiEngine;
-
- // Cache Multi font engine as well in case we got the single
- // font engine when we are actually looking for a Multi one
- QFontCache::Key key(request, script, 1);
- QFontCache::instance()->insertEngine(key, engine);
- }
-
- return engine;
-}
-
-static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
-{
- QFontDatabasePrivate *db = privateDb();
-
- fnt->families = QGuiApplicationPrivate::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;
-}
-
-// QT_DEPRECATED_SINCE(5, 2)
-bool QFontDatabase::supportsThreadedFontRendering()
-{
- return true;
-}
-
-/*!
- \internal
-*/
-QFontEngine *
-QFontDatabase::findFont(int script, const QFontPrivate *fp,
- const QFontDef &request, bool multi)
-{
- QMutexLocker locker(fontDatabaseMutex());
-
- const int force_encoding_id = -1;
-
- if (!privateDb()->count)
- initializeDb();
-
- QFontEngine *engine;
- QFontCache::Key key(request, script, multi ? 1 : 0);
- engine = QFontCache::instance()->findEngine(key);
- if (engine) {
- FM_DEBUG("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;
- QList<int> blackListed;
- int index = match(script, request, family_name, foundry_name, force_encoding_id, &desc, blackListed);
- if (index >= 0) {
- engine = loadEngine(script, request, desc.family, desc.foundry, desc.style, desc.size);
- if (!engine)
- blackListed.append(index);
- } else {
- FM_DEBUG(" NO MATCH FOUND\n");
- }
-
- if (engine && engine->type() != QFontEngine::TestFontEngine) {
- initFontDef(desc, request, &engine->fontDef, engine->type() == QFontEngine::Multi);
-
- 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 = request.fallBackFamilies
- + fallbackFamilies(request.family,
- QFont::Style(request.style),
- QFont::StyleHint(request.styleHint),
- QChar::Script(script));
- if (script > QChar::Script_Common)
- fallbacks += QString(); // Find the first font matching the specified script.
-
- for (int i = 0; !engine && i < fallbacks.size(); i++) {
- QFontDef def = request;
- def.family = fallbacks.at(i);
- QFontCache::Key key(def, script, multi ? 1 : 0);
- engine = QFontCache::instance()->findEngine(key);
- if (!engine) {
- QtFontDesc desc;
- do {
- index = match(script, def, def.family, QLatin1String(""), 0, &desc, blackListed);
- if (index >= 0) {
- QFontDef loadDef = def;
- if (loadDef.family.isEmpty())
- loadDef.family = desc.family->name;
- engine = loadEngine(script, loadDef, desc.family, desc.foundry, desc.style, desc.size);
- if (engine)
- initFontDef(desc, loadDef, &engine->fontDef, engine->type() == QFontEngine::Multi);
- else
- blackListed.append(index);
- }
- } while (index >= 0 && !engine);
- }
- }
- }
-
- 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;
-
- // Until we specifically asked not to, try looking for Multi font engine
- // first, the last '1' indicates that we want Multi font engine instead
- // of single ones
- bool multi = !(req.styleStrategy & QFont::NoFontMerging);
- QFontCache::Key key(req, script, multi ? 1 : 0);
-
- if (!d->engineData)
- getEngineData(d, req);
-
- // 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()) {
- QStringList familiesForRequest = familyList(req);
-
- // Add primary selection
- family_list << familiesForRequest.takeFirst();
-
- // Fallbacks requested in font request
- req.fallBackFamilies = familiesForRequest;
-
- // add the default family
- QString defaultFamily = QGuiApplication::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, multi);
- if (fe && (fe->type()==QFontEngine::Box) && !req.family.isEmpty()) {
- if (fe->ref.load() == 0)
- delete fe;
-
- fe = 0;
- }
-
- // No need to check requested fallback families again
- req.fallBackFamilies.clear();
- }
-
- if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
- for (int i = 0; i < QChar::ScriptCount; ++i) {
- if (!d->engineData->engines[i]) {
- d->engineData->engines[i] = fe;
- fe->ref.ref();
- }
- }
- } else {
- d->engineData->engines[script] = fe;
- fe->ref.ref();
- }
-}
-
-QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
-{
- return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family);
-}
-
-QT_END_NAMESPACE
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 83e64a51a6..a72ac23418 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -101,35 +101,13 @@ static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint
*numGlyphs = nGlyphs;
if (rightToLeft && result && !fe->symbol) {
- uint glyph_pos = 0;
- for (uint i = 0; i < length; ++i, ++glyph_pos) {
- uint ucs4 = str[i].unicode();
- if (Q_UNLIKELY(QChar::isHighSurrogate(ucs4) && i + 1 < length)) {
- uint low = str[i + 1].unicode();
- if (Q_LIKELY(QChar::isLowSurrogate(low))) {
- ucs4 = QChar::surrogateToUcs4(ucs4, low);
- ++i;
- }
- }
-
- uint mirrored = QChar::mirroredChar(ucs4);
- if (Q_UNLIKELY(mirrored != ucs4)) {
- QChar chars[2];
- uint numChars = 0;
- if (Q_UNLIKELY(QChar::requiresSurrogates(mirrored))) {
- chars[numChars++] = QChar(QChar::highSurrogate(mirrored));
- chars[numChars++] = QChar(QChar::lowSurrogate(mirrored));
- } else {
- chars[numChars++] = QChar(mirrored);
- }
-
- qglyphs.numGlyphs = numChars;
- qglyphs.glyphs = glyphs + glyph_pos;
- nGlyphs = numChars;
- if (!fe->stringToCMap(chars, numChars, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nGlyphs == 1);
- }
+ QStringIterator it(str, str + length);
+ while (it.hasNext()) {
+ const uint ucs4 = it.next();
+ const uint mirrored = QChar::mirroredChar(ucs4);
+ if (Q_UNLIKELY(mirrored != ucs4))
+ *glyphs = fe->glyphIndex(mirrored);
+ ++glyphs;
}
}
@@ -242,8 +220,8 @@ Q_AUTOTEST_EXPORT QList<QFontEngine *> QFontEngine_stopCollectingEngines()
// QFontEngine
-QFontEngine::QFontEngine()
- : ref(0),
+QFontEngine::QFontEngine(Type type)
+ : m_type(type), ref(0),
font_(0), font_destroy_func(0),
face_(0), face_destroy_func(0)
{
@@ -359,6 +337,15 @@ bool QFontEngine::supportsScript(QChar::Script script) const
return true;
}
+#ifdef Q_OS_MAC
+ {
+ // in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table
+ uint len;
+ if (getSfntTableData(MAKE_TAG('m','o','r','t'), 0, &len) || getSfntTableData(MAKE_TAG('m','o','r','x'), 0, &len))
+ return true;
+ }
+#endif
+
#ifdef QT_ENABLE_HARFBUZZ_NG
if (useHarfbuzzNG) {
bool ret = false;
@@ -385,6 +372,17 @@ bool QFontEngine::supportsScript(QChar::Script script) const
return hbFace->supported_scripts[script_to_hbscript(script)];
}
+bool QFontEngine::canRender(const QChar *str, int len) const
+{
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ if (glyphIndex(it.next()) == 0)
+ return false;
+ }
+
+ return true;
+}
+
glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix)
{
glyph_metrics_t metrics = boundingBox(glyph);
@@ -397,38 +395,14 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix
QFixed QFontEngine::xHeight() const
{
- QChar x((ushort)'x');
-
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
-
+ const glyph_t glyph = glyphIndex('x');
glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
return bb.height;
}
QFixed QFontEngine::averageCharWidth() const
{
- QChar x((ushort)'x');
-
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
-
+ const glyph_t glyph = glyphIndex('x');
glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
return bb.xoff;
}
@@ -489,18 +463,14 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
if (glyphs.justifications[i].nKashidas) {
QChar ch(0x640); // Kashida character
- glyph_t kashidaGlyph;
+ glyph_t kashidaGlyph = glyphIndex(ch.unicode());
QFixed kashidaWidth;
QGlyphLayout g;
g.numGlyphs = 1;
g.glyphs = &kashidaGlyph;
g.advances = &kashidaWidth;
-
- int nglyphs = 1;
- if (!stringToCMap(&ch, 1, &g, &nglyphs, 0))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ recalcAdvances(&g, 0);
for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) {
xpos -= kashidaWidth;
@@ -937,14 +907,31 @@ void QFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metr
addGlyphsToPath(&glyph, &p, 1, path, QFlag(0));
}
+/*!
+ Returns \c true if the font table idetified by \a tag exists in the font;
+ returns \c false otherwise.
+
+ If \a buffer is NULL, stores the size of the buffer required for the font table data,
+ in bytes, in \a length. If \a buffer is not NULL and the capacity
+ of the buffer, passed in \a length, is sufficient to store the font table data,
+ also copies the font table data to \a buffer.
+
+ Note: returning \c false when the font table exists could lead to an undefined behavior.
+*/
+bool QFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ Q_UNUSED(tag)
+ Q_UNUSED(buffer)
+ Q_UNUSED(length)
+ return false;
+}
+
QByteArray QFontEngine::getSfntTable(uint tag) const
{
QByteArray table;
uint len = 0;
if (!getSfntTableData(tag, 0, &len))
return table;
- if (!len)
- return table;
table.resize(len);
if (!getSfntTableData(tag, reinterpret_cast<uchar *>(table.data()), &len))
return QByteArray();
@@ -1382,7 +1369,15 @@ QFontEngine::GlyphCacheEntry &QFontEngine::GlyphCacheEntry::operator=(const Glyp
// ------------------------------------------------------------------
QFontEngineBox::QFontEngineBox(int size)
- : _size(size)
+ : QFontEngine(Box),
+ _size(size)
+{
+ cache_cost = sizeof(QFontEngineBox);
+}
+
+QFontEngineBox::QFontEngineBox(Type type, int size)
+ : QFontEngine(type),
+ _size(size)
{
cache_cost = sizeof(QFontEngineBox);
}
@@ -1391,8 +1386,15 @@ QFontEngineBox::~QFontEngineBox()
{
}
+glyph_t QFontEngineBox::glyphIndex(uint ucs4) const
+{
+ Q_UNUSED(ucs4)
+ return 0;
+}
+
bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
{
+ Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
return false;
@@ -1503,22 +1505,11 @@ qreal QFontEngineBox::maxCharWidth() const
return _size;
}
-
-const char *QFontEngineBox::name() const
-{
- return "null";
-}
-
-bool QFontEngineBox::canRender(const QChar *, int)
+bool QFontEngineBox::canRender(const QChar *, int) const
{
return true;
}
-QFontEngine::Type QFontEngineBox::type() const
-{
- return Box;
-}
-
QImage QFontEngineBox::alphaMapForGlyph(glyph_t)
{
QImage image(_size, _size, QImage::Format_Indexed8);
@@ -1550,6 +1541,7 @@ static inline glyph_t stripped(glyph_t glyph)
{ return glyph & 0x00ffffff; }
QFontEngineMulti::QFontEngineMulti(int engineCount)
+ : QFontEngine(Multi)
{
engines.fill(0, engineCount);
cache_cost = 0;
@@ -1564,6 +1556,35 @@ QFontEngineMulti::~QFontEngineMulti()
}
}
+glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
+{
+ glyph_t glyph = engine(0)->glyphIndex(ucs4);
+ if (glyph == 0 && ucs4 != QChar::LineSeparator) {
+ const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
+ for (int x = 1, n = qMin(engines.size(), 256); x < n; ++x) {
+ QFontEngine *engine = engines.at(x);
+ if (!engine) {
+ if (!shouldLoadFontEngineForCharacter(x, ucs4))
+ continue;
+ const_cast<QFontEngineMulti *>(this)->loadEngine(x);
+ engine = engines.at(x);
+ }
+ Q_ASSERT(engine != 0);
+ if (engine->type() == Box)
+ continue;
+
+ glyph = engine->glyphIndex(ucs4);
+ if (glyph != 0) {
+ // set the high byte to indicate which engine the glyph came from
+ glyph |= (x << 24);
+ break;
+ }
+ }
+ }
+
+ return glyph;
+}
+
bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
QGlyphLayout *glyphs, int *nglyphs,
QFontEngine::ShaperFlags flags) const
@@ -1573,13 +1594,10 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
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) {
- QFixed tmpAdvance;
- if (!(flags & GlyphIndicesOnly))
- tmpAdvance = glyphs->advances[glyph_pos];
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ const uint ucs4 = it.peekNext();
+ if (glyphs->glyphs[glyph_pos] == 0 && ucs4 != QChar::LineSeparator) {
for (int x = 1, n = qMin(engines.size(), 256); x < n; ++x) {
if (engines.at(x) == 0 && !shouldLoadFontEngineForCharacter(x, ucs4))
continue;
@@ -1593,27 +1611,21 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
if (engine->type() == Box)
continue;
- if (!(flags & GlyphIndicesOnly))
- glyphs->advances[glyph_pos] = QFixed();
- int num = 2;
- QGlyphLayout g = glyphs->mid(glyph_pos, num);
- if (!engine->stringToCMap(str + i, surrogate ? 2 : 1, &g, &num, flags))
- Q_UNREACHABLE();
- Q_ASSERT(num == 1);
- if (glyphs->glyphs[glyph_pos]) {
+ glyph_t glyph = engine->glyphIndex(ucs4);
+ if (glyph != 0) {
+ glyphs->glyphs[glyph_pos] = glyph;
+ if (!(flags & GlyphIndicesOnly)) {
+ QGlyphLayout g = glyphs->mid(glyph_pos, 1);
+ engine->recalcAdvances(&g, flags);
+ }
// set the high byte to indicate which engine the glyph came from
glyphs->glyphs[glyph_pos] |= (x << 24);
break;
}
}
-
- // ensure we use metrics from the 1st font when we use the fallback image.
- if (!(flags & GlyphIndicesOnly) && glyphs->glyphs[glyph_pos] == 0)
- glyphs->advances[glyph_pos] = tmpAdvance;
}
- if (surrogate)
- ++i;
+ it.advance();
++glyph_pos;
}
@@ -1898,7 +1910,7 @@ qreal QFontEngineMulti::minRightBearing() const
return engine(0)->minRightBearing();
}
-bool QFontEngineMulti::canRender(const QChar *string, int len)
+bool QFontEngineMulti::canRender(const QChar *string, int len) const
{
if (engine(0)->canRender(string, len))
return true;
@@ -1959,13 +1971,4 @@ QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosit
return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);
}
-QTestFontEngine::QTestFontEngine(int size)
- : QFontEngineBox(size)
-{}
-
-QFontEngine::Type QTestFontEngine::type() const
-{
- return TestFontEngine;
-}
-
QT_END_NAMESPACE
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index c13f60ff69..11e9ce6c02 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -45,6 +45,7 @@
#include "qvariant.h"
#include "qfontengine_ft_p.h"
#include "private/qimage_p.h"
+#include <private/qstringiterator_p.h>
#ifndef QT_NO_FREETYPE
@@ -125,6 +126,7 @@ static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *leng
FT_ULong len = *length;
result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
*length = len;
+ Q_ASSERT(!result || int(*length) > 0);
}
return result;
@@ -634,6 +636,7 @@ static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height,
}
QFontEngineFT::QFontEngineFT(const QFontDef &fd)
+ : QFontEngine(Freetype)
{
fontDef = fd;
matrix.xx = 0x10000;
@@ -1281,22 +1284,10 @@ qreal QFontEngineFT::minRightBearing() const
{
if (rbearing == SHRT_MIN) {
lbearing = rbearing = 0;
-
- const QChar *ch = reinterpret_cast<const QChar *>(char_table);
-
- glyph_t glyphs[char_table_entries];
-
- QGlyphLayout g;
- g.glyphs = glyphs;
- g.numGlyphs = char_table_entries;
- int ng = char_table_entries;
- if (!stringToCMap(ch, char_table_entries, &g, &ng, GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(ng == char_table_entries);
-
- while (--ng) {
- if (glyphs[ng]) {
- glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs[ng]);
+ for (int i = 0; i < char_table_entries; ++i) {
+ const glyph_t glyph = glyphIndex(char_table[i]);
+ if (glyph != 0) {
+ glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyph);
lbearing = qMin(lbearing, gi.x);
rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
}
@@ -1457,29 +1448,6 @@ bool QFontEngineFT::supportsTransformation(const QTransform &transform) const
return transform.type() <= QTransform::TxTranslate;
}
-static inline unsigned int getChar(const QChar *str, int &i, const int len)
-{
- uint ucs4 = str[i].unicode();
- if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
- ++i;
- ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
- }
- return ucs4;
-}
-
-bool QFontEngineFT::canRender(const QChar *string, int len)
-{
- FT_Face face = freetype->face;
- {
- for ( int i = 0; i < len; i++ ) {
- unsigned int uc = getChar(string, i, len);
- if (!FT_Get_Char_Index(face, uc))
- return false;
- }
- }
- return true;
-}
-
void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
{
if (!glyphs.numGlyphs)
@@ -1524,9 +1492,40 @@ void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int
unlockFace();
}
+glyph_t QFontEngineFT::glyphIndex(uint ucs4) const
+{
+ glyph_t glyph = ucs4 < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[ucs4] : 0;
+ if (glyph == 0) {
+ FT_Face face = freetype->face;
+ glyph = FT_Get_Char_Index(face, ucs4);
+ if (glyph == 0) {
+ // Certain fonts don't have no-break space and tab,
+ // while we usually want to render them as space
+ if (ucs4 == QChar::Nbsp || ucs4 == QChar::Tabulation) {
+ glyph = FT_Get_Char_Index(face, QChar::Space);
+ } else if (freetype->symbol_map) {
+ // Symbol fonts can have more than one CMAPs, FreeType should take the
+ // correct one for us by default, so we always try FT_Get_Char_Index
+ // first. If it didn't work (returns 0), we will explicitly set the
+ // CMAP to symbol font one and try again. symbol_map is not always the
+ // correct one because in certain fonts like Wingdings symbol_map only
+ // contains PUA codepoints instead of the common ones.
+ FT_Set_Charmap(face, freetype->symbol_map);
+ glyph = FT_Get_Char_Index(face, ucs4);
+ FT_Set_Charmap(face, freetype->unicode_map);
+ }
+ }
+ if (ucs4 < QFreetypeFace::cmapCacheSize)
+ freetype->cmapCache[ucs4] = glyph;
+ }
+
+ return glyph;
+}
+
bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
QFontEngine::ShaperFlags flags) const
{
+ Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
return false;
@@ -1535,8 +1534,9 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
int glyph_pos = 0;
if (freetype->symbol_map) {
FT_Face face = freetype->face;
- for ( int i = 0; i < len; ++i ) {
- unsigned int uc = getChar(str, i, len);
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ uint uc = it.next();
glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
if ( !glyphs->glyphs[glyph_pos] ) {
// Symbol fonts can have more than one CMAPs, FreeType should take the
@@ -1565,8 +1565,9 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
}
} else {
FT_Face face = freetype->face;
- for (int i = 0; i < len; ++i) {
- unsigned int uc = getChar(str, i, len);
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ uint uc = it.next();
glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
if (!glyphs->glyphs[glyph_pos]) {
{
diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h
index ad1598ba6d..8bdf991174 100644
--- a/src/gui/text/qfontengine_ft_p.h
+++ b/src/gui/text/qfontengine_ft_p.h
@@ -225,19 +225,13 @@ private:
virtual QFixed lineThickness() const;
virtual QFixed underlinePosition() const;
+ virtual glyph_t glyphIndex(uint ucs4) const;
void doKerning(QGlyphLayout *, ShaperFlags) const;
- inline virtual Type type() const
- { return QFontEngine::Freetype; }
- inline virtual const char *name() const
- { return "freetype"; }
-
virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics);
virtual bool supportsTransformation(const QTransform &transform) const;
- virtual bool canRender(const QChar *string, int len);
-
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
QPainterPath *path, QTextItem::RenderFlags flags);
virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 0bfb9e70e2..5e40abbda6 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -125,9 +125,10 @@ public:
};
Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
- QFontEngine();
virtual ~QFontEngine();
+ inline Type type() const { return m_type; }
+
// all of these are in unscaled metrics if the engine supports uncsaled metrics,
// otherwise in design metrics
struct Properties {
@@ -144,8 +145,8 @@ public:
};
virtual Properties properties() const;
virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics);
- QByteArray getSfntTable(uint /*tag*/) const;
- virtual bool getSfntTableData(uint /*tag*/, uchar * /*buffer*/, uint * /*length*/) const { return false; }
+ QByteArray getSfntTable(uint tag) const;
+ virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
struct FaceId {
FaceId() : index(0), encoding(0) {}
@@ -167,6 +168,7 @@ public:
virtual QFixed emSquareSize() const { return ascent(); }
/* returns 0 as glyph index for non existent glyphs */
+ virtual glyph_t glyphIndex(uint ucs4) const = 0;
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0;
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const {}
virtual void doKerning(QGlyphLayout *, ShaperFlags) const;
@@ -224,26 +226,11 @@ public:
virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0);
- virtual const char *name() const = 0;
-
- virtual bool canRender(const QChar *string, int len) = 0;
- inline bool canRender(uint ucs4) {
- QChar utf16[2];
- int utf16len = 1;
- if (QChar::requiresSurrogates(ucs4)) {
- utf16[0] = QChar::highSurrogate(ucs4);
- utf16[1] = QChar::lowSurrogate(ucs4);
- ++utf16len;
- } else {
- utf16[0] = QChar(ucs4);
- }
- return canRender(utf16, utf16len);
- }
+ inline bool canRender(uint ucs4) const { return glyphIndex(ucs4) != 0; }
+ virtual bool canRender(const QChar *str, int len) const;
virtual bool supportsTransformation(const QTransform &transform) const;
- virtual Type type() const = 0;
-
virtual int glyphCount() const;
virtual int glyphMargin(GlyphFormat format) { return format == Format_A32 ? 2 : 0; }
@@ -272,6 +259,10 @@ public:
};
virtual void setDefaultHintStyle(HintStyle) { }
+private:
+ const Type m_type;
+
+public:
QAtomicInt ref;
QFontDef fontDef;
@@ -306,6 +297,8 @@ public:
inline QVariant userData() const { return m_userData; }
protected:
+ explicit QFontEngine(Type type);
+
QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round = false);
inline void setUserData(const QVariant &userData) { m_userData = userData; }
@@ -352,6 +345,7 @@ public:
QFontEngineBox(int size);
~QFontEngineBox();
+ virtual glyph_t glyphIndex(uint ucs4) const;
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const;
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const;
@@ -370,13 +364,13 @@ public:
virtual qreal minRightBearing() const { return 0; }
virtual QImage alphaMapForGlyph(glyph_t);
- virtual const char *name() const;
-
- virtual bool canRender(const QChar *string, int len);
+ virtual bool canRender(const QChar *string, int len) const;
- virtual Type type() const;
inline int size() const { return _size; }
+protected:
+ explicit QFontEngineBox(Type type, int size);
+
private:
friend class QFontPrivate;
int _size;
@@ -388,6 +382,7 @@ public:
explicit QFontEngineMulti(int engineCount);
~QFontEngineMulti();
+ virtual glyph_t glyphIndex(uint ucs4) const;
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const;
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs);
@@ -415,12 +410,7 @@ public:
virtual qreal minLeftBearing() const;
virtual qreal minRightBearing() const;
- virtual inline Type type() const
- { return QFontEngine::Multi; }
-
- virtual bool canRender(const QChar *string, int len);
- inline virtual const char *name() const
- { return "Multi"; }
+ virtual bool canRender(const QChar *string, int len) const;
QFontEngine *engine(int at) const
{Q_ASSERT(at < engines.size()); return engines.at(at); }
@@ -444,8 +434,7 @@ protected:
class QTestFontEngine : public QFontEngineBox
{
public:
- QTestFontEngine(int size);
- virtual Type type() const;
+ inline QTestFontEngine(int size) : QFontEngineBox(TestFontEngine, size) {}
};
QT_END_NAMESPACE
diff --git a/src/gui/text/qfontengine_qpa.cpp b/src/gui/text/qfontengine_qpa.cpp
index cb40a5388a..f9ed3c38c1 100644
--- a/src/gui/text/qfontengine_qpa.cpp
+++ b/src/gui/text/qfontengine_qpa.cpp
@@ -45,6 +45,7 @@
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QBuffer>
+#include <QtCore/private/qstringiterator_p.h>
#include <QtGui/private/qpaintengine_raster_p.h>
#include <QtGui/private/qguiapplication_p.h>
@@ -225,23 +226,13 @@ QVariant QFontEngineQPA::extractHeaderField(const uchar *data, HeaderTag request
}
-
-static inline unsigned int getChar(const QChar *str, int &i, const int len)
-{
- uint ucs4 = str[i].unicode();
- if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
- ++i;
- ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
- }
- return ucs4;
-}
-
QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
- : fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
+ : QFontEngine(QPF2),
+ fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
{
fontDef = def;
cache_cost = 100;
- externalCMap = 0;
+ cmap = 0;
cmapOffset = 0;
cmapSize = 0;
glyphMapOffset = 0;
@@ -292,15 +283,8 @@ QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
// get the real cmap
if (cmapOffset) {
- int tableSize = cmapSize;
- const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
- if (cmapPtr)
- cmapOffset = cmapPtr - fontData;
- else
- cmapOffset = 0;
- } else if (externalCMap) {
- int tableSize = cmapSize;
- externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
+ cmap = QFontEngine::getCMap(fontData + cmapOffset, cmapSize, &symbol, &cmapSize);
+ cmapOffset = cmap ? cmap - fontData : 0;
}
// verify all the positions in the glyphMap
@@ -322,7 +306,7 @@ QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
#if defined(DEBUG_FONTENGINE)
if (!isValid())
qDebug() << "fontData" << fontData << "dataSize" << dataSize
- << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
+ << "cmap" << cmap << "cmapOffset" << cmapOffset
<< "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
<< "fd" << fd << "glyphDataSize" << glyphDataSize;
#endif
@@ -334,14 +318,30 @@ QFontEngineQPA::~QFontEngineQPA()
bool QFontEngineQPA::getSfntTableData(uint tag, uchar *buffer, uint *length) const
{
- Q_UNUSED(tag);
- Q_UNUSED(buffer);
- *length = 0;
- return false;
+ if (tag != MAKE_TAG('c', 'm', 'a', 'p') || !cmap)
+ return false;
+
+ if (buffer && int(*length) >= cmapSize)
+ memcpy(buffer, cmap, cmapSize);
+ *length = cmapSize;
+ Q_ASSERT(int(*length) > 0);
+ return true;
+}
+
+glyph_t QFontEngineQPA::glyphIndex(uint ucs4) const
+{
+ glyph_t glyph = getTrueTypeGlyphIndex(cmap, ucs4);
+ if (glyph == 0 && symbol && ucs4 < 0x100)
+ glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000);
+ if (!findGlyph(glyph))
+ glyph = 0;
+
+ return glyph;
}
bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
{
+ Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
return false;
@@ -351,20 +351,20 @@ bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
QSet<QChar> seenGlyphs;
#endif
- const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
-
int glyph_pos = 0;
if (symbol) {
- for (int i = 0; i < len; ++i) {
- unsigned int uc = getChar(str, i, len);
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ const uint uc = it.next();
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
++glyph_pos;
}
} else {
- for (int i = 0; i < len; ++i) {
- unsigned int uc = getChar(str, i, len);
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ const uint uc = it.next();
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
#if 0 && defined(DEBUG_FONTENGINE)
QChar c(uc);
@@ -390,10 +390,8 @@ void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFla
{
for (int i = 0; i < glyphs->numGlyphs; ++i) {
const Glyph *g = findGlyph(glyphs->glyphs[i]);
- if (!g) {
- glyphs->glyphs[i] = 0;
+ if (!g)
continue;
- }
glyphs->advances[i] = g->advance;
}
}
@@ -498,37 +496,9 @@ QFixed QFontEngineQPA::lineThickness() const
return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
}
-QFontEngine::Type QFontEngineQPA::type() const
-{
- return QFontEngine::QPF2;
-}
-
-bool QFontEngineQPA::canRender(const QChar *string, int len)
-{
- const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
-
- if (symbol) {
- for (int i = 0; i < len; ++i) {
- unsigned int uc = getChar(string, i, len);
- glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
- if(!g && uc < 0x100)
- g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
- if (!g)
- return false;
- }
- } else {
- for (int i = 0; i < len; ++i) {
- unsigned int uc = getChar(string, i, len);
- if (!getTrueTypeGlyphIndex(cmap, uc))
- return false;
- }
- }
- return true;
-}
-
bool QFontEngineQPA::isValid() const
{
- return fontData && dataSize && (cmapOffset || externalCMap)
+ return fontData && dataSize && cmapOffset
&& glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
}
@@ -563,11 +533,9 @@ void QPAGenerator::writeHeader()
writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index);
{
- uchar data[4];
- uint len = 4;
- bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
- if (ok) {
- const quint32 revision = qFromBigEndian<quint32>(data);
+ const QByteArray head = fe->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd'));
+ if (head.size() >= 4) {
+ const quint32 revision = qFromBigEndian<quint32>(reinterpret_cast<const uchar *>(head.constData()));
writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision);
}
}
@@ -748,10 +716,9 @@ QFontEngine* QFontEngineMultiQPA::createMultiFontEngine(QFontEngine *fe, int scr
QFontCache::EngineCache::Iterator it = fc->engineCache.find(key),
end = fc->engineCache.end();
while (it != end && it.key() == key) {
- QFontEngineMulti *cachedEngine = 0;
- if (it.value().data->type() == QFontEngine::Multi)
- cachedEngine = static_cast<QFontEngineMulti *>(it.value().data);
- if (faceIsLocal || (cachedEngine && fe == cachedEngine->engine(0))) {
+ Q_ASSERT(it.value().data->type() == QFontEngine::Multi);
+ QFontEngineMulti *cachedEngine = static_cast<QFontEngineMulti *>(it.value().data);
+ if (faceIsLocal || fe == cachedEngine->engine(0)) {
engine = cachedEngine;
fc->updateHitCountAndTimeStamp(it.value());
break;
diff --git a/src/gui/text/qfontengine_qpa_p.h b/src/gui/text/qfontengine_qpa_p.h
index c8b40abd7f..e84b067c68 100644
--- a/src/gui/text/qfontengine_qpa_p.h
+++ b/src/gui/text/qfontengine_qpa_p.h
@@ -163,6 +163,7 @@ public:
FaceId faceId() const { return face_id; }
bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
+ virtual glyph_t glyphIndex(uint ucs4) const;
bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const;
void recalcAdvances(QGlyphLayout *, ShaperFlags) const;
@@ -181,11 +182,6 @@ public:
QFixed underlinePosition() const;
QFixed lineThickness() const;
- Type type() const;
-
- bool canRender(const QChar *string, int len);
- inline const char *name() const { return "QPF2"; }
-
virtual int glyphCount() const { return glyphMapEntries; }
bool isValid() const;
@@ -199,7 +195,7 @@ private:
const uchar *fontData;
int dataSize;
- const uchar *externalCMap;
+ const uchar *cmap;
quint32 cmapOffset;
int cmapSize;
quint32 glyphMapOffset;
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index 2f4709afe4..7868fd23d1 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -410,12 +410,7 @@ int QFontMetrics::averageCharWidth() const
*/
bool QFontMetrics::inFont(QChar ch) const
{
- const int script = ch.script();
- QFontEngine *engine = d->engineForScript(script);
- Q_ASSERT(engine != 0);
- if (engine->type() == QFontEngine::Box)
- return false;
- return engine->canRender(&ch, 1);
+ return inFontUcs4(ch.unicode());
}
/*!
@@ -458,16 +453,7 @@ int QFontMetrics::leftBearing(QChar ch) const
d->alterCharForCapitalization(ch);
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ glyph_t glyph = engine->glyphIndex(ch.unicode());
qreal lb;
engine->getGlyphBearings(glyph, &lb);
@@ -500,16 +486,7 @@ int QFontMetrics::rightBearing(QChar ch) const
d->alterCharForCapitalization(ch);
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ glyph_t glyph = engine->glyphIndex(ch.unicode());
qreal rb;
engine->getGlyphBearings(glyph, 0, &rb);
@@ -605,18 +582,14 @@ int QFontMetrics::width(QChar ch) const
d->alterCharForCapitalization(ch);
+ glyph_t glyph = engine->glyphIndex(ch.unicode());
QFixed advance;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
- glyph_t glyph;
glyphs.glyphs = &glyph;
glyphs.advances = &advance;
-
- int nglyphs = 1;
- if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ engine->recalcAdvances(&glyphs, 0);
return qRound(advance);
}
@@ -660,18 +633,14 @@ int QFontMetrics::charWidth(const QString &text, int pos) const
d->alterCharForCapitalization(ch);
+ glyph_t glyph = engine->glyphIndex(ch.unicode());
QFixed advance;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
- glyph_t glyph;
glyphs.glyphs = &glyph;
glyphs.advances = &advance;
-
- int nglyphs = 1;
- if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ engine->recalcAdvances(&glyphs, 0);
width = qRound(advance);
}
@@ -739,16 +708,7 @@ QRect QFontMetrics::boundingRect(QChar ch) const
d->alterCharForCapitalization(ch);
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ glyph_t glyph = engine->glyphIndex(ch.unicode());
glyph_metrics_t gm = engine->boundingBox(glyph);
return QRect(qRound(gm.x), qRound(gm.y), qRound(gm.width), qRound(gm.height));
@@ -1315,12 +1275,7 @@ qreal QFontMetricsF::averageCharWidth() const
*/
bool QFontMetricsF::inFont(QChar ch) const
{
- const int script = ch.script();
- QFontEngine *engine = d->engineForScript(script);
- Q_ASSERT(engine != 0);
- if (engine->type() == QFontEngine::Box)
- return false;
- return engine->canRender(&ch, 1);
+ return inFontUcs4(ch.unicode());
}
/*!
@@ -1365,16 +1320,7 @@ qreal QFontMetricsF::leftBearing(QChar ch) const
d->alterCharForCapitalization(ch);
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ glyph_t glyph = engine->glyphIndex(ch.unicode());
qreal lb;
engine->getGlyphBearings(glyph, &lb);
@@ -1407,16 +1353,7 @@ qreal QFontMetricsF::rightBearing(QChar ch) const
d->alterCharForCapitalization(ch);
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ glyph_t glyph = engine->glyphIndex(ch.unicode());
qreal rb;
engine->getGlyphBearings(glyph, 0, &rb);
@@ -1484,18 +1421,14 @@ qreal QFontMetricsF::width(QChar ch) const
d->alterCharForCapitalization(ch);
+ glyph_t glyph = engine->glyphIndex(ch.unicode());
QFixed advance;
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
- glyph_t glyph;
glyphs.glyphs = &glyph;
glyphs.advances = &advance;
-
- int nglyphs = 1;
- if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ engine->recalcAdvances(&glyphs, 0);
return advance.toReal();
}
@@ -1559,16 +1492,7 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const
d->alterCharForCapitalization(ch);
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ glyph_t glyph = engine->glyphIndex(ch.unicode());
glyph_metrics_t gm = engine->boundingBox(glyph);
return QRectF(gm.x.toReal(), gm.y.toReal(), gm.width.toReal(), gm.height.toReal());
diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp
index 2109b16bb5..4bb29da2af 100644
--- a/src/gui/text/qfontsubset.cpp
+++ b/src/gui/text/qfontsubset.cpp
@@ -201,22 +201,8 @@ static void checkRanges(QPdf::ByteStream &ts, QByteArray &ranges, int &nranges)
QVector<int> QFontSubset::getReverseMap() const
{
QVector<int> reverseMap(0x10000, 0);
-
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.glyphs = &glyph;
- glyphs.numGlyphs = 1;
-
for (uint uc = 0; uc < 0x10000; ++uc) {
- QChar ch(uc);
-
- int nglyphs = 1;
- if (!fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
-
- int idx = glyph_indices.indexOf(glyph);
+ int idx = glyph_indices.indexOf(fontEngine->glyphIndex(uc));
if (idx >= 0 && !reverseMap.at(idx))
reverseMap[idx] = uc;
}
diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp
index c09f27b665..1258ea9a78 100644
--- a/src/gui/text/qharfbuzzng.cpp
+++ b/src/gui/text/qharfbuzzng.cpp
@@ -45,6 +45,8 @@
#include <qstring.h>
#include <qvector.h>
+#include <private/qstringiterator_p.h>
+
#include "qfontengine_p.h"
QT_BEGIN_NAMESPACE
@@ -341,16 +343,10 @@ _hb_qt_unicode_decompose_compatibility(hb_unicode_funcs_t * /*ufuncs*/,
const QString normalized = QChar::decomposition(u);
uint outlen = 0;
-
- // ### replace with QCharIterator
- const ushort *p = reinterpret_cast<const ushort *>(normalized.unicode());
- const ushort *const e = p + normalized.size();
- for ( ; p != e; ++p) {
- uint ucs4 = *p;
- if (QChar::isHighSurrogate(ucs4) && p + 1 != e && QChar::isLowSurrogate(p[1]))
- ucs4 = QChar::surrogateToUcs4(ucs4, *++p);
+ QStringIterator it(normalized);
+ while (it.hasNext()) {
Q_ASSERT(outlen < HB_UNICODE_MAX_DECOMPOSITION_LEN);
- decomposed[outlen++] = ucs4;
+ decomposed[outlen++] = it.next();
}
return outlen;
@@ -397,33 +393,7 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data,
QFontEngine *fe = (QFontEngine *)font_data;
Q_ASSERT(fe);
- QChar chars[2];
- int numChars = 0;
- if (Q_UNLIKELY(QChar::requiresSurrogates(unicode))) {
- chars[numChars++] = QChar(QChar::highSurrogate(unicode));
- chars[numChars++] = QChar(QChar::lowSurrogate(unicode));
- } else {
- chars[numChars++] = QChar(unicode);
- }
-#if 0
- if (Q_UNLIKELY(variation_selector != 0)) {
- if (Q_UNLIKELY(QChar::requiresSurrogates(variation_selector))) {
- chars[numChars++] = QChar(QChar::highSurrogate(variation_selector));
- chars[numChars++] = QChar(QChar::lowSurrogate(variation_selector));
- } else {
- chars[numChars++] = QChar(variation_selector);
- }
- }
-#endif
-
- QGlyphLayout g;
- g.numGlyphs = numChars;
- g.glyphs = glyph;
-
- int numGlyphs = numChars;
- if (!fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(numGlyphs == 1);
+ *glyph = fe->glyphIndex(unicode);
return true;
}
@@ -625,7 +595,7 @@ _hb_qt_reference_table(hb_face_t * /*face*/, hb_tag_t tag, void *user_data)
Q_ASSERT(get_font_table);
uint length = 0;
- if (Q_UNLIKELY(!get_font_table(data->user_data, tag, 0, &length) || length == 0))
+ if (Q_UNLIKELY(!get_font_table(data->user_data, tag, 0, &length)))
return hb_blob_get_empty();
char *buffer = (char *)malloc(length);
diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp
index 3049e0ab5e..5f277c878a 100644
--- a/src/gui/text/qplatformfontdatabase.cpp
+++ b/src/gui/text/qplatformfontdatabase.cpp
@@ -276,6 +276,16 @@ void QPlatformFontDatabase::populateFontDatabase()
}
/*!
+ This function is called whenever the font database is invalidated.
+
+ Reimplement this function to clear any internal data structures that
+ will need to be rebuilt at the next call to populateFontDatabase().
+*/
+void QPlatformFontDatabase::invalidate()
+{
+}
+
+/*!
Returns a multi font engine in the specified \a script to encapsulate \a fontEngine with the
option to fall back to the fonts given by \a fallbacks if \a fontEngine does not support
a certain character.
diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h
index 5f2c9a74ba..870480809b 100644
--- a/src/gui/text/qplatformfontdatabase.h
+++ b/src/gui/text/qplatformfontdatabase.h
@@ -96,6 +96,8 @@ class Q_GUI_EXPORT QPlatformFontDatabase
public:
virtual ~QPlatformFontDatabase();
virtual void populateFontDatabase();
+ virtual void invalidate();
+
virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script);
virtual QFontEngine *fontEngine(const QFontDef &fontDef, void *handle);
virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const;
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
index 449278df06..2ba350fb67 100644
--- a/src/gui/text/qrawfont.cpp
+++ b/src/gui/text/qrawfont.cpp
@@ -665,7 +665,7 @@ QList<QFontDatabase::WritingSystem> QRawFont::supportedWritingSystems() const
*/
bool QRawFont::supportsCharacter(QChar character) const
{
- return d->isValid() && d->fontEngine->canRender(&character, 1);
+ return supportsCharacter(character.unicode());
}
/*!
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 63e2af8d15..0298adde7a 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -839,6 +839,22 @@ void QTextEngine::bidiReorder(int numItems, const quint8 *levels, int *visualOrd
#endif
}
+
+enum JustificationClass {
+ Justification_Prohibited = 0, // Justification can not be applied after this glyph
+ Justification_Arabic_Space = 1, // This glyph represents a space inside arabic text
+ Justification_Character = 2, // Inter-character justification point follows this glyph
+ Justification_Space = 4, // This glyph represents a blank outside an Arabic run
+ Justification_Arabic_Normal = 7, // Normal Middle-Of-Word glyph that connects to the right (begin)
+ Justification_Arabic_Waw = 8, // Next character is final form of Waw/Ain/Qaf/Feh
+ Justification_Arabic_BaRa = 9, // Next two characters are Ba + Ra/Ya/AlefMaksura
+ Justification_Arabic_Alef = 10, // Next character is final form of Alef/Tah/Lam/Kaf/Gaf
+ Justification_Arabic_HahDal = 11, // Next character is final form of Hah/Dal/Teh Marbuta
+ Justification_Arabic_Seen = 12, // Initial or medial form of Seen/Sad
+ Justification_Arabic_Kashida = 13 // User-inserted Kashida(U+0640)
+};
+
+
// shape all the items that intersect with the line, taking tab widths into account to find out what text actually fits in the line.
void QTextEngine::shapeLine(const QScriptLine &line)
{
@@ -1018,12 +1034,12 @@ void QTextEngine::shapeText(int item) const
}
if (wordSpacing != 0) {
for (int i = 0; i < si.num_glyphs; ++i) {
- if (glyphs.attributes[i].justification == QGlyphAttributes::Space
- || glyphs.attributes[i].justification == QGlyphAttributes::Arabic_Space) {
+ if (glyphs.attributes[i].justification == Justification_Space
+ || glyphs.attributes[i].justification == Justification_Arabic_Space) {
// word spacing only gets added once to a consecutive run of spaces (see CSS spec)
if (i + 1 == si.num_glyphs
- ||(glyphs.attributes[i+1].justification != QGlyphAttributes::Space
- && glyphs.attributes[i+1].justification != QGlyphAttributes::Arabic_Space))
+ ||(glyphs.attributes[i+1].justification != Justification_Space
+ && glyphs.attributes[i+1].justification != Justification_Arabic_Space))
glyphs.advances[i] += wordSpacing;
}
}
@@ -1190,7 +1206,6 @@ QT_BEGIN_INCLUDE_NAMESPACE
QT_END_INCLUDE_NAMESPACE
Q_STATIC_ASSERT(sizeof(HB_Glyph) == sizeof(glyph_t));
-Q_STATIC_ASSERT(sizeof(HB_GlyphAttributes) == sizeof(QGlyphAttributes));
Q_STATIC_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed));
Q_STATIC_ASSERT(sizeof(HB_FixedPoint) == sizeof(QFixedPoint));
@@ -1256,18 +1271,23 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri
remaining_glyphs -= shaper_item.initialGlyphCount;
+ QVarLengthArray<HB_GlyphAttributes, 128> hbGlyphAttributes;
do {
if (!ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs))
return 0;
+ if (hbGlyphAttributes.size() < int(shaper_item.num_glyphs)) {
+ hbGlyphAttributes.resize(shaper_item.num_glyphs);
+ memset(hbGlyphAttributes.data(), 0, hbGlyphAttributes.size() * sizeof(HB_GlyphAttributes));
+ }
const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos);
if (fontEngine->type() == QFontEngine::Multi && shaper_item.num_glyphs > shaper_item.item.length)
moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);
shaper_item.glyphs = reinterpret_cast<HB_Glyph *>(g.glyphs);
- shaper_item.attributes = reinterpret_cast<HB_GlyphAttributes *>(g.attributes);
shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances);
shaper_item.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets);
+ shaper_item.attributes = hbGlyphAttributes.data();
if (engineIdx != 0 && shaper_item.glyphIndicesPresent) {
for (quint32 i = 0; i < shaper_item.initialGlyphCount; ++i)
@@ -1281,6 +1301,14 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri
if (fontEngine->type() == QFontEngine::Multi)
moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);
+ for (quint32 i = 0; i < shaper_item.num_glyphs; ++i) {
+ HB_GlyphAttributes hbAttrs = hbGlyphAttributes.at(i);
+ QGlyphAttributes &attrs = g.attributes[i];
+ attrs.clusterStart = hbAttrs.clusterStart;
+ attrs.dontPrint = hbAttrs.dontPrint;
+ attrs.justification = hbAttrs.justification;
+ }
+
for (quint32 i = 0; i < shaper_item.item.length; ++i)
shaper_item.log_clusters[i] += glyph_pos;
@@ -1478,18 +1506,8 @@ void QTextEngine::itemize() const
{
QVarLengthArray<uchar> scripts(length);
QUnicodeTools::initScripts(string, length, scripts.data());
- for (int i = 0; i < length; ++i) {
- ushort script = scripts.at(i);
- switch (script) {
- case QChar::Script_Hiragana:
- case QChar::Script_Katakana:
- script = QChar::Script_Han;
- break;
- default:
- break;
- }
- analysis[i].script = script;
- }
+ for (int i = 0; i < length; ++i)
+ analysis[i].script = scripts.at(i);
}
const ushort *uc = string;
@@ -1536,8 +1554,21 @@ void QTextEngine::itemize() const
(analysis-1)->flags = QScriptAnalysis::LineOrParagraphSeparator; // to exclude it from width
}
#ifdef QT_ENABLE_HARFBUZZ_NG
- if (!useHarfbuzzNG) {
- analysis = scriptAnalysis.data();
+ analysis = scriptAnalysis.data();
+ if (useHarfbuzzNG) {
+ for (int i = 0; i < length; ++i) {
+ switch (analysis[i].script) {
+ case QChar::Script_Han:
+ case QChar::Script_Hiragana:
+ case QChar::Script_Katakana:
+ case QChar::Script_Bopomofo:
+ analysis[i].script = QChar::Script_Common;
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
for (int i = 0; i < length; ++i)
analysis[i].script = hbscript_to_script(script_to_hbscript(analysis[i].script));
}
@@ -1980,26 +2011,21 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph,
point->type = type;
point->glyph = glyph;
- if (type >= QGlyphAttributes::Arabic_Normal) {
+ if (type >= Justification_Arabic_Normal) {
QChar ch(0x640); // Kashida character
- glyph_t kashidaGlyph;
- QFixed kashidaWidth;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &kashidaGlyph;
- glyphs.advances = &kashidaWidth;
-
- int nglyphs = 1;
- if (!fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ glyph_t kashidaGlyph = fe->glyphIndex(ch.unicode());
+ if (kashidaGlyph != 0) {
+ QGlyphLayout g;
+ g.numGlyphs = 1;
+ g.glyphs = &kashidaGlyph;
+ g.advances = &point->kashidaWidth;
+ fe->recalcAdvances(&g, 0);
- if (kashidaGlyph != 0 && kashidaWidth != 0) {
- point->kashidaWidth = kashidaWidth;
+ if (point->kashidaWidth == 0)
+ point->type = Justification_Prohibited;
} else {
- point->type = QGlyphAttributes::NoJustification;
+ point->type = Justification_Prohibited;
point->kashidaWidth = 0;
}
}
@@ -2067,7 +2093,7 @@ void QTextEngine::justify(const QScriptLine &line)
for (int i = 0; i < nItems; ++i) {
QScriptItem &si = layoutData->items[firstItem + i];
- int kashida_type = QGlyphAttributes::Arabic_Normal;
+ int kashida_type = Justification_Arabic_Normal;
int kashida_pos = -1;
int start = qMax(line.from - si.position, 0);
@@ -2091,11 +2117,11 @@ void QTextEngine::justify(const QScriptLine &line)
int justification = g.attributes[i].justification;
switch(justification) {
- case QGlyphAttributes::NoJustification:
+ case Justification_Prohibited:
break;
- case QGlyphAttributes::Space :
+ case Justification_Space:
// fall through
- case QGlyphAttributes::Arabic_Space :
+ case Justification_Arabic_Space:
if (kashida_pos >= 0) {
// qDebug("kashida position at %d in word", kashida_pos);
set(&justificationPoints[nPoints], kashida_type, g.mid(kashida_pos), fontEngine(si));
@@ -2106,19 +2132,19 @@ void QTextEngine::justify(const QScriptLine &line)
}
}
kashida_pos = -1;
- kashida_type = QGlyphAttributes::Arabic_Normal;
+ kashida_type = Justification_Arabic_Normal;
// fall through
- case QGlyphAttributes::Character :
+ case Justification_Character:
set(&justificationPoints[nPoints++], justification, g.mid(i), fontEngine(si));
maxJustify = qMax(maxJustify, justification);
break;
- case QGlyphAttributes::Arabic_Normal :
- case QGlyphAttributes::Arabic_Waw :
- case QGlyphAttributes::Arabic_BaRa :
- case QGlyphAttributes::Arabic_Alef :
- case QGlyphAttributes::Arabic_HaaDal :
- case QGlyphAttributes::Arabic_Seen :
- case QGlyphAttributes::Arabic_Kashida :
+ case Justification_Arabic_Normal:
+ case Justification_Arabic_Waw:
+ case Justification_Arabic_BaRa:
+ case Justification_Arabic_Alef:
+ case Justification_Arabic_HahDal:
+ case Justification_Arabic_Seen:
+ case Justification_Arabic_Kashida:
if (justification >= kashida_type) {
kashida_pos = i;
kashida_type = justification;
@@ -2147,9 +2173,9 @@ void QTextEngine::justify(const QScriptLine &line)
// qDebug(" minKashida=%f, need=%f", minKashida.toReal(), need.toReal());
// distribute in priority order
- if (maxJustify >= QGlyphAttributes::Arabic_Normal) {
+ if (maxJustify >= Justification_Arabic_Normal) {
while (need >= minKashida) {
- for (int type = maxJustify; need >= minKashida && type >= QGlyphAttributes::Arabic_Normal; --type) {
+ for (int type = maxJustify; need >= minKashida && type >= Justification_Arabic_Normal; --type) {
for (int i = 0; need >= minKashida && i < nPoints; ++i) {
if (justificationPoints[i].type == type && justificationPoints[i].kashidaWidth <= need) {
justificationPoints[i].glyph.justifications->nKashidas++;
@@ -2166,7 +2192,7 @@ void QTextEngine::justify(const QScriptLine &line)
if (!need)
goto end;
- maxJustify = qMin(maxJustify, int(QGlyphAttributes::Space));
+ maxJustify = qMin(maxJustify, int(Justification_Space));
for (int type = maxJustify; need != 0 && type > 0; --type) {
int n = 0;
for (int i = 0; i < nPoints; ++i) {
@@ -2616,40 +2642,30 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
QFixed ellipsisWidth;
QString ellipsisText;
{
- QChar ellipsisChar(0x2026);
-
QFontEngine *fe = fnt.d->engineForScript(QChar::Script_Common);
+ QFontEngine *engine = fe->type() == QFontEngine::Multi ? static_cast<QFontEngineMulti *>(fe)->engine(0) : fe;
- QGlyphLayoutArray<1> ellipsisGlyph;
- {
- QFontEngine *feForEllipsis = (fe->type() == QFontEngine::Multi)
- ? static_cast<QFontEngineMulti *>(fe)->engine(0)
- : fe;
+ QChar ellipsisChar(0x2026);
- if (feForEllipsis->type() == QFontEngine::Mac)
- feForEllipsis = fe;
+ glyph_t glyph = engine->glyphIndex(ellipsisChar.unicode());
- int nGlyphs = 1;
- if (!feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0))
- Q_UNREACHABLE();
- Q_ASSERT(nGlyphs == 1);
- }
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyphs.glyphs = &glyph;
+ glyphs.advances = &ellipsisWidth;
+
+ if (glyph != 0) {
+ engine->recalcAdvances(&glyphs, 0);
- if (ellipsisGlyph.glyphs[0]) {
- ellipsisWidth = ellipsisGlyph.advances[0];
ellipsisText = ellipsisChar;
} else {
- QString dotDotDot(QLatin1String("..."));
+ glyph = engine->glyphIndex('.');
+ if (glyph != 0) {
+ engine->recalcAdvances(&glyphs, 0);
- QGlyphLayoutArray<3> glyphs;
- int nGlyphs = 3;
- if (!fe->stringToCMap(dotDotDot.constData(), 3, &glyphs, &nGlyphs, 0))
- Q_UNREACHABLE();
- Q_ASSERT(nGlyphs == 3);
-
- for (int i = 0; i < nGlyphs; ++i)
- ellipsisWidth += glyphs.advances[i];
- ellipsisText = dotDotDot;
+ ellipsisWidth *= 3;
+ ellipsisText = QStringLiteral("...");
+ }
}
}
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index 1616a78937..342a94de66 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -89,35 +89,6 @@ class QAbstractTextDocumentLayout;
typedef quint32 glyph_t;
-#ifdef __xlC__
-typedef unsigned q_hb_bitfield;
-#else
-typedef quint8 q_hb_bitfield;
-#endif
-
-typedef struct {
- typedef enum {
- NoJustification= 0, /* Justification can't be applied after this glyph */
- Arabic_Space = 1, /* This glyph represents a space inside arabic text */
- Character = 2, /* Inter-character justification point follows this glyph */
- Space = 4, /* This glyph represents a blank outside an Arabic run */
- Arabic_Normal = 7, /* Normal Middle-Of-Word glyph that connects to the right (begin) */
- Arabic_Waw = 8, /* Next character is final form of Waw/Ain/Qaf/Fa */
- Arabic_BaRa = 9, /* Next two chars are Ba + Ra/Ya/AlefMaksura */
- Arabic_Alef = 10, /* Next character is final form of Alef/Tah/Lam/Kaf/Gaf */
- Arabic_HaaDal = 11, /* Next character is final form of Haa/Dal/Taa Marbutah */
- Arabic_Seen = 12, /* Initial or Medial form Of Seen/Sad */
- Arabic_Kashida = 13 /* Kashida(U+640) in middle of word */
- } JustificationClass;
-
- q_hb_bitfield justification :4; /* Justification class */
- q_hb_bitfield clusterStart :1; /* First glyph of representation of cluster */
- q_hb_bitfield mark :1; /* needs to be positioned around base char */
- q_hb_bitfield zeroWidth :1; /* ZWJ, ZWNJ etc, with no width */
- q_hb_bitfield dontPrint :1;
- q_hb_bitfield combiningClass :8;
-} QGlyphAttributes;
-
// this uses the same coordinate system as Qt, but a different one to freetype.
// * y is usually negative, and is equal to the ascent.
// * negative yoff means the following stuff is drawn higher up.
@@ -188,6 +159,14 @@ struct QGlyphJustification
};
Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE);
+struct QGlyphAttributes {
+ uchar clusterStart : 1;
+ uchar dontPrint : 1;
+ uchar justification : 4;
+ uchar reserved : 2;
+};
+Q_STATIC_ASSERT(sizeof(QGlyphAttributes) == 1);
+
struct QGlyphLayout
{
enum {
@@ -200,7 +179,7 @@ struct QGlyphLayout
glyph_t *glyphs; // 4 bytes per element
QFixed *advances; // 4 bytes per element
QGlyphJustification *justifications; // 4 bytes per element
- QGlyphAttributes *attributes; // 2 bytes per element
+ QGlyphAttributes *attributes; // 1 byte per element
int numGlyphs;