summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qfont.cpp13
-rw-r--r--src/gui/text/qfont_p.h7
-rw-r--r--src/gui/text/qfontmetrics.cpp44
-rw-r--r--src/gui/text/qfontvariableaxis.cpp38
-rw-r--r--src/gui/text/qtextengine.cpp61
-rw-r--r--src/gui/text/qtextengine_p.h4
6 files changed, 102 insertions, 65 deletions
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index b50dc4a43bf..7bbc9cf63db 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -257,6 +257,19 @@ QFontEngine *QFontPrivate::engineForScript(int script) const
return QT_FONT_ENGINE_FROM_DATA(engineData, script);
}
+QFontEngine *QFontPrivate::engineForCharacter(char32_t c, EngineQueryOptions opt) const
+{
+ const bool smallCaps = !(opt & EngineQueryOption::IgnoreSmallCapsEngine);
+ const auto script = QChar::script(c);
+ QFontEngine *engine;
+ if (smallCaps && capital == QFont::SmallCaps && QChar::isLower(c))
+ engine = smallCapsFontPrivate()->engineForScript(script);
+ else
+ engine = engineForScript(script);
+ Q_ASSERT(engine != nullptr);
+ return engine;
+}
+
void QFontPrivate::alterCharForCapitalization(QChar &c) const {
switch (capital) {
case QFont::AllUppercase:
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index 75550439521..27bc2a6a7cc 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -163,6 +163,11 @@ private:
class Q_GUI_EXPORT QFontPrivate
{
public:
+ enum class EngineQueryOption {
+ Default = 0,
+ IgnoreSmallCapsEngine = 0x1,
+ };
+ Q_DECLARE_FLAGS(EngineQueryOptions, EngineQueryOption)
QFontPrivate();
QFontPrivate(const QFontPrivate &other);
@@ -170,6 +175,7 @@ public:
~QFontPrivate();
QFontEngine *engineForScript(int script) const;
+ QFontEngine *engineForCharacter(char32_t c, EngineQueryOptions opt = {}) const;
void alterCharForCapitalization(QChar &c) const;
QAtomicInt ref;
@@ -208,6 +214,7 @@ public:
void unsetVariableAxis(QFont::Tag tag);
bool hasVariableAxis(QFont::Tag tag, float value) const;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QFontPrivate::EngineQueryOptions)
class Q_GUI_EXPORT QFontCache : public QObject
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index 4ea21c9f0f3..c4403a16c6d 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -410,9 +410,8 @@ bool QFontMetrics::inFont(QChar ch) const
*/
bool QFontMetrics::inFontUcs4(uint ucs4) const
{
- const int script = QChar::script(ucs4);
- QFontEngine *engine = d->engineForScript(script);
- Q_ASSERT(engine != nullptr);
+ constexpr auto Ignore = QFontPrivate::EngineQueryOption::IgnoreSmallCapsEngine;
+ QFontEngine *engine = d->engineForCharacter(ucs4, Ignore);
if (engine->type() == QFontEngine::Box)
return false;
return engine->canRender(ucs4);
@@ -432,13 +431,7 @@ bool QFontMetrics::inFontUcs4(uint ucs4) const
*/
int QFontMetrics::leftBearing(QChar ch) const
{
- const int script = ch.script();
- QFontEngine *engine;
- if (d->capital == QFont::SmallCaps && ch.isLower())
- engine = d->smallCapsFontPrivate()->engineForScript(script);
- else
- engine = d->engineForScript(script);
- Q_ASSERT(engine != nullptr);
+ QFontEngine *engine = d->engineForCharacter(ch.unicode());
if (engine->type() == QFontEngine::Box)
return 0;
@@ -465,12 +458,7 @@ int QFontMetrics::leftBearing(QChar ch) const
*/
int QFontMetrics::rightBearing(QChar ch) const
{
- const int script = ch.script();
- QFontEngine *engine;
- if (d->capital == QFont::SmallCaps && ch.isLower())
- engine = d->smallCapsFontPrivate()->engineForScript(script);
- else
- engine = d->engineForScript(script);
+ QFontEngine *engine = d->engineForCharacter(ch.unicode());
Q_ASSERT(engine != nullptr);
if (engine->type() == QFontEngine::Box)
return 0;
@@ -574,13 +562,7 @@ int QFontMetrics::horizontalAdvance(QChar ch) const
if (QChar::category(ch.unicode()) == QChar::Mark_NonSpacing)
return 0;
- const int script = ch.script();
- QFontEngine *engine;
- if (d->capital == QFont::SmallCaps && ch.isLower())
- engine = d->smallCapsFontPrivate()->engineForScript(script);
- else
- engine = d->engineForScript(script);
- Q_ASSERT(engine != nullptr);
+ QFontEngine *engine = d->engineForCharacter(ch.unicode());
d->alterCharForCapitalization(ch);
@@ -684,13 +666,7 @@ QRect QFontMetrics::boundingRect(const QString &text, const QTextOption &option)
*/
QRect QFontMetrics::boundingRect(QChar ch) const
{
- const int script = ch.script();
- QFontEngine *engine;
- if (d->capital == QFont::SmallCaps && ch.isLower())
- engine = d->smallCapsFontPrivate()->engineForScript(script);
- else
- engine = d->engineForScript(script);
- Q_ASSERT(engine != nullptr);
+ QFontEngine *engine = d->engineForCharacter(ch.unicode());
d->alterCharForCapitalization(ch);
@@ -1345,13 +1321,7 @@ bool QFontMetricsF::inFontUcs4(uint ucs4) const
*/
qreal QFontMetricsF::leftBearing(QChar ch) const
{
- const int script = ch.script();
- QFontEngine *engine;
- if (d->capital == QFont::SmallCaps && ch.isLower())
- engine = d->smallCapsFontPrivate()->engineForScript(script);
- else
- engine = d->engineForScript(script);
- Q_ASSERT(engine != nullptr);
+ QFontEngine *engine = d->engineForCharacter(ch.unicode());
if (engine->type() == QFontEngine::Box)
return 0;
diff --git a/src/gui/text/qfontvariableaxis.cpp b/src/gui/text/qfontvariableaxis.cpp
index be83a3e02ce..bbc14f4cd11 100644
--- a/src/gui/text/qfontvariableaxis.cpp
+++ b/src/gui/text/qfontvariableaxis.cpp
@@ -60,6 +60,18 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QFontVariableAxisPrivate)
QFontVariableAxis::QFontVariableAxis(const QFontVariableAxis &axis) = default;
/*!
+ \property QFontVariableAxis::tag
+ \brief the tag of the axis
+
+ This is a four-character sequence which identifies the axis. Certain tags
+ have standardized meanings, such as "wght" (weight) and "wdth" (width),
+ but any sequence of four latin-1 characters is a valid tag. By convention,
+ non-standard/custom axes are denoted by tags in all uppercase.
+
+ \sa QFont::setVariableAxis(), name()
+*/
+
+/*!
Returns the tag of the axis. This is a four-character sequence which identifies the axis.
Certain tags have standardized meanings, such as "wght" (weight) and "wdth" (width), but any
sequence of four latin-1 characters is a valid tag. By convention, non-standard/custom axes
@@ -91,6 +103,13 @@ void QFontVariableAxis::setTag(QFont::Tag tag)
}
/*!
+ \property QFontVariableAxis::name
+ \brief the name of the axis, if provided by the font
+
+ \sa tag()
+*/
+
+/*!
Returns the name of the axis, if provided by the font.
\sa tag()
@@ -153,6 +172,15 @@ void QFontVariableAxis::setMinimumValue(qreal minimumValue)
}
/*!
+ \property QFontVariableAxis::maximumValue
+ \brief the maximum value of the axis
+
+ Setting the axis to a value which is higher than this is not supported.
+
+ \sa minimumValue(), defaultValue()
+*/
+
+/*!
Returns the maximum value of the axis. Setting the axis to a value which is higher than this
is not supported.
@@ -182,6 +210,16 @@ void QFontVariableAxis::setMaximumValue(qreal maximumValue)
}
/*!
+ \property QFontVariableAxis::defaultValue
+ \brief the default value of the axis
+
+ This is the value the axis will have if none has been provided in the
+ QFont query.
+
+ \sa minimumValue(), maximumValue()
+*/
+
+/*!
Returns the default value of the axis. This is the value the axis will have if none has been
provided in the QFont query.
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 11c79f23d25..29fda652ef6 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:critical reason:data-parser
+#include <QtCore/private/qflatmap_p.h>
#include <QtGui/private/qtguiglobal_p.h>
#include "qdebug.h"
#include "qtextformat.h"
@@ -1613,11 +1614,15 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
{
uint glyphs_shaped = 0;
- hb_buffer_t *buffer = hb_buffer_create();
- hb_buffer_set_unicode_funcs(buffer, hb_qt_get_unicode_funcs());
+ if (!buffer) {
+ buffer = hb_buffer_create();
+ hb_buffer_set_unicode_funcs(buffer, hb_qt_get_unicode_funcs());
+ }
+
hb_buffer_pre_allocate(buffer, itemLength);
if (Q_UNLIKELY(!hb_buffer_allocation_successful(buffer))) {
hb_buffer_destroy(buffer);
+ buffer = nullptr;
return 0;
}
@@ -1671,26 +1676,26 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
bool dontLigate = hasLetterSpacing && !scriptRequiresOpenType;
- QHash<QFont::Tag, quint32> features;
- features.insert(QFont::Tag("kern"), !!kerningEnabled);
+ QVarLengthFlatMap<QFont::Tag, hb_feature_t, 16> features;
+ auto insertFeature = [&features](QFont::Tag tag, quint32 value) {
+ features.insert(tag, { tag.value(),
+ value,
+ HB_FEATURE_GLOBAL_START,
+ HB_FEATURE_GLOBAL_END });
+ };
+ // fontFeatures have precedence
+ for (const auto &[tag, value]: fontFeatures.asKeyValueRange())
+ insertFeature(tag, value);
+ insertFeature(QFont::Tag("kern"), !!kerningEnabled);
if (dontLigate) {
- features.insert(QFont::Tag("liga"), false);
- features.insert(QFont::Tag("clig"), false);
- features.insert(QFont::Tag("dlig"), false);
- features.insert(QFont::Tag("hlig"), false);
- }
- features.insert(fontFeatures);
-
- QVarLengthArray<hb_feature_t, 16> featureArray;
- for (auto it = features.constBegin(); it != features.constEnd(); ++it) {
- featureArray.append({ it.key().value(),
- it.value(),
- HB_FEATURE_GLOBAL_START,
- HB_FEATURE_GLOBAL_END });
+ insertFeature(QFont::Tag("liga"), false);
+ insertFeature(QFont::Tag("clig"), false);
+ insertFeature(QFont::Tag("dlig"), false);
+ insertFeature(QFont::Tag("hlig"), false);
}
// whitelist cross-platforms shapers only
- static const char *shaper_list[] = {
+ constexpr const char *shaper_list[] = {
"graphite2",
"ot",
"fallback",
@@ -1699,13 +1704,11 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
bool shapedOk = hb_shape_full(hb_font,
buffer,
- featureArray.constData(),
- features.size(),
+ features.values().constData(),
+ features.values().size(),
shaper_list);
- if (Q_UNLIKELY(!shapedOk)) {
- hb_buffer_destroy(buffer);
+ if (Q_UNLIKELY(!shapedOk))
return 0;
- }
if (Q_UNLIKELY(HB_DIRECTION_IS_BACKWARD(props.direction)))
hb_buffer_reverse(buffer);
@@ -1718,10 +1721,8 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
num_glyphs = 1;
// ensure we have enough space for shaped glyphs and metrics
- if (Q_UNLIKELY(!ensureSpace(glyphs_shaped + num_glyphs))) {
- hb_buffer_destroy(buffer);
+ if (Q_UNLIKELY(!ensureSpace(glyphs_shaped + num_glyphs)))
return 0;
- }
// fetch the shaped glyphs and metrics
QGlyphLayout g = availableGlyphs(&si).mid(glyphs_shaped, num_glyphs);
@@ -1781,8 +1782,6 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
glyphs_shaped += num_glyphs;
}
- hb_buffer_destroy(buffer);
-
return glyphs_shaped;
}
@@ -1826,6 +1825,12 @@ QTextEngine::~QTextEngine()
delete layoutData;
delete specialData;
resetFontEngineCache();
+#if QT_CONFIG(harfbuzz)
+ if (buffer) {
+ hb_buffer_destroy(buffer);
+ buffer = nullptr;
+ }
+#endif
}
const QCharAttributes *QTextEngine::attributes() const
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index dffbc129b3a..e513fd598ba 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -40,6 +40,8 @@
#include <stdlib.h>
#include <vector>
+struct hb_buffer_t;
+
QT_BEGIN_NAMESPACE
class QFontPrivate;
@@ -583,6 +585,8 @@ private:
void indexFormats();
void resolveFormats() const;
+ mutable hb_buffer_t *buffer = nullptr;
+
public:
bool atWordSeparator(int position) const;