summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorRomain Pokrzywka <romain.pokrzywka@gmail.com>2019-08-23 11:26:17 -0500
committerRomain Pokrzywka <romain.pokrzywka@bluescape.com>2020-01-09 10:14:48 -0600
commit96d03be3e06649f9c9ed277622709e7a732bbcf9 (patch)
tree9bcb7e6ec224c8c1a6072c642ee6b4a295adc44f /tests
parentd2f6a5c7b97d61c4e983243d444dd51592a44bab (diff)
Fix crash when handling QEvent::TouchCancel
TouchCancel events have an empty touchPoints() list, which first trips when accessing touchPoints[0], and later on crashes Chromium if we pass the empty list to m_touchSelectionController. Rework handleTouchEvent() to route TouchCancel events like other touch events, and make sure we pass a non-empty touchpoints list to Chromium. Task-number: QTBUG-80893 Change-Id: Ie8396a1191f72b5bbb2b047f131794b37cfded48 Reviewed-by: Peter Varga <pvarga@inf.u-szeged.hu>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 044fac9d7..0b11be355 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -60,6 +60,8 @@ do { \
QCOMPARE((__expr), __expected); \
} while (0)
+static QTouchDevice* s_touchDevice = nullptr;
+
static QPoint elementCenter(QWebEnginePage *page, const QString &id)
{
const QString jsCode(
@@ -165,6 +167,9 @@ private Q_SLOTS:
void keyboardEvents();
void keyboardFocusAfterPopup();
void mouseClick();
+ void touchTap();
+ void touchTapAndHold();
+ void touchTapAndHoldCancelled();
void postData();
void inputFieldOverridesShortcuts();
@@ -210,6 +215,7 @@ private Q_SLOTS:
// It is only called once.
void tst_QWebEngineView::initTestCase()
{
+ s_touchDevice = QTest::createTouchDevice();
}
// This will be called after the last test function is executed.
@@ -1513,6 +1519,172 @@ void tst_QWebEngineView::mouseClick()
QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty());
}
+void tst_QWebEngineView::touchTap()
+{
+#if defined(Q_OS_MACOS)
+ QSKIP("Synthetic touch events are not supported on macOS");
+#endif
+
+ QWebEngineView view;
+ view.show();
+ view.resize(200, 200);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished);
+
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
+ view.setHtml("<html><body>"
+ "<p id='text' style='width: 150px;'>The Qt Company</p>"
+ "<div id='notext' style='width: 150px; height: 100px; background-color: #f00;'></div>"
+ "<form><input id='input' width='150px' type='text' value='The Qt Company2' /></form>"
+ "</body></html>");
+ QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+
+ auto singleTap = [](QWidget* target, const QPoint& tapCoords) -> void {
+ QTest::touchEvent(target, s_touchDevice).press(1, tapCoords, target);
+ QTest::touchEvent(target, s_touchDevice).stationary(1);
+ QTest::touchEvent(target, s_touchDevice).release(1, tapCoords, target);
+ };
+
+ // Single tap on text doesn't trigger a selection
+ singleTap(view.focusProxy(), elementCenter(view.page(), "text"));
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+ QTRY_VERIFY(!view.hasSelection());
+
+ // Single tap inside the input field focuses it without selecting the text
+ singleTap(view.focusProxy(), elementCenter(view.page(), "input"));
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
+ QTRY_VERIFY(!view.hasSelection());
+
+ // Single tap on the div clears the input field focus
+ singleTap(view.focusProxy(), elementCenter(view.page(), "notext"));
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+
+ // Double tap on text still doesn't trigger a selection
+ singleTap(view.focusProxy(), elementCenter(view.page(), "text"));
+ singleTap(view.focusProxy(), elementCenter(view.page(), "text"));
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+ QTRY_VERIFY(!view.hasSelection());
+
+ // Double tap inside the input field focuses it and selects the word under it
+ singleTap(view.focusProxy(), elementCenter(view.page(), "input"));
+ singleTap(view.focusProxy(), elementCenter(view.page(), "input"));
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
+ QTRY_COMPARE(view.selectedText(), QStringLiteral("Company2"));
+
+ // Double tap outside the input field behaves like a single tap: clears its focus and selection
+ singleTap(view.focusProxy(), elementCenter(view.page(), "notext"));
+ singleTap(view.focusProxy(), elementCenter(view.page(), "notext"));
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+ QTRY_VERIFY(!view.hasSelection());
+}
+
+void tst_QWebEngineView::touchTapAndHold()
+{
+#if defined(Q_OS_MACOS)
+ QSKIP("Synthetic touch events are not supported on macOS");
+#endif
+
+ QWebEngineView view;
+ view.show();
+ view.resize(200, 200);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished);
+
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
+ view.setHtml("<html><body>"
+ "<p id='text' style='width: 150px;'>The Qt Company</p>"
+ "<div id='notext' style='width: 150px; height: 100px; background-color: #f00;'></div>"
+ "<form><input id='input' width='150px' type='text' value='The Qt Company2' /></form>"
+ "</body></html>");
+ QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+
+ auto tapAndHold = [](QWidget* target, const QPoint& tapCoords) -> void {
+ QTest::touchEvent(target, s_touchDevice).press(1, tapCoords, target);
+ QTest::touchEvent(target, s_touchDevice).stationary(1);
+ QTest::qWait(1000);
+ QTest::touchEvent(target, s_touchDevice).release(1, tapCoords, target);
+ };
+
+ // Tap-and-hold on text selects the word under it
+ tapAndHold(view.focusProxy(), elementCenter(view.page(), "text"));
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+ QTRY_COMPARE(view.selectedText(), QStringLiteral("Company"));
+
+ // Tap-and-hold inside the input field focuses it and selects the word under it
+ tapAndHold(view.focusProxy(), elementCenter(view.page(), "input"));
+ QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
+ QTRY_COMPARE(view.selectedText(), QStringLiteral("Company2"));
+
+ // Only test the page context menu on Windows, as Linux doesn't handle context menus consistently
+ // and other non-desktop platforms like Android may not even support context menus at all
+#if defined(Q_OS_WIN)
+ // Tap-and-hold clears the text selection and shows the page's context menu
+ QVERIFY(QApplication::activePopupWidget() == nullptr);
+ tapAndHold(view.focusProxy(), elementCenter(view.page(), "notext"));
+ QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+ QTRY_VERIFY(!view.hasSelection());
+ QTRY_VERIFY(QApplication::activePopupWidget() != nullptr);
+
+ QApplication::activePopupWidget()->close();
+ QVERIFY(QApplication::activePopupWidget() == nullptr);
+#endif
+}
+
+void tst_QWebEngineView::touchTapAndHoldCancelled()
+{
+#if defined(Q_OS_MACOS)
+ QSKIP("Synthetic touch events are not supported on macOS");
+#endif
+
+ QWebEngineView view;
+ view.show();
+ view.resize(200, 200);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished);
+
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
+ view.setHtml("<html><body>"
+ "<p id='text' style='width: 150px;'>The Qt Company</p>"
+ "<div id='notext' style='width: 150px; height: 100px; background-color: #f00;'></div>"
+ "<form><input id='input' width='150px' type='text' value='The Qt Company2' /></form>"
+ "</body></html>");
+ QVERIFY(loadFinishedSpy.wait());
+ QVERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
+
+ auto cancelledTapAndHold = [](QWidget* target, const QPoint& tapCoords) -> void {
+ QTest::touchEvent(target, s_touchDevice).press(1, tapCoords, target);
+ QTest::touchEvent(target, s_touchDevice).stationary(1);
+ QTest::qWait(1000);
+ QWindowSystemInterface::handleTouchCancelEvent(target->windowHandle(), s_touchDevice);
+ };
+
+ // A cancelled tap-and-hold should cancel text selection, but currently doesn't
+ cancelledTapAndHold(view.focusProxy(), elementCenter(view.page(), "text"));
+ QEXPECT_FAIL("", "Incorrect Chromium selection behavior when cancelling tap-and-hold on text", Continue);
+ QTRY_VERIFY_WITH_TIMEOUT(!view.hasSelection(), 100);
+
+ // A cancelled tap-and-hold should cancel input field focusing and selection, but currently doesn't
+ cancelledTapAndHold(view.focusProxy(), elementCenter(view.page(), "input"));
+ QEXPECT_FAIL("", "Incorrect Chromium selection behavior when cancelling tap-and-hold on input field", Continue);
+ QTRY_VERIFY_WITH_TIMEOUT(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty(), 100);
+ QEXPECT_FAIL("", "Incorrect Chromium focus behavior when cancelling tap-and-hold on input field", Continue);
+ QTRY_VERIFY_WITH_TIMEOUT(!view.hasSelection(), 100);
+
+ // Only test the page context menu on Windows, as Linux doesn't handle context menus consistently
+ // and other non-desktop platforms like Android may not even support context menus at all
+#if defined(Q_OS_WIN)
+ // A cancelled tap-and-hold cancels the context menu
+ QVERIFY(QApplication::activePopupWidget() == nullptr);
+ cancelledTapAndHold(view.focusProxy(), elementCenter(view.page(), "notext"));
+ QVERIFY(QApplication::activePopupWidget() == nullptr);
+#endif
+}
+
void tst_QWebEngineView::postData()
{
QMap<QString, QString> postData;