1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
Description: 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.
Origin: upstream, https://code.qt.io/cgit/qt/qtdeclarative.git/commit/?id=144ce34e846b3f73
Backported to 5.15 by Dmitry Shachnev: validate allocation manually
instead of using QImageIOHandler::allocateImage().
Last-Update: 2025-12-11
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -47,6 +47,7 @@
#include <QtGui/qtextobject.h>
#include <QtGui/qtexttable.h>
#include <QtGui/qtextlist.h>
+#include <QtGui/private/qimage_p.h>
#include <private/qquicktext_p.h>
#include <private/qquicktextdocument_p.h>
@@ -464,12 +465,16 @@ void QQuickTextNodeEngine::addTextObject
}
}
- if (image.isNull()) {
- image = QImage(size.toSize(), QImage::Format_ARGB32_Premultiplied);
- image.fill(Qt::transparent);
- {
- QPainter painter(&image);
- handler->drawObject(&painter, image.rect(), textDocument, pos, format);
+ if (image.isNull() && !size.isEmpty()) {
+ QImageData::ImageSizeParameters szp =
+ QImageData::calculateImageParameters(size.width(), size.height(), 32);
+ if (szp.isValid() && szp.totalSize <= 268435456L /* 256 MB */) {
+ image = QImage(size.toSize(), QImage::Format_ARGB32_Premultiplied);
+ image.fill(Qt::transparent);
+ {
+ QPainter painter(&image);
+ handler->drawObject(&painter, image.rect(), textDocument, pos, format);
+ }
}
}
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -133,6 +133,8 @@ private slots:
void imgTagsElide();
void imgTagsUpdates();
void imgTagsError();
+ void imgSize_data();
+ void imgSize();
void fontSizeMode_data();
void fontSizeMode();
void fontSizeModeMultiline_data();
@@ -3237,6 +3239,85 @@ void tst_qquicktext::imgTagsError()
delete textObject;
}
+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::qWaitForItemPolished(myText.data()));
+}
+
void tst_qquicktext::fontSizeMode_data()
{
QTest::addColumn<QString>("text");
|