diff options
Diffstat (limited to 'src/gui/text')
| -rw-r--r-- | src/gui/text/qfont.cpp | 13 | ||||
| -rw-r--r-- | src/gui/text/qfont_p.h | 7 | ||||
| -rw-r--r-- | src/gui/text/qfontmetrics.cpp | 44 | ||||
| -rw-r--r-- | src/gui/text/qfontvariableaxis.cpp | 38 | ||||
| -rw-r--r-- | src/gui/text/qtextengine.cpp | 61 | ||||
| -rw-r--r-- | src/gui/text/qtextengine_p.h | 4 |
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; |
