diff options
-rw-r--r-- | src/core/render_widget_host_view_qt.cpp | 78 | ||||
-rw-r--r-- | tests/auto/widgets/touchinput/tst_touchinput.cpp | 63 |
2 files changed, 107 insertions, 34 deletions
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index c4a07a70c..36ffbea57 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -66,6 +66,7 @@ #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/common/content_switches_internal.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" +#include "content/browser/renderer_host/ui_events_helper.h" #include "content/common/cursors/webcursor.h" #include "content/common/input_messages.h" #include "third_party/skia/include/core/SkColor.h" @@ -198,8 +199,12 @@ public: , flags(flagsFromModifiers(modifiers)) , index(index) { - // ACTION_DOWN and ACTION_UP must be accesssed through pointer_index 0 - Q_ASSERT((action != Action::DOWN && action != Action::UP) || index == 0); + // index is only valid for ACTION_DOWN and ACTION_UP and should correspond to the point causing it + // see blink_event_util.cc:ToWebTouchPointState for details + Q_ASSERT_X((action != Action::POINTER_DOWN && action != Action::POINTER_UP && index == -1) + || (action == Action::POINTER_DOWN && index >= 0 && touchPoint(index).state() == Qt::TouchPointPressed) + || (action == Action::POINTER_UP && index >= 0 && touchPoint(index).state() == Qt::TouchPointReleased), + "MotionEventQt", qPrintable(QString("action: %1, index: %2, state: %3").arg(int(action)).arg(index).arg(touchPoint(index).state()))); } uint32_t GetUniqueEventId() const override { return eventId; } @@ -1231,7 +1236,8 @@ void RenderWidgetHostViewQt::closePopup() void RenderWidgetHostViewQt::ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, content::InputEventAckState ack_result) { Q_UNUSED(touch); const bool eventConsumed = ack_result == content::INPUT_EVENT_ACK_STATE_CONSUMED; - m_gestureProvider.OnTouchEventAck(touch.event.unique_touch_event_id, eventConsumed, /*fixme: ?? */false); + const bool isSetNonBlocking = content::InputEventAckStateIsSetNonBlocking(ack_result); + m_gestureProvider.OnTouchEventAck(touch.event.unique_touch_event_id, eventConsumed, isSetNonBlocking); } void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEvent) @@ -1611,6 +1617,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) m_previousTouchPoints.clear(); m_touchMotionStarted = false; break; + default: m_previousTouchPoints = touchPoints; break; @@ -1648,8 +1655,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) action = ui::MotionEvent::Action::CANCEL; } - MotionEventQt me(touchPoints, eventTimestamp, action, ev->modifiers(), - action == ui::MotionEvent::Action::CANCEL ? -1 : 0); + MotionEventQt me(touchPoints, eventTimestamp, action, ev->modifiers()); if (m_touchSelectionController->WillHandleTouchEvent(me)) return; @@ -1692,31 +1698,49 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) #endif } - for (int i = 0; i < touchPoints.size(); ++i) { - ui::MotionEvent::Action action; - switch (touchPoints[i].second.state()) { - case Qt::TouchPointPressed: - if (m_sendMotionActionDown) { - action = ui::MotionEvent::Action::DOWN; - m_sendMotionActionDown = false; - } else { - action = ui::MotionEvent::Action::POINTER_DOWN; + // MEMO for the basis of this logic look into: + // * blink_event_util.cc:ToWebTouchPointState: which is used later to forward touch event + // composed from motion event after gesture recognition + // * gesture_detector.cc:GestureDetector::OnTouchEvent: contains logic for every motion + // event action and corresponding gesture recognition routines + // * input_router_imp.cc:InputRouterImp::SetMovementXYForTouchPoints: expectation about + // touch event content like number of points for different states + + int lastPressIndex = -1; + while ((lastPressIndex + 1) < touchPoints.size() && touchPoints[lastPressIndex + 1].second.state() == Qt::TouchPointPressed) + ++lastPressIndex; + + switch (ev->type()) { + case QEvent::TouchBegin: + processMotionEvent(MotionEventQt(touchPoints.mid(lastPressIndex), + eventTimestamp, ui::MotionEvent::Action::DOWN, ev->modifiers())); + --lastPressIndex; + Q_FALLTHROUGH(); + + case QEvent::TouchUpdate: + for (; lastPressIndex >= 0; --lastPressIndex) { + Q_ASSERT(touchPoints[lastPressIndex].second.state() == Qt::TouchPointPressed); + MotionEventQt me(touchPoints.mid(lastPressIndex), eventTimestamp, ui::MotionEvent::Action::POINTER_DOWN, ev->modifiers(), 0); + processMotionEvent(me); + } + + if (ev->touchPointStates() & Qt::TouchPointMoved) + processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, ui::MotionEvent::Action::MOVE, ev->modifiers())); + + Q_FALLTHROUGH(); + + case QEvent::TouchEnd: + while (!touchPoints.isEmpty() && touchPoints.back().second.state() == Qt::TouchPointReleased) { + auto action = touchPoints.size() > 1 ? ui::MotionEvent::Action::POINTER_UP : ui::MotionEvent::Action::UP; + int index = action == ui::MotionEvent::Action::POINTER_UP ? touchPoints.size() - 1 : -1; + processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, action, ev->modifiers(), index)); + touchPoints.pop_back(); } break; - case Qt::TouchPointMoved: - action = ui::MotionEvent::Action::MOVE; - break; - case Qt::TouchPointReleased: - action = touchPoints.size() > 1 ? ui::MotionEvent::Action::POINTER_UP : - ui::MotionEvent::Action::UP; - break; - default: - // Ignore Qt::TouchPointStationary - continue; - } - MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), i); - processMotionEvent(motionEvent); + default: + Q_ASSERT_X(false, __FUNCTION__, "Other event types are expected to be already handled."); + break; } } diff --git a/tests/auto/widgets/touchinput/tst_touchinput.cpp b/tests/auto/widgets/touchinput/tst_touchinput.cpp index 3eee6d824..d9381153d 100644 --- a/tests/auto/widgets/touchinput/tst_touchinput.cpp +++ b/tests/auto/widgets/touchinput/tst_touchinput.cpp @@ -51,7 +51,9 @@ private Q_SLOTS: void touchTapAndHold(); void touchTapAndHoldCancelled(); void scrolling(); + void pinchZoom_data(); void pinchZoom(); + void complexSequence(); private: QWebEngineView view; @@ -75,13 +77,17 @@ private: QTest::touchEvent(target, s_touchDevice).release(42, p, target); } - void gesturePinch(bool zoomIn) { + void gesturePinch(bool zoomIn, bool tapOneByOne = false) { auto target = view.focusProxy(); QPoint p(target->width() / 2, target->height() / 2); auto t1 = p - QPoint(zoomIn ? 50 : 150, 10), t2 = p + QPoint(zoomIn ? 50 : 150, 10); - QTest::touchEvent(target, s_touchDevice).press(42, t1, target); - QTest::touchEvent(target, s_touchDevice).stationary(42).press(24, t2, target); + if (tapOneByOne) { + QTest::touchEvent(target, s_touchDevice).press(42, t1, target); + QTest::touchEvent(target, s_touchDevice).stationary(42).press(24, t2, target); + } else { + QTest::touchEvent(target, s_touchDevice).press(42, t1, target).press(24, t2, target); + } for (int i = 0; i < 3; ++i) { if (zoomIn) { @@ -95,8 +101,12 @@ private: QTest::touchEvent(target, s_touchDevice).move(24, t1, target).move(42, t2, target); } - QTest::touchEvent(target, s_touchDevice).stationary(42).release(24, t2, target); - QTest::touchEvent(target, s_touchDevice).release(42, t1, target); + if (tapOneByOne) { + QTest::touchEvent(target, s_touchDevice).stationary(42).release(24, t2, target); + QTest::touchEvent(target, s_touchDevice).release(42, t1, target); + } else { + QTest::touchEvent(target, s_touchDevice).release(42, t1, target).release(24, t2, target); + } } int getScrollPosition(int *position = nullptr) { @@ -275,18 +285,57 @@ void TouchInputTest::scrolling() QTRY_COMPARE(getScrollPosition(), 0); } +void TouchInputTest::pinchZoom_data() +{ + QTest::addColumn<bool>("tapOneByOne"); + QTest::addRow("sequential") << true; + QTest::addRow("simultaneous") << false; +} + void TouchInputTest::pinchZoom() { + QFETCH(bool, tapOneByOne); double scale = getScaleFactor(); QCOMPARE(scale, 1.0); for (int i = 0; i < 3; ++i) { - gesturePinch(/* zoomIn = */true); + gesturePinch(/* zoomIn = */true, tapOneByOne); QTRY_VERIFY2(getScaleFactor(&scale) > 1.5, qPrintable(QString("i: %1, scale: %2").arg(i).arg(scale))); - gesturePinch(/* zoomIn = */false); + gesturePinch(/* zoomIn = */false, tapOneByOne); QTRY_COMPARE(getScaleFactor(&scale), 1.0); } } +void TouchInputTest::complexSequence() +{ + auto t = view.focusProxy(); + QPoint pc(view.width() / 2, view.height() / 2), p1 = pc - QPoint(50, 25), p2 = pc + QPoint(50, 25); + + for (int i = 0; i < 4; ++i) { + QTest::touchEvent(t, s_touchDevice).press(42, p1, t); QTest::qWait(50); + QTest::touchEvent(t, s_touchDevice).stationary(42).press(24, p2, t); QTest::qWait(50); + QTest::touchEvent(t, s_touchDevice).release(42, p1, t).release(24, p2, t); + + // for additional variablity add zooming in on even steps and zooming out on odd steps + // MEMO scroll position will always be 0 while viewport scale factor > 1.0, so do zoom in after scroll + bool zoomIn = i % 2 == 0; + + if (!zoomIn) { + gesturePinch(false); + QTRY_COMPARE(getScaleFactor(), 1.0); + } + + int p = getScrollPosition(), positionBefore = p; + gestureScroll(true); + QTRY_VERIFY2_WITH_TIMEOUT(getScrollPosition(&p) > positionBefore, qPrintable(QString("i: %1, position: %2 -> %3").arg(i).arg(positionBefore).arg(p)), 1000); + + if (zoomIn) { + double s = getScaleFactor(), scaleBefore = s; + gesturePinch(true); + QTRY_VERIFY2(getScaleFactor(&s) > scaleBefore, qPrintable(QString("i: %1, scale: %2").arg(i).arg(s))); + } + } +} + QTEST_MAIN(TouchInputTest) #include "tst_touchinput.moc" |