diff options
| author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2025-10-31 09:08:51 +0100 |
|---|---|---|
| committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2025-10-31 18:51:16 +0000 |
| commit | c3a07c99f9d2328cee4aa48a51d261d243b50d85 (patch) | |
| tree | faf3bb2d9c93f6d88d4ce5db1022dd124374767a | |
| parent | f8d051f3dea0302b9305454b9a9c3f279ef48fc6 (diff) | |
Rich text: Limit size of text object
When we draw a text object, we need to store this in RAM
since the QTextObjectInterface is QPainter-based. This
could lead to over-allocation if the text object size
was set to be very large. We use the existing image IO
infrastructure for making sure allocations are within
reasonable (and configurable) limits.
Pick-to: 6.8 6.5 5.15
Task-number: QTBUG-141515
Change-Id: Ieae06a9e92a7bd078d22ab2314889201c2049122
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
(cherry picked from commit 144ce34e846b3f732bdb003f99b1f9455425416f)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
| -rw-r--r-- | src/quick/items/qquicktextnodeengine.cpp | 16 | ||||
| -rw-r--r-- | tests/auto/quick/qquicktext/tst_qquicktext.cpp | 81 |
2 files changed, 91 insertions, 6 deletions
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 461191f6d0..d000638593 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -12,6 +12,7 @@ #include <QtGui/qtextobject.h> #include <QtGui/qtexttable.h> #include <QtGui/qtextlist.h> +#include <QtGui/qimageiohandler.h> #include <private/qquicktext_p.h> #include <private/qtextdocumentlayout_p.h> @@ -435,12 +436,15 @@ void QQuickTextNodeEngine::addTextObject(const QTextBlock &block, const QPointF } if (image.isNull()) { - image = QImage((size * m_devicePixelRatio).toSize(), QImage::Format_ARGB32_Premultiplied); - image.setDevicePixelRatio(m_devicePixelRatio); - image.fill(Qt::transparent); - { - QPainter painter(&image); - handler->drawObject(&painter, QRectF({}, size), textDocument, pos, format); + if (QImageIOHandler::allocateImage((size * m_devicePixelRatio).toSize(), + QImage::Format_ARGB32_Premultiplied, + &image)) { + image.setDevicePixelRatio(m_devicePixelRatio); + image.fill(Qt::transparent); + { + QPainter painter(&image); + handler->drawObject(&painter, QRectF({}, size), textDocument, pos, format); + } } } diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index 9f8f250d11..d6534e504c 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -125,6 +125,8 @@ private slots: void imgTagsElide(); void imgTagsUpdates(); void imgTagsError(); + void imgSize_data(); + void imgSize(); void fontSizeMode_data(); void fontSizeMode(); void fontSizeModeMultiline_data(); @@ -3451,6 +3453,85 @@ void tst_qquicktext::imgTagsError() QVERIFY(textObject != nullptr); } +void tst_qquicktext::imgSize_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<qint64>("width"); + QTest::addColumn<qint64>("height"); + QTest::addColumn<QQuickText::TextFormat>("format"); + + QTest::newRow("negative (styled text)") << QStringLiteral("images/starfish_2.png") + << qint64(-0x7FFFFF) + << qint64(-0x7FFFFF) + << QQuickText::StyledText; + QTest::newRow("negative (rich text)") << QStringLiteral("images/starfish_2.png") + << qint64(-0x7FFFFF) + << qint64(-0x7FFFFF) + << QQuickText::RichText; + QTest::newRow("large (styled text)") << QStringLiteral("images/starfish_2.png") + << qint64(0x7FFFFF) + << qint64(0x7FFFFF) + << QQuickText::StyledText; + QTest::newRow("large (right text)") << QStringLiteral("images/starfish_2.png") + << qint64(0x7FFFFF) + << qint64(0x7FFFFF) + << QQuickText::RichText; + QTest::newRow("medium (styled text)") << QStringLiteral("images/starfish_2.png") + << qint64(0x10000) + << qint64(0x10000) + << QQuickText::StyledText; + QTest::newRow("medium (right text)") << QStringLiteral("images/starfish_2.png") + << qint64(0x10000) + << qint64(0x10000) + << QQuickText::RichText; + QTest::newRow("large non-existent (styled text)") << QStringLiteral("a") + << qint64(0x7FFFFF) + << qint64(0x7FFFFF) + << QQuickText::StyledText; + QTest::newRow("medium non-existent (styled text)") << QStringLiteral("a") + << qint64(0x10000) + << qint64(0x10000) + << QQuickText::StyledText; + QTest::newRow("out-of-bounds non-existent (styled text)") << QStringLiteral("a") + << (qint64(INT_MAX) + 1) + << (qint64(INT_MAX) + 1) + << QQuickText::StyledText; + QTest::newRow("large non-existent (rich text)") << QStringLiteral("a") + << qint64(0x7FFFFF) + << qint64(0x7FFFFF) + << QQuickText::RichText; + QTest::newRow("medium non-existent (rich text)") << QStringLiteral("a") + << qint64(0x10000) + << qint64(0x10000) + << QQuickText::RichText; +} + +void tst_qquicktext::imgSize() +{ + QFETCH(QString, url); + QFETCH(qint64, width); + QFETCH(qint64, height); + QFETCH(QQuickText::TextFormat, format); + + // Reusing imgTagsUpdates.qml here, since it is just an empty Text component + QScopedPointer<QQuickView> window(createView(testFile("imgTagsUpdates.qml"))); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QScopedPointer<QQuickText> myText(window->rootObject()->findChild<QQuickText*>("myText")); + QVERIFY(myText); + + myText->setTextFormat(format); + + QString imgStr = QStringLiteral("<img src=\"%1\" width=\"%2\" height=\"%3\" />") + .arg(url) + .arg(width) + .arg(height); + myText->setText(imgStr); + + QVERIFY(QQuickTest::qWaitForPolish(myText.data())); +} + void tst_qquicktext::fontSizeMode_data() { QTest::addColumn<QString>("text"); |
