aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2022-01-06 17:12:36 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-01-07 23:29:03 +0000
commite35b06219d5456c8ce7c96931f7c627a480c56db (patch)
treeb340e9f23a1d49bdb113e21e231d6d7b44640d7e
parent9c8e32a575c2ba415090a11e05a204d4b5e8f0b3 (diff)
Don't crash when pasting text into TextArea
If QQuickTextAreaPrivate::ensureCursorVisible() calls QQuickFlickable::setContentY() while the Flickable does not yet know the extents of its new content, it caused a crash when QQuickScrollBarPrivate::visualArea() called qBound(0, 1, -something). We need to wait until Flickable knows it can scroll that far. It turns out ensureCursorVisible() is called several times anyway, so it's OK to skip the calls that would ask the Flickable to scroll out-of-bounds. Task-number: QTBUG-99582 Change-Id: Ifb374a81591df49d3c571f55cb3076a78a808918 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> (cherry picked from commit 924b2d5d47a33d11999a8edbfe6960e9593038ec) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/qmltest/quicktestutil.cpp13
-rw-r--r--src/qmltest/quicktestutil_p.h2
-rw-r--r--src/quicktemplates2/qquicktextarea.cpp2
-rw-r--r--tests/auto/quickcontrols2/controls/data/tst_textarea.qml33
4 files changed, 49 insertions, 1 deletions
diff --git a/src/qmltest/quicktestutil.cpp b/src/qmltest/quicktestutil.cpp
index 994c66845b..25863c3842 100644
--- a/src/qmltest/quicktestutil.cpp
+++ b/src/qmltest/quicktestutil.cpp
@@ -47,6 +47,7 @@
#include <QtQml/private/qjsvalue_p.h>
#include <QtGui/qguiapplication.h>
+#include <QtGui/qclipboard.h>
#include <QtGui/qstylehints.h>
#include <QtQml/qqmlengine.h>
@@ -62,6 +63,18 @@ int QuickTestUtil::dragThreshold() const
return QGuiApplication::styleHints()->startDragDistance();
}
+void QuickTestUtil::populateClipboardText(int lineCount)
+{
+#if QT_CONFIG(clipboard)
+ QString fmt(u"%1 bottles of beer on the wall, %1 bottles of beer; "
+ "take one down, pass it around, %2 bottles of beer on the wall."_qs);
+ QStringList lines;
+ for (int i = lineCount; i > 0; --i)
+ lines << fmt.arg(i).arg(i - 1);
+ QGuiApplication::clipboard()->setText(lines.join(u'\n'));
+#endif
+}
+
QJSValue QuickTestUtil::typeName(const QVariant &v) const
{
QString name = QString::fromUtf8(v.typeName());
diff --git a/src/qmltest/quicktestutil_p.h b/src/qmltest/quicktestutil_p.h
index 1cf2a6f356..fae904b84c 100644
--- a/src/qmltest/quicktestutil_p.h
+++ b/src/qmltest/quicktestutil_p.h
@@ -73,6 +73,8 @@ public:
bool printAvailableFunctions() const;
int dragThreshold() const;
+ Q_INVOKABLE void populateClipboardText(int lineCount);
+
Q_SIGNALS:
void printAvailableFunctionsChanged();
void dragThresholdChanged();
diff --git a/src/quicktemplates2/qquicktextarea.cpp b/src/quicktemplates2/qquicktextarea.cpp
index 6ba0474073..c2c2a91cb4 100644
--- a/src/quicktemplates2/qquicktextarea.cpp
+++ b/src/quicktemplates2/qquicktextarea.cpp
@@ -383,7 +383,7 @@ void QQuickTextAreaPrivate::ensureCursorVisible()
flickable->setContentY(cr.top() - tp);
} else {
const qreal bp = q->bottomPadding();
- if (cr.bottom() >= cy + tp + h - bp)
+ if (cr.bottom() >= cy + tp + h - bp && cr.bottom() <= flickable->contentHeight())
flickable->setContentY(cr.bottom() - h + bp);
}
}
diff --git a/tests/auto/quickcontrols2/controls/data/tst_textarea.qml b/tests/auto/quickcontrols2/controls/data/tst_textarea.qml
index 5fcc4773dc..e4ae3713f3 100644
--- a/tests/auto/quickcontrols2/controls/data/tst_textarea.qml
+++ b/tests/auto/quickcontrols2/controls/data/tst_textarea.qml
@@ -88,6 +88,16 @@ TestCase {
}
Component {
+ id: flickableWithScrollBar
+ Flickable {
+ width: 200
+ height: 200
+ TextArea.flickable: TextArea { }
+ ScrollBar.vertical: ScrollBar { }
+ }
+ }
+
+ Component {
id: signalSpy
SignalSpy { }
}
@@ -101,6 +111,10 @@ TestCase {
id: defaultFontMetrics
}
+ TestUtil {
+ id: util
+ }
+
function test_creation() {
var control = createTemporaryObject(textArea, testCase)
verify(control)
@@ -351,6 +365,25 @@ TestCase {
compare(textArea.background.height, flickable.height)
}
+ function test_scrollable_paste_large() {
+ var control = createTemporaryObject(flickableWithScrollBar, testCase)
+ verify(control)
+
+ var textArea = control.TextArea.flickable
+ verify(textArea)
+
+ if (typeof(textArea.paste) !== "function")
+ skip("Clipboard is not supported on this platform.")
+
+ util.populateClipboardText(100)
+ waitForRendering(control)
+ // don't crash (QTBUG-99582)
+ textArea.paste()
+ // verify that the cursor moved to the bottom after pasting, and we scrolled down to show it
+ tryVerify(function() { return textArea.cursorRectangle.y > 1000 }); // maybe > 2000, depending on font size
+ tryVerify(function() { return control.contentY > textArea.cursorRectangle.y - control.height })
+ }
+
function test_warning() {
ignoreWarning(/QML TestCase: TextArea must be attached to a Flickable/)
testCase.TextArea.flickable = null