From 9334feb682db6e6e35bc98dce377a091eb640438 Mon Sep 17 00:00:00 2001 From: Kirill Burtsev Date: Fri, 22 Apr 2022 14:06:39 +0200 Subject: Fix touch input for html's popup in quick impl Ammends 292f573f4e. Now that touch events are forwarded to popup delegate also instead of synthesized mouse events, the bug with touch event being ignored became present. Also extend testing of touch events for html popups. Task-number: QTBUG-79254 Fixes: QTBUG-103217 Pick-to: 6.2 6.3 Change-Id: I097a6617493355c7603fef8eb41025e299a6e809 Reviewed-by: Shawn Rutledge Reviewed-by: Michal Klocek --- .../tst_qquickwebengineview.cpp | 48 ++++++++++++++++---- tests/auto/util/util.h | 24 +++------- .../widgets/qwebenginepage/tst_qwebenginepage.cpp | 51 +++++++++++++++++----- tests/auto/widgets/touchinput/tst_touchinput.cpp | 48 ++++++++++++++++++++ 4 files changed, 132 insertions(+), 39 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 347f370f7..2bfedd707 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -96,6 +96,7 @@ private Q_SLOTS: void setProfile(); void focusChild(); void focusChild_data(); + void htmlSelectPopup(); private: inline QQuickWebEngineView *newWebEngineView(); @@ -105,6 +106,11 @@ private: QString m_testSourceDirPath; QScopedPointer m_window; QScopedPointer m_component; + + QPointingDevice *touchDevice() { + static auto d = QScopedPointer(QTest::createTouchDevice()); + return d.get(); + } }; tst_QQuickWebEngineView::tst_QQuickWebEngineView() @@ -587,9 +593,8 @@ void tst_QQuickWebEngineView::interruptImeTextComposition() QTest::mouseClick(view->window(), Qt::LeftButton, {}, textInputCenter); } else if (eventType == "Touch") { QPoint textInputCenter = elementCenter(view, QStringLiteral("input2")); - QPointingDevice *touchDevice = QTest::createTouchDevice(); - QTest::touchEvent(view->window(), touchDevice).press(0, textInputCenter, view->window()); - QTest::touchEvent(view->window(), touchDevice).release(0, textInputCenter, view->window()); + QTest::touchEvent(view->window(), touchDevice()).press(0, textInputCenter, view->window()); + QTest::touchEvent(view->window(), touchDevice()).release(0, textInputCenter, view->window()); } QTRY_COMPARE(evaluateJavaScriptSync(view, "document.activeElement.id").toString(), QStringLiteral("input2")); #ifndef Q_OS_WIN @@ -987,11 +992,9 @@ void tst_QQuickWebEngineView::inputEventForwardingDisabledWhenActiveFocusOnPress QTest::mousePress(view->window(), Qt::LeftButton); QTest::mouseRelease(view->window(), Qt::LeftButton); - QPointingDevice *device = QTest::createTouchDevice(); - - QTest::touchEvent(view->window(), device).press(0, QPoint(0,0), view->window()); - QTest::touchEvent(view->window(), device).move(0, QPoint(1, 1), view->window()); - QTest::touchEvent(view->window(), device).release(0, QPoint(1, 1), view->window()); + QTest::touchEvent(view->window(), touchDevice()).press(0, QPoint(0,0), view->window()); + QTest::touchEvent(view->window(), touchDevice()).move(0, QPoint(1, 1), view->window()); + QTest::touchEvent(view->window(), touchDevice()).release(0, QPoint(1, 1), view->window()); // We expect to catch 7 events - click = 2, press + release = 2, touches = 3. QCOMPARE(item.eventCount(), 7); @@ -1170,6 +1173,8 @@ void tst_QQuickWebEngineView::setProfile() { QVERIFY(waitForLoadSucceeded(webEngineView())); QCOMPARE(loadSpy.size(), 4); QQuickWebEngineProfile *profile = new QQuickWebEngineProfile(); + auto oldProfile = webEngineView()->profile(); + auto sc = qScopeGuard([&] () { webEngineView()->setProfile(oldProfile); delete profile; }); webEngineView()->setProfile(profile); QTRY_COMPARE(webEngineView()->url() ,urlFromTestPath("html/basic_page2.html")); } @@ -1237,6 +1242,33 @@ void tst_QQuickWebEngineView::focusChild() QCOMPARE(traverseToWebDocumentAccessibleInterface(iface)->child(0)->child(0), iface->focusChild()); } +void tst_QQuickWebEngineView::htmlSelectPopup() +{ + m_window->show(); + QQuickWebEngineView &view = *webEngineView(); + view.settings()->setFocusOnNavigationEnabled(true); + view.setSize(QSizeF(640, 480)); + view.loadHtml("" + "" + ""); + QVERIFY(waitForLoadSucceeded(&view)); + + auto makeTouch = [this] (QWindow *w, const QPoint &p) { + QTest::touchEvent(w, touchDevice()).press(1, p); + QTest::touchEvent(w, touchDevice()).release(1, p); + }; + + makeTouch(view.window(), elementCenter(&view, "select")); + QPointer popup; + QTRY_VERIFY((popup = m_window->findChild())); + QCOMPARE(activeElementId(&view), QStringLiteral("select")); + + makeTouch(popup, QPoint(popup->width() / 2, popup->height() / 2)); + QTRY_VERIFY(!popup); + QCOMPARE(evaluateJavaScriptSync(&view, "document.getElementById('select').value").toString(), QStringLiteral("O2")); +} + static QByteArrayList params = QByteArrayList() << "--force-renderer-accessibility"; diff --git a/tests/auto/util/util.h b/tests/auto/util/util.h index a624a978f..232d26d8f 100644 --- a/tests/auto/util/util.h +++ b/tests/auto/util/util.h @@ -175,31 +175,13 @@ static inline bool loadSync(QWebEnginePage *page, const QUrl &url, bool ok = tru return (!spy.empty() || spy.wait(20000)) && (spy.front().value(0).toBool() == ok); } -static inline QPoint elementCenter(QWebEnginePage *page, const QString &id) -{ - const QString jsCode( - "(function(){" - " var elem = document.getElementById('" + id + "');" - " var rect = elem.getBoundingClientRect();" - " return [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];" - "})()"); - QVariantList rectList = evaluateJavaScriptSync(page, jsCode).toList(); - - if (rectList.count() != 2) { - qWarning("elementCenter failed."); - return QPoint(); - } - - return QPoint(rectList.at(0).toInt(), rectList.at(1).toInt()); -} - static inline QRect elementGeometry(QWebEnginePage *page, const QString &id) { const QString jsCode( "(function() {" " var elem = document.getElementById('" + id + "');" " var rect = elem.getBoundingClientRect();" - " return [rect.left, rect.top, rect.right, rect.bottom];" + " return [rect.left, rect.top, rect.width, rect.height];" "})()"); QVariantList coords = evaluateJavaScriptSync(page, jsCode).toList(); @@ -211,5 +193,9 @@ static inline QRect elementGeometry(QWebEnginePage *page, const QString &id) return QRect(coords[0].toInt(), coords[1].toInt(), coords[2].toInt(), coords[3].toInt()); } +static inline QPoint elementCenter(QWebEnginePage *page, const QString &id) +{ + return elementGeometry(page, id).center(); +} #define W_QSKIP(a, b) QSKIP(a) diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 90ec9eb22..9c730e45d 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -96,7 +96,9 @@ public Q_SLOTS: private Q_SLOTS: void initTestCase(); void cleanupTestCase(); + void comboBoxPopupPositionAfterMove_data(); void comboBoxPopupPositionAfterMove(); + void comboBoxPopupPositionAfterChildMove_data(); void comboBoxPopupPositionAfterChildMove(); void acceptNavigationRequest(); void acceptNavigationRequestNavigationType(); @@ -262,6 +264,18 @@ private: + QDateTime::currentDateTime().toString(QLatin1String("yyyyMMddhhmmss")); return tmpd; } + + QScopedPointer s_touchDevice; + void makeClick(QWindow *window, bool withTouch = false, const QPoint &p = QPoint()) { + if (!withTouch) { + QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), p); + } else { + if (!s_touchDevice) + s_touchDevice.reset(QTest::createTouchDevice()); + QTest::touchEvent(window, s_touchDevice.get()).press(1, p); + QTest::touchEvent(window, s_touchDevice.get()).release(1, p); + } + }; }; tst_QWebEnginePage::tst_QWebEnginePage() @@ -1298,6 +1312,13 @@ static QWindow *findNewTopLevelWindow(const QWindowList &oldTopLevelWindows) return nullptr; } +void tst_QWebEnginePage::comboBoxPopupPositionAfterMove_data() +{ + QTest::addColumn("withTouch"); + QTest::addRow("mouse") << false; + QTest::addRow("touch") << true; +} + void tst_QWebEnginePage::comboBoxPopupPositionAfterMove() { QWebEngineView view; @@ -1311,9 +1332,10 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterMove() "")); QTRY_COMPARE(loadSpy.count(), 1); const auto oldTlws = QGuiApplication::topLevelWindows(); + + QFETCH(bool, withTouch); QWindow *window = view.windowHandle(); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - elementCenter(view.page(), "foo")); + makeClick(window, withTouch, elementCenter(view.page(), "foo")); QWindow *popup = nullptr; QTRY_VERIFY(popup = findNewTopLevelWindow(oldTlws)); @@ -1322,7 +1344,7 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterMove() QPoint popupPos = popup->position(); // Close the popup by clicking somewhere into the page. - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(1, 1)); + makeClick(window, withTouch, QPoint(1, 1)); QTRY_VERIFY(!QGuiApplication::topLevelWindows().contains(popup)); auto jsViewPosition = [&view]() { @@ -1341,16 +1363,22 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterMove() const QPoint offset(12, 13); view.move(view.pos() + offset); QTRY_COMPARE(jsViewPosition(), view.pos()); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - elementCenter(view.page(), "foo")); + makeClick(window, withTouch, elementCenter(view.page(), "foo")); QTRY_VERIFY(popup = findNewTopLevelWindow(oldTlws)); QTRY_VERIFY(QGuiApplication::topLevelWindows().contains(popup)); QTRY_VERIFY(!popup->position().isNull()); QCOMPARE(popupPos + offset, popup->position()); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(1, 1)); + makeClick(window, withTouch, QPoint(1, 1)); QTRY_VERIFY(!QGuiApplication::topLevelWindows().contains(popup)); } +void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove_data() +{ + QTest::addColumn("withTouch"); + QTest::addRow("mouse") << false; + QTest::addRow("touch") << true; +} + void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove() { QWidget mainWidget; @@ -1373,9 +1401,10 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove() "")); QTRY_COMPARE(loadSpy.count(), 1); const auto oldTlws = QGuiApplication::topLevelWindows(); + + QFETCH(bool, withTouch); QWindow *window = view.window()->windowHandle(); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - view.mapTo(view.window(), elementCenter(view.page(), "foo"))); + makeClick(window, withTouch, view.mapTo(view.window(), elementCenter(view.page(), "foo"))); QWindow *popup = nullptr; QTRY_VERIFY(popup = findNewTopLevelWindow(oldTlws)); @@ -1384,8 +1413,7 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove() QPoint popupPos = popup->position(); // Close the popup by clicking somewhere into the page. - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - view.mapTo(view.window(), QPoint(1, 1))); + makeClick(window, withTouch, view.mapTo(view.window(), QPoint(1, 1))); QTRY_VERIFY(!QGuiApplication::topLevelWindows().contains(popup)); int originalViewWidth = view.size().width(); @@ -1400,8 +1428,7 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove() spacer.setMinimumWidth(spacer.size().width() + offset); QTRY_COMPARE(jsViewWidth(), originalViewWidth - offset); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - view.mapTo(view.window(), elementCenter(view.page(), "foo"))); + makeClick(window, withTouch, view.mapTo(view.window(), elementCenter(view.page(), "foo"))); QTRY_VERIFY(popup = findNewTopLevelWindow(oldTlws)); QTRY_VERIFY(!popup->position().isNull()); QCOMPARE(popupPos + QPoint(50, 0), popup->position()); diff --git a/tests/auto/widgets/touchinput/tst_touchinput.cpp b/tests/auto/widgets/touchinput/tst_touchinput.cpp index d60fd1d7b..957f3e74c 100644 --- a/tests/auto/widgets/touchinput/tst_touchinput.cpp +++ b/tests/auto/widgets/touchinput/tst_touchinput.cpp @@ -37,6 +37,12 @@ static QPointingDevice* s_touchDevice = nullptr; +struct Page : QWebEnginePage +{ + QStringList alerts; + void javaScriptAlert(const QUrl &/*origin*/, const QString &msg) override { alerts.append(msg); } +}; + class TouchInputTest : public QObject { Q_OBJECT @@ -54,14 +60,23 @@ private Q_SLOTS: void pinchZoom_data(); void pinchZoom(); void complexSequence(); + void buttonClickHandler(); + void htmlSelectPopup(); private: + Page page; QWebEngineView view; QSignalSpy loadSpy { &view, &QWebEngineView::loadFinished }; QPoint notextCenter, textCenter, inputCenter; QString activeElement() { return evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(); } + void makeTouch(QWindow *w, const QPoint &p) { + QTest::touchEvent(w, s_touchDevice).press(1, p); + QTest::touchEvent(w, s_touchDevice).release(1, p); + } + void makeTouch(const QPoint &p) { makeTouch(view.windowHandle(), p); } + void gestureScroll(bool down) { auto target = view.focusProxy(); QPoint p(target->width() / 2, target->height() / 4 * (down ? 3 : 1)); @@ -131,6 +146,7 @@ void TouchInputTest::initTestCase() { s_touchDevice = QTest::createTouchDevice(); + view.setPage(&page); view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); view.show(); view.resize(480, 320); @@ -140,6 +156,9 @@ void TouchInputTest::initTestCase() "

The Qt Company

" "
" "
" + "" + "" "" "" "" @@ -163,6 +182,7 @@ void TouchInputTest::cleanup() evaluateJavaScriptSync(view.page(), "window.scrollTo(0, 0)"); QTRY_COMPARE(getScrollPosition(), 0); QTRY_COMPARE(pageScrollPosition(), 0); + page.alerts.clear(); } void TouchInputTest::touchTap() @@ -345,5 +365,33 @@ void TouchInputTest::complexSequence() } } +void TouchInputTest::buttonClickHandler() +{ + auto buttonCenter = elementGeometry(view.page(), "btn").center(); + makeTouch(buttonCenter); + QTRY_VERIFY(!page.alerts.isEmpty()); + QCOMPARE(page.alerts.first(), "button clicked!"); + QCOMPARE(page.alerts.size(), 1); + QEXPECT_FAIL("", "Shouldn't trigger twice due to synthesized mouse events for touch", Continue); + QTRY_VERIFY_WITH_TIMEOUT(page.alerts.size() == 2, 500); +} + +void TouchInputTest::htmlSelectPopup() +{ + auto selectRect = elementGeometry(view.page(), "select"); + makeTouch(selectRect.center()); + QTRY_VERIFY(QApplication::activePopupWidget()); + QCOMPARE(activeElement(), QStringLiteral("select")); + + auto popup = QApplication::activePopupWidget(); + makeTouch(popup->windowHandle(), QPoint(popup->width() / 2, popup->height() / 2)); + QTRY_VERIFY(!QApplication::activePopupWidget()); + + QTRY_VERIFY(!page.alerts.isEmpty()); + QCOMPARE(page.alerts.first(), "option changed to: O2"); + QEXPECT_FAIL("", "Shouldn't trigger twice due to synthesized mouse events for touch", Continue); + QTRY_VERIFY_WITH_TIMEOUT(page.alerts.size() == 2, 500); +} + QTEST_MAIN(TouchInputTest) #include "tst_touchinput.moc" -- cgit v1.2.3
BEFORE
AFTER
BEFORE
AFTER