aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2025-10-31 09:08:51 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2025-10-31 18:51:16 +0000
commitc3a07c99f9d2328cee4aa48a51d261d243b50d85 (patch)
treefaf3bb2d9c93f6d88d4ce5db1022dd124374767a
parentf8d051f3dea0302b9305454b9a9c3f279ef48fc6 (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.cpp16
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp81
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");