diff options
Diffstat (limited to 'src/core/render_widget_host_view_qt_delegate_client.cpp')
-rw-r--r-- | src/core/render_widget_host_view_qt_delegate_client.cpp | 377 |
1 files changed, 182 insertions, 195 deletions
diff --git a/src/core/render_widget_host_view_qt_delegate_client.cpp b/src/core/render_widget_host_view_qt_delegate_client.cpp index 25344a1c4..3e8cad669 100644 --- a/src/core/render_widget_host_view_qt_delegate_client.cpp +++ b/src/core/render_widget_host_view_qt_delegate_client.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "render_widget_host_view_qt_delegate_client.h" @@ -47,18 +11,17 @@ #include "web_event_factory.h" #include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_input_event_router.h" #include "ui/touch_selection/touch_selection_controller.h" #include <QEvent> #include <QInputMethodEvent> -#include <QSGNode> +#include <QSet> #include <QStyleHints> #include <QTextFormat> #include <QVariant> -#include <private/qguiapplication_p.h> -#include <qpa/qplatforminputcontext.h> -#include <qpa/qplatformintegration.h> +#include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qinputcontrol_p.h> namespace QtWebEngineCore { @@ -72,39 +35,38 @@ static inline int firstAvailableId(const QMap<int, int> &map) return usedIds.first_unmarked_bit(); } -static QList<QTouchEvent::TouchPoint> -mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &inputPoints) +typedef QPair<int, QTouchEvent::TouchPoint> TouchPoint; +QList<TouchPoint> RenderWidgetHostViewQtDelegateClient::mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &input) { - static QMap<int, int> touchIdMapping; - QList<QTouchEvent::TouchPoint> outputPoints = inputPoints; - for (int i = 0; i < outputPoints.size(); ++i) { - QTouchEvent::TouchPoint &point = outputPoints[i]; + QList<TouchPoint> output; + for (int i = 0; i < input.size(); ++i) { + const QTouchEvent::TouchPoint &point = input[i]; int qtId = point.id(); - QMap<int, int>::const_iterator it = touchIdMapping.find(qtId); - if (it == touchIdMapping.end()) - it = touchIdMapping.insert(qtId, firstAvailableId(touchIdMapping)); - point.setId(it.value()); + QMap<int, int>::const_iterator it = m_touchIdMapping.find(qtId); + if (it == m_touchIdMapping.end()) { + Q_ASSERT_X(m_touchIdMapping.size() <= 16, "", "Number of mapped ids can't exceed 16 for velocity tracker"); + it = m_touchIdMapping.insert(qtId, firstAvailableId(m_touchIdMapping)); + } - if (point.state() == Qt::TouchPointReleased) - touchIdMapping.remove(qtId); + output.append(qMakePair(it.value(), point)); } - return outputPoints; -} + Q_ASSERT(output.size() == std::accumulate(output.cbegin(), output.cend(), QSet<int>(), + [] (QSet<int> s, const TouchPoint &p) { s.insert(p.second.id()); return s; }).size()); -static inline bool compareTouchPoints(const QTouchEvent::TouchPoint &lhs, - const QTouchEvent::TouchPoint &rhs) -{ - // TouchPointPressed < TouchPointMoved < TouchPointReleased - return lhs.state() < rhs.state(); + for (auto &&point : std::as_const(input)) + if (point.state() == QEventPoint::Released) + m_touchIdMapping.remove(point.id()); + + return output; } static uint32_t s_eventId = 0; class MotionEventQt : public ui::MotionEvent { public: - MotionEventQt(const QList<QTouchEvent::TouchPoint> &touchPoints, + MotionEventQt(const QList<TouchPoint> &touchPoints, const base::TimeTicks &eventTime, Action action, const Qt::KeyboardModifiers modifiers, int index = -1) : touchPoints(touchPoints) @@ -114,8 +76,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() == QEventPoint::Pressed) + || (action == Action::POINTER_UP && index >= 0 && touchPoint(index).state() == QEventPoint::Released), + "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; } @@ -124,39 +90,39 @@ public: size_t GetPointerCount() const override { return touchPoints.size(); } int GetPointerId(size_t pointer_index) const override { - return touchPoints.at(pointer_index).id(); + return touchPoints[pointer_index].first; } float GetX(size_t pointer_index) const override { - return touchPoints.at(pointer_index).pos().x(); + return touchPoint(pointer_index).position().x(); } float GetY(size_t pointer_index) const override { - return touchPoints.at(pointer_index).pos().y(); + return touchPoint(pointer_index).position().y(); } float GetRawX(size_t pointer_index) const override { - return touchPoints.at(pointer_index).screenPos().x(); + return touchPoint(pointer_index).globalPosition().x(); } float GetRawY(size_t pointer_index) const override { - return touchPoints.at(pointer_index).screenPos().y(); + return touchPoint(pointer_index).globalPosition().y(); } float GetTouchMajor(size_t pointer_index) const override { - QSizeF diams = touchPoints.at(pointer_index).ellipseDiameters(); + QSizeF diams = touchPoint(pointer_index).ellipseDiameters(); return std::max(diams.height(), diams.width()); } float GetTouchMinor(size_t pointer_index) const override { - QSizeF diams = touchPoints.at(pointer_index).ellipseDiameters(); + QSizeF diams = touchPoint(pointer_index).ellipseDiameters(); return std::min(diams.height(), diams.width()); } float GetOrientation(size_t pointer_index) const override { return 0; } int GetFlags() const override { return flags; } float GetPressure(size_t pointer_index) const override { - return touchPoints.at(pointer_index).pressure(); + return touchPoint(pointer_index).pressure(); } float GetTiltX(size_t pointer_index) const override { return 0; } float GetTiltY(size_t pointer_index) const override { return 0; } @@ -177,19 +143,19 @@ public: float GetHistoricalY(size_t pointer_index, size_t historical_index) const override { return 0; } ToolType GetToolType(size_t pointer_index) const override { - return (touchPoints.at(pointer_index).flags() & QTouchEvent::TouchPoint::InfoFlag::Pen) - ? ui::MotionEvent::ToolType::STYLUS - : ui::MotionEvent::ToolType::FINGER; + return ui::MotionEvent::ToolType::FINGER; } + int GetButtonState() const override { return 0; } private: - QList<QTouchEvent::TouchPoint> touchPoints; + QList<TouchPoint> touchPoints; base::TimeTicks eventTime; Action action; const uint32_t eventId; int flags; int index; + const QTouchEvent::TouchPoint& touchPoint(size_t i) const { return touchPoints[i].second; } }; RenderWidgetHostViewQtDelegateClient::RenderWidgetHostViewQtDelegateClient( @@ -197,11 +163,6 @@ RenderWidgetHostViewQtDelegateClient::RenderWidgetHostViewQtDelegateClient( : m_rwhv(rwhv) { Q_ASSERT(rwhv); - - const QPlatformInputContext *context = - QGuiApplicationPrivate::platformIntegration()->inputContext(); - m_imeHasHiddenTextCapability = - context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); } Compositor::Id RenderWidgetHostViewQtDelegateClient::compositorId() @@ -237,7 +198,7 @@ void RenderWidgetHostViewQtDelegateClient::visualPropertiesChanged() m_rwhv->host()->SendScreenRects(); if (m_viewRectInDips.size() != oldViewRect.size() || screenInfoChanged) - m_rwhv->synchronizeVisualProperties(base::nullopt); + m_rwhv->synchronizeVisualProperties(absl::nullopt); } bool RenderWidgetHostViewQtDelegateClient::forwardEvent(QEvent *event) @@ -247,7 +208,7 @@ bool RenderWidgetHostViewQtDelegateClient::forwardEvent(QEvent *event) switch (event->type()) { case QEvent::ShortcutOverride: { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); - + event->ignore(); auto acceptKeyOutOfInputField = [](QKeyEvent *keyEvent) -> bool { #ifdef Q_OS_MACOS // Check if a shortcut is registered for this key sequence. @@ -331,9 +292,13 @@ bool RenderWidgetHostViewQtDelegateClient::forwardEvent(QEvent *event) handleHoverEvent(static_cast<QHoverEvent *>(event)); break; case QEvent::FocusIn: - case QEvent::FocusOut: - handleFocusEvent(static_cast<QFocusEvent *>(event)); - break; + case QEvent::FocusOut: { + // Focus in/out events for popup event do not mean 'parent' focus change + // and should not be handled by Chromium + QFocusEvent *e = static_cast<QFocusEvent *>(event); + if (e->reason() != Qt::PopupFocusReason) + handleFocusEvent(e); + } break; case QEvent::InputMethod: handleInputMethodEvent(static_cast<QInputMethodEvent *>(event)); break; @@ -346,7 +311,10 @@ bool RenderWidgetHostViewQtDelegateClient::forwardEvent(QEvent *event) return false; #endif case QEvent::HoverLeave: - m_rwhv->host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(event)); + if (m_rwhv->host()->delegate() && m_rwhv->host()->delegate()->GetInputEventRouter()) { + auto webEvent = WebEventFactory::toWebMouseEvent(event); + m_rwhv->host()->delegate()->GetInputEventRouter()->RouteMouseEvent(m_rwhv, &webEvent, ui::LatencyInfo()); + } break; default: return false; @@ -357,17 +325,8 @@ bool RenderWidgetHostViewQtDelegateClient::forwardEvent(QEvent *event) QVariant RenderWidgetHostViewQtDelegateClient::inputMethodQuery(Qt::InputMethodQuery query) { switch (query) { - case Qt::ImEnabled: { - ui::TextInputType type = m_rwhv->getTextInputType(); - bool editorVisible = type != ui::TEXT_INPUT_TYPE_NONE; - // IME manager should disable composition on input fields with ImhHiddenText hint if - // supported - if (m_imeHasHiddenTextCapability) - return QVariant(editorVisible); - - bool passwordInput = type == ui::TEXT_INPUT_TYPE_PASSWORD; - return QVariant(editorVisible && !passwordInput); - } + case Qt::ImEnabled: + return QVariant(m_rwhv->getTextInputType() != ui::TEXT_INPUT_TYPE_NONE); case Qt::ImFont: // TODO: Implement this return QVariant(); @@ -385,6 +344,7 @@ QVariant RenderWidgetHostViewQtDelegateClient::inputMethodQuery(Qt::InputMethodQ } return QVariant(); } + case Qt::ImAbsolutePosition: case Qt::ImCursorPosition: return m_cursorPosition; case Qt::ImAnchorPosition: @@ -398,12 +358,8 @@ QVariant RenderWidgetHostViewQtDelegateClient::inputMethodQuery(Qt::InputMethodQ // TODO: Implement this return QVariant(); // No limit. case Qt::ImHints: -#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) return int(toQtInputMethodHints(m_rwhv->getTextInputType()) | Qt::ImhNoPredictiveText | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu); -#else - return int(toQtInputMethodHints(m_rwhv->getTextInputType()) | Qt::ImhNoPredictiveText); -#endif default: return QVariant(); } @@ -424,8 +380,8 @@ void RenderWidgetHostViewQtDelegateClient::handlePointerEvent(T *event) // Currently WebMouseEvent is a subclass of WebPointerProperties, so basically // tablet events are mouse events with extra properties. blink::WebMouseEvent webEvent = WebEventFactory::toWebMouseEvent(event); - if ((webEvent.GetType() == blink::WebInputEvent::kMouseDown - || webEvent.GetType() == blink::WebInputEvent::kMouseUp) + if ((webEvent.GetType() == blink::WebInputEvent::Type::kMouseDown + || webEvent.GetType() == blink::WebInputEvent::Type::kMouseUp) && webEvent.button == blink::WebMouseEvent::Button::kNoButton) { // Blink can only handle the 5 main mouse-buttons and may assert when processing mouse-down // for no button. @@ -433,11 +389,11 @@ void RenderWidgetHostViewQtDelegateClient::handlePointerEvent(T *event) return; } - if (webEvent.GetType() == blink::WebInputEvent::kMouseDown) { + if (webEvent.GetType() == blink::WebInputEvent::Type::kMouseDown) { if (event->button() != m_clickHelper.lastPressButton || (event->timestamp() - m_clickHelper.lastPressTimestamp > static_cast<ulong>(qGuiApp->styleHints()->mouseDoubleClickInterval())) - || (event->pos() - m_clickHelper.lastPressPosition).manhattanLength() + || (event->position() - m_clickHelper.lastPressPosition).manhattanLength() > qGuiApp->styleHints()->startDragDistance() || m_clickHelper.clickCounter >= 3) m_clickHelper.clickCounter = 0; @@ -445,21 +401,22 @@ void RenderWidgetHostViewQtDelegateClient::handlePointerEvent(T *event) m_clickHelper.lastPressTimestamp = event->timestamp(); webEvent.click_count = ++m_clickHelper.clickCounter; m_clickHelper.lastPressButton = event->button(); - m_clickHelper.lastPressPosition = QPointF(event->pos()).toPoint(); + m_clickHelper.lastPressPosition = event->position().toPoint(); } - if (webEvent.GetType() == blink::WebInputEvent::kMouseUp) + if (webEvent.GetType() == blink::WebInputEvent::Type::kMouseUp) webEvent.click_count = m_clickHelper.clickCounter; - webEvent.movement_x = event->globalX() - m_previousMousePosition.x(); - webEvent.movement_y = event->globalY() - m_previousMousePosition.y(); + webEvent.movement_x = event->globalPosition().x() - m_previousMousePosition.x(); + webEvent.movement_y = event->globalPosition().y() - m_previousMousePosition.y(); + webEvent.is_raw_movement_event = true; if (m_rwhv->IsMouseLocked()) QCursor::setPos(m_previousMousePosition); else - m_previousMousePosition = event->globalPos(); + m_previousMousePosition = event->globalPosition().toPoint(); - if (m_imeInProgress && webEvent.GetType() == blink::WebInputEvent::kMouseDown) { + if (m_imeInProgress && webEvent.GetType() == blink::WebInputEvent::Type::kMouseDown) { m_imeInProgress = false; // Tell input method to commit the pre-edit string entered so far, and finish the // composition operation. @@ -472,7 +429,8 @@ void RenderWidgetHostViewQtDelegateClient::handlePointerEvent(T *event) #endif } - m_rwhv->host()->ForwardMouseEvent(webEvent); + if (m_rwhv->host()->delegate() && m_rwhv->host()->delegate()->GetInputEventRouter()) + m_rwhv->host()->delegate()->GetInputEventRouter()->RouteMouseEvent(m_rwhv, &webEvent, ui::LatencyInfo()); } void RenderWidgetHostViewQtDelegateClient::handleMouseEvent(QMouseEvent *event) @@ -482,12 +440,6 @@ void RenderWidgetHostViewQtDelegateClient::handleMouseEvent(QMouseEvent *event) if (event->type() == QEvent::MouseButtonRelease) m_mouseButtonPressed--; - // Don't forward mouse events synthesized by the system, which are caused by genuine touch - // events. Chromium would then process for e.g. a mouse click handler twice, once due to the - // system synthesized mouse event, and another time due to a touch-to-gesture-to-mouse - // transformation done by Chromium. - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; handlePointerEvent<QMouseEvent>(event); } @@ -524,29 +476,32 @@ void RenderWidgetHostViewQtDelegateClient::handleKeyEvent(QKeyEvent *event) if (event->type() == QEvent::KeyRelease && event->isAutoRepeat()) return; + if (!m_rwhv->GetFocusedWidget()) + return; + content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(event); - if (webEvent.GetType() == blink::WebInputEvent::kRawKeyDown && !m_editCommand.empty()) { + if (webEvent.GetType() == blink::WebInputEvent::Type::kRawKeyDown && !m_editCommand.empty()) { ui::LatencyInfo latency; latency.set_source_event_type(ui::SourceEventType::KEY_PRESS); - content::EditCommands commands; - commands.emplace_back(m_editCommand, ""); + std::vector<blink::mojom::EditCommandPtr> commands; + commands.emplace_back(blink::mojom::EditCommand::New(m_editCommand, "")); m_editCommand.clear(); - m_rwhv->host()->ForwardKeyboardEventWithCommands(webEvent, latency, &commands, nullptr); + m_rwhv->GetFocusedWidget()->ForwardKeyboardEventWithCommands(webEvent, latency, std::move(commands), nullptr); return; } bool keyDownTextInsertion = - webEvent.GetType() == blink::WebInputEvent::kRawKeyDown && webEvent.text[0]; - webEvent.skip_in_browser = keyDownTextInsertion; - m_rwhv->host()->ForwardKeyboardEvent(webEvent); + webEvent.GetType() == blink::WebInputEvent::Type::kRawKeyDown && webEvent.text[0]; + webEvent.skip_if_unhandled = keyDownTextInsertion; + m_rwhv->GetFocusedWidget()->ForwardKeyboardEvent(webEvent); if (keyDownTextInsertion) { // Blink won't consume the RawKeyDown, but rather the Char event in this case. // The RawKeyDown is skipped on the way back (see above). // The same os_event will be set on both NativeWebKeyboardEvents. - webEvent.skip_in_browser = false; - webEvent.SetType(blink::WebInputEvent::kChar); - m_rwhv->host()->ForwardKeyboardEvent(webEvent); + webEvent.skip_if_unhandled = false; + webEvent.SetType(blink::WebInputEvent::Type::kChar); + m_rwhv->GetFocusedWidget()->ForwardKeyboardEvent(webEvent); } } @@ -567,59 +522,70 @@ void RenderWidgetHostViewQtDelegateClient::handleTouchEvent(QTouchEvent *event) // Calculate a delta between event timestamps and Now() on the first received event, and // apply this delta to all successive events. This delta is most likely smaller than it // should by calculating it here but this will hopefully cause less than one frame of delay. - base::TimeTicks eventTimestamp = - base::TimeTicks() + base::TimeDelta::FromMilliseconds(event->timestamp()); - static base::TimeDelta eventsToNowDelta = base::TimeTicks::Now() - eventTimestamp; - eventTimestamp += eventsToNowDelta; + base::TimeTicks eventTimestamp = base::TimeTicks() + base::Milliseconds(event->timestamp()); + if (m_eventsToNowDelta == 0) + m_eventsToNowDelta = (base::TimeTicks::Now() - eventTimestamp).InMicroseconds(); + eventTimestamp += base::Microseconds(m_eventsToNowDelta); + + auto touchPoints = mapTouchPointIds(event->points()); + // Make sure that POINTER_DOWN action is delivered before MOVE, and MOVE before POINTER_UP + std::sort(touchPoints.begin(), touchPoints.end(), [] (const TouchPoint &l, const TouchPoint &r) { + return l.second.state() < r.second.state(); + }); + + auto sc = qScopeGuard([&] () { + switch (event->type()) { + case QEvent::TouchCancel: + for (auto &&it : std::as_const(touchPoints)) + m_touchIdMapping.remove(it.second.id()); + Q_FALLTHROUGH(); + + case QEvent::TouchEnd: + m_previousTouchPoints.clear(); + m_touchMotionStarted = false; + break; - QList<QTouchEvent::TouchPoint> touchPoints = mapTouchPointIds(event->touchPoints()); - // Make sure that ACTION_POINTER_DOWN is delivered before ACTION_MOVE, - // and ACTION_MOVE before ACTION_POINTER_UP. - std::sort(touchPoints.begin(), touchPoints.end(), compareTouchPoints); + default: + m_previousTouchPoints = touchPoints; + break; + } + }); + ui::MotionEvent::Action action; // Check first if the touch event should be routed to the selectionController if (!touchPoints.isEmpty()) { - ui::MotionEvent::Action action; - switch (touchPoints[0].state()) { - case Qt::TouchPointPressed: + switch (touchPoints[0].second.state()) { + case QEventPoint::Pressed: action = ui::MotionEvent::Action::DOWN; break; - case Qt::TouchPointMoved: + case QEventPoint::Updated: action = ui::MotionEvent::Action::MOVE; break; - case Qt::TouchPointReleased: + case QEventPoint::Released: action = ui::MotionEvent::Action::UP; break; default: action = ui::MotionEvent::Action::NONE; break; } - - MotionEventQt motionEvent(touchPoints, eventTimestamp, action, event->modifiers(), 0); - if (m_rwhv->getTouchSelectionController()->WillHandleTouchEvent(motionEvent)) { - m_previousTouchPoints = touchPoints; - event->accept(); - return; - } } else { // An empty touchPoints always corresponds to a TouchCancel event. // We can't forward touch cancellations without a previously processed touch event, // as Chromium expects the previous touchPoints for Action::CANCEL. // If both are empty that means the TouchCancel was sent without an ongoing touch, // so there's nothing to cancel anyway. + Q_ASSERT(event->type() == QEvent::TouchCancel); touchPoints = m_previousTouchPoints; if (touchPoints.isEmpty()) return; - MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, - event->modifiers()); - if (m_rwhv->getTouchSelectionController()->WillHandleTouchEvent(cancelEvent)) { - m_previousTouchPoints.clear(); - event->accept(); - return; - } + action = ui::MotionEvent::Action::CANCEL; } + MotionEventQt me(touchPoints, eventTimestamp, action, event->modifiers()); + if (m_rwhv->getTouchSelectionController()->WillHandleTouchEvent(me)) + return; + switch (event->type()) { case QEvent::TouchBegin: m_sendMotionActionDown = true; @@ -629,19 +595,17 @@ void RenderWidgetHostViewQtDelegateClient::handleTouchEvent(QTouchEvent *event) case QEvent::TouchUpdate: m_touchMotionStarted = true; break; - case QEvent::TouchCancel: { + case QEvent::TouchCancel: + { // Only process TouchCancel events received following a TouchBegin or TouchUpdate event if (m_touchMotionStarted) { - MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, - event->modifiers()); + MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, event->modifiers()); m_rwhv->processMotionEvent(cancelEvent); } - clearPreviousTouchMotionState(); return; } case QEvent::TouchEnd: - clearPreviousTouchMotionState(); m_rwhv->getTouchSelectionControllerClient()->onTouchUp(); break; default: @@ -661,34 +625,50 @@ void RenderWidgetHostViewQtDelegateClient::handleTouchEvent(QTouchEvent *event) #endif } - for (int i = 0; i < touchPoints.size(); ++i) { - ui::MotionEvent::Action action; - switch (touchPoints[i].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() == QEventPoint::Pressed) + ++lastPressIndex; + + switch (event->type()) { + case QEvent::TouchBegin: + m_rwhv->processMotionEvent(MotionEventQt(touchPoints.mid(lastPressIndex), + eventTimestamp, ui::MotionEvent::Action::DOWN, event->modifiers())); + --lastPressIndex; + Q_FALLTHROUGH(); + + case QEvent::TouchUpdate: + for (; lastPressIndex >= 0; --lastPressIndex) { + Q_ASSERT(touchPoints[lastPressIndex].second.state() == QEventPoint::Pressed); + MotionEventQt me(touchPoints.mid(lastPressIndex), eventTimestamp, ui::MotionEvent::Action::POINTER_DOWN, event->modifiers(), 0); + m_rwhv->processMotionEvent(me); + } + + if (event->touchPointStates() & Qt::TouchPointMoved) + m_rwhv->processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, ui::MotionEvent::Action::MOVE, event->modifiers())); + + Q_FALLTHROUGH(); + + case QEvent::TouchEnd: + while (!touchPoints.isEmpty() && touchPoints.back().second.state() == QEventPoint::Released) { + 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; + m_rwhv->processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, action, event->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, event->modifiers(), i); - m_rwhv->processMotionEvent(motionEvent); + default: + Q_ASSERT_X(false, __FUNCTION__, "Other event types are expected to be already handled."); + break; } - - m_previousTouchPoints = touchPoints; } #if QT_CONFIG(tabletevent) @@ -703,15 +683,24 @@ void RenderWidgetHostViewQtDelegateClient::handleGestureEvent(QNativeGestureEven { const Qt::NativeGestureType type = event->gestureType(); // These are the only supported gestures by Chromium so far. - if (type == Qt::ZoomNativeGesture || type == Qt::SmartZoomNativeGesture) { - m_rwhv->host()->ForwardGestureEvent(WebEventFactory::toWebGestureEvent(event)); + if (type == Qt::ZoomNativeGesture || type == Qt::SmartZoomNativeGesture + || type == Qt::BeginNativeGesture || type == Qt::EndNativeGesture) { + auto *hostDelegate = m_rwhv->host()->delegate(); + if (hostDelegate && hostDelegate->GetInputEventRouter()) { + auto webEvent = WebEventFactory::toWebGestureEvent(event); + hostDelegate->GetInputEventRouter()->RouteGestureEvent(m_rwhv, &webEvent, ui::LatencyInfo()); + } } } #endif void RenderWidgetHostViewQtDelegateClient::handleHoverEvent(QHoverEvent *event) { - m_rwhv->host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(event)); + auto *hostDelegate = m_rwhv->host()->delegate(); + if (hostDelegate && hostDelegate->GetInputEventRouter()) { + auto webEvent = WebEventFactory::toWebMouseEvent(event); + hostDelegate->GetInputEventRouter()->RouteMouseEvent(m_rwhv, &webEvent, ui::LatencyInfo()); + } } void RenderWidgetHostViewQtDelegateClient::handleFocusEvent(QFocusEvent *event) @@ -770,6 +759,7 @@ void RenderWidgetHostViewQtDelegateClient::handleInputMethodEvent(QInputMethodEv underlines.push_back(ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, start, end, ui::ImeTextSpan::Thickness::kThin, + ui::ImeTextSpan::UnderlineStyle::kSolid, SK_ColorTRANSPARENT)); QTextCharFormat format = qvariant_cast<QTextFormat>(attribute.value).toCharFormat(); @@ -813,10 +803,8 @@ void RenderWidgetHostViewQtDelegateClient::handleInputMethodEvent(QInputMethodEv } if (hasSelection) { - content::mojom::FrameInputHandler *frameInputHandler = m_rwhv->getFrameInputHandler(); - if (frameInputHandler) - frameInputHandler->SetEditableSelectionOffsets(selectionRange.start(), - selectionRange.end()); + if (auto *frameWidgetInputHandler = m_rwhv->getFrameWidgetInputHandler()) + frameWidgetInputHandler->SetEditableSelectionOffsets(selectionRange.start(), selectionRange.end()); } int replacementLength = event->replacementLength(); @@ -844,8 +832,7 @@ void RenderWidgetHostViewQtDelegateClient::handleInputMethodEvent(QInputMethodEv if (commitString.isEmpty() && preeditString.isEmpty() && replacementLength == 0) { if (!m_receivedEmptyImeEvent && m_imeInProgress && !hasSelection) { m_receivedEmptyImeEvent = true; - QInputMethodEvent *eventCopy = new QInputMethodEvent(*event); - QGuiApplication::postEvent(qApp->focusObject(), eventCopy); + QGuiApplication::postEvent(qApp->focusObject(), event->clone()); } else { m_receivedEmptyImeEvent = false; if (m_imeInProgress) { @@ -922,7 +909,7 @@ void RenderWidgetHostViewQtDelegateClient::selectionChanged() // position if the selection is cleared because TextInputState changes before the // TextSelection change. Q_ASSERT(text_input_manager->GetTextInputState()); - m_cursorPosition = text_input_manager->GetTextInputState()->selection_start; + m_cursorPosition = text_input_manager->GetTextInputState()->selection.start(); m_rwhv->delegate()->inputMethodStateChanged(true /*editorVisible*/, type == ui::TEXT_INPUT_TYPE_PASSWORD); |