blob: ff807e388fec0e4815b0f06fb4a54ac42345326b [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/input/legacy_input_router_impl.h"
#include <math.h>
#include <utility>
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "content/browser/renderer_host/input/gesture_event_queue.h"
#include "content/browser/renderer_host/input/input_disposition_handler.h"
#include "content/browser/renderer_host/input/input_router_client.h"
#include "content/browser/renderer_host/input/legacy_touch_event_queue.h"
#include "content/browser/renderer_host/input/passthrough_touch_event_queue.h"
#include "content/browser/renderer_host/input/touch_event_queue.h"
#include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
#include "content/common/content_constants_internal.h"
#include "content/common/edit_command.h"
#include "content/common/input/input_event_ack_state.h"
#include "content/common/input/web_touch_event_traits.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "ipc/ipc_sender.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/blink/web_input_event_traits.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
using blink::WebGestureEvent;
using blink::WebInputEvent;
using blink::WebKeyboardEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
using blink::WebTouchEvent;
using ui::WebInputEventTraits;
namespace content {
namespace {
const char* GetEventAckName(InputEventAckState ack_result) {
switch (ack_result) {
case INPUT_EVENT_ACK_STATE_UNKNOWN:
return "UNKNOWN";
case INPUT_EVENT_ACK_STATE_CONSUMED:
return "CONSUMED";
case INPUT_EVENT_ACK_STATE_NOT_CONSUMED:
return "NOT_CONSUMED";
case INPUT_EVENT_ACK_STATE_CONSUMED_SHOULD_BUBBLE:
return "CONSUMED_SHOULD_BUBBLE";
case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
return "NO_CONSUMER_EXISTS";
case INPUT_EVENT_ACK_STATE_IGNORED:
return "IGNORED";
case INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING:
return "SET_NON_BLOCKING";
case INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING_DUE_TO_FLING:
return "SET_NON_BLOCKING_DUE_TO_FLING";
}
DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName.";
return "";
}
} // namespace
LegacyInputRouterImpl::LegacyInputRouterImpl(
IPC::Sender* sender,
InputRouterClient* client,
InputDispositionHandler* disposition_handler,
int routing_id,
const Config& config)
: sender_(sender),
client_(client),
disposition_handler_(disposition_handler),
routing_id_(routing_id),
frame_tree_node_id_(-1),
select_message_pending_(false),
move_caret_pending_(false),
current_ack_source_(ACK_SOURCE_NONE),
active_renderer_fling_count_(0),
touch_scroll_started_sent_(false),
wheel_scroll_latching_enabled_(base::FeatureList::IsEnabled(
features::kTouchpadAndWheelScrollLatching)),
wheel_event_queue_(this, wheel_scroll_latching_enabled_),
gesture_event_queue_(this, this, config.gesture_config),
device_scale_factor_(1.f),
raf_aligned_touch_enabled_(
base::FeatureList::IsEnabled(features::kRafAlignedTouchInputEvents)) {
if (raf_aligned_touch_enabled_) {
touch_event_queue_.reset(
new PassthroughTouchEventQueue(this, config.touch_config));
} else {
touch_event_queue_.reset(
new LegacyTouchEventQueue(this, config.touch_config));
}
DCHECK(sender);
DCHECK(client);
DCHECK(disposition_handler);
UpdateTouchAckTimeoutEnabled();
}
LegacyInputRouterImpl::~LegacyInputRouterImpl() {}
bool LegacyInputRouterImpl::SendInput(std::unique_ptr<IPC::Message> message) {
DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart);
switch (message->type()) {
// Check for types that require an ACK.
case InputMsg_SelectRange::ID:
case InputMsg_MoveRangeSelectionExtent::ID:
return SendSelectMessage(std::move(message));
case InputMsg_MoveCaret::ID:
return SendMoveCaret(std::move(message));
case InputMsg_HandleInputEvent::ID:
NOTREACHED() << "WebInputEvents should never be sent via SendInput.";
return false;
default:
return Send(message.release());
}
}
void LegacyInputRouterImpl::SendMouseEvent(
const MouseEventWithLatencyInfo& mouse_event) {
if (mouse_event.event.GetType() == WebInputEvent::kMouseDown &&
gesture_event_queue_.GetTouchpadTapSuppressionController()
->ShouldDeferMouseDown(mouse_event))
return;
if (mouse_event.event.GetType() == WebInputEvent::kMouseUp &&
gesture_event_queue_.GetTouchpadTapSuppressionController()
->ShouldSuppressMouseUp())
return;
SendMouseEventImmediately(mouse_event);
}
void LegacyInputRouterImpl::SendWheelEvent(
const MouseWheelEventWithLatencyInfo& wheel_event) {
wheel_event_queue_.QueueEvent(wheel_event);
}
void LegacyInputRouterImpl::SendKeyboardEvent(
const NativeWebKeyboardEventWithLatencyInfo& key_event) {
// Put all WebKeyboardEvent objects in a queue since we can't trust the
// renderer and we need to give something to the HandleKeyboardEvent
// handler.
key_queue_.push_back(key_event);
LOCAL_HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
gesture_event_queue_.FlingHasBeenHalted();
// Only forward the non-native portions of our event.
FilterAndSendWebInputEvent(key_event.event, key_event.latency);
}
void LegacyInputRouterImpl::SendGestureEvent(
const GestureEventWithLatencyInfo& original_gesture_event) {
input_stream_validator_.Validate(original_gesture_event.event);
GestureEventWithLatencyInfo gesture_event(original_gesture_event);
if (touch_action_filter_.FilterGestureEvent(&gesture_event.event))
return;
wheel_event_queue_.OnGestureScrollEvent(gesture_event);
if (gesture_event.event.source_device ==
blink::kWebGestureDeviceTouchscreen) {
if (gesture_event.event.GetType() ==
blink::WebInputEvent::kGestureScrollBegin) {
touch_scroll_started_sent_ = false;
} else if (!touch_scroll_started_sent_ &&
gesture_event.event.GetType() ==
blink::WebInputEvent::kGestureScrollUpdate) {
// A touch scroll hasn't really started until the first
// GestureScrollUpdate event. Eg. if the page consumes all touchmoves
// then no scrolling really ever occurs (even though we still send
// GestureScrollBegin).
touch_scroll_started_sent_ = true;
touch_event_queue_->PrependTouchScrollNotification();
}
touch_event_queue_->OnGestureScrollEvent(gesture_event);
}
gesture_event_queue_.QueueEvent(gesture_event);
}
void LegacyInputRouterImpl::SendTouchEvent(
const TouchEventWithLatencyInfo& touch_event) {
TouchEventWithLatencyInfo updatd_touch_event = touch_event;
SetMovementXYForTouchPoints(&updatd_touch_event.event);
input_stream_validator_.Validate(updatd_touch_event.event);
touch_event_queue_->QueueEvent(updatd_touch_event);
}
// Forwards MouseEvent without passing it through
// TouchpadTapSuppressionController.
void LegacyInputRouterImpl::SendMouseEventImmediately(
const MouseEventWithLatencyInfo& mouse_event) {
mouse_event_queue_.push_back(mouse_event);
FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency);
}
void LegacyInputRouterImpl::SendTouchEventImmediately(
const TouchEventWithLatencyInfo& touch_event) {
FilterAndSendWebInputEvent(touch_event.event, touch_event.latency);
}
void LegacyInputRouterImpl::SendGestureEventImmediately(
const GestureEventWithLatencyInfo& gesture_event) {
FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency);
}
void LegacyInputRouterImpl::NotifySiteIsMobileOptimized(
bool is_mobile_optimized) {
touch_event_queue_->SetIsMobileOptimizedSite(is_mobile_optimized);
}
bool LegacyInputRouterImpl::HasPendingEvents() const {
return !touch_event_queue_->Empty() || !gesture_event_queue_.empty() ||
!key_queue_.empty() || !mouse_event_queue_.empty() ||
wheel_event_queue_.has_pending() || select_message_pending_ ||
move_caret_pending_ || active_renderer_fling_count_ > 0;
}
void LegacyInputRouterImpl::SetDeviceScaleFactor(float device_scale_factor) {
device_scale_factor_ = device_scale_factor;
}
bool LegacyInputRouterImpl::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(LegacyInputRouterImpl, message)
IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck)
IPC_MESSAGE_HANDLER(InputHostMsg_DidOverscroll, OnDidOverscroll)
IPC_MESSAGE_HANDLER(InputHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck)
IPC_MESSAGE_HANDLER(InputHostMsg_SelectRange_ACK, OnSelectMessageAck)
IPC_MESSAGE_HANDLER(InputHostMsg_MoveRangeSelectionExtent_ACK,
OnSelectMessageAck)
IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
OnHasTouchEventHandlers)
IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction, OnSetTouchAction)
IPC_MESSAGE_HANDLER(InputHostMsg_SetWhiteListedTouchAction,
OnSetWhiteListedTouchAction)
IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging, OnDidStopFlinging)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void LegacyInputRouterImpl::OnTouchEventAck(
const TouchEventWithLatencyInfo& event,
InputEventAckState ack_result) {
// Touchstart events sent to the renderer indicate a new touch sequence, but
// in some cases we may filter out sending the touchstart - catch those here.
if (WebTouchEventTraits::IsTouchSequenceStart(event.event) &&
ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
touch_action_filter_.ResetTouchAction();
UpdateTouchAckTimeoutEnabled();
}
disposition_handler_->OnTouchEventAck(event, ack_result);
// Reset the touch action at the end of a touch-action sequence.
if (WebTouchEventTraits::IsTouchSequenceEnd(event.event)) {
touch_action_filter_.ReportAndResetTouchAction();
UpdateTouchAckTimeoutEnabled();
}
}
void LegacyInputRouterImpl::OnFilteringTouchEvent(
const WebTouchEvent& touch_event) {
// The event stream given to the renderer is not guaranteed to be
// valid based on the current TouchEventStreamValidator rules. This event will
// never be given to the renderer, but in order to ensure that the event
// stream |output_stream_validator_| sees is valid, we give events which are
// filtered out to the validator. crbug.com/589111 proposes adding an
// additional validator for the events which are actually sent to the
// renderer.
output_stream_validator_.Validate(touch_event);
}
void LegacyInputRouterImpl::OnGestureEventAck(
const GestureEventWithLatencyInfo& event,
InputEventAckState ack_result) {
touch_event_queue_->OnGestureEventAck(event, ack_result);
disposition_handler_->OnGestureEventAck(event, ack_result);
}
void LegacyInputRouterImpl::ForwardGestureEventWithLatencyInfo(
const blink::WebGestureEvent& event,
const ui::LatencyInfo& latency_info) {
client_->ForwardGestureEventWithLatencyInfo(event, latency_info);
}
void LegacyInputRouterImpl::SendMouseWheelEventImmediately(
const MouseWheelEventWithLatencyInfo& wheel_event) {
FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency);
}
void LegacyInputRouterImpl::OnMouseWheelEventAck(
const MouseWheelEventWithLatencyInfo& event,
InputEventAckState ack_result) {
disposition_handler_->OnWheelEventAck(event, ack_result);
}
bool LegacyInputRouterImpl::SendSelectMessage(
std::unique_ptr<IPC::Message> message) {
DCHECK(message->type() == InputMsg_SelectRange::ID ||
message->type() == InputMsg_MoveRangeSelectionExtent::ID);
// TODO(jdduke): Factor out common logic between selection and caret-related
// IPC messages.
if (select_message_pending_) {
if (!pending_select_messages_.empty() &&
pending_select_messages_.back()->type() == message->type()) {
pending_select_messages_.pop_back();
}
pending_select_messages_.push_back(std::move(message));
return true;
}
select_message_pending_ = true;
return Send(message.release());
}
bool LegacyInputRouterImpl::SendMoveCaret(
std::unique_ptr<IPC::Message> message) {
DCHECK(message->type() == InputMsg_MoveCaret::ID);
if (move_caret_pending_) {
next_move_caret_ = std::move(message);
return true;
}
move_caret_pending_ = true;
return Send(message.release());
}
bool LegacyInputRouterImpl::Send(IPC::Message* message) {
return sender_->Send(message);
}
void LegacyInputRouterImpl::FilterAndSendWebInputEvent(
const WebInputEvent& input_event,
const ui::LatencyInfo& latency_info) {
TRACE_EVENT1("input", "LegacyInputRouterImpl::FilterAndSendWebInputEvent",
"type", WebInputEvent::GetName(input_event.GetType()));
TRACE_EVENT_WITH_FLOW2(
"input,benchmark,devtools.timeline", "LatencyInfo.Flow",
TRACE_ID_DONT_MANGLE(latency_info.trace_id()),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
"SendInputEventUI", "frameTreeNodeId", frame_tree_node_id_);
OfferToHandlers(input_event, latency_info);
}
void LegacyInputRouterImpl::OfferToHandlers(
const WebInputEvent& input_event,
const ui::LatencyInfo& latency_info) {
output_stream_validator_.Validate(input_event);
if (OfferToClient(input_event, latency_info))
return;
bool should_block = WebInputEventTraits::ShouldBlockEventStream(
input_event, raf_aligned_touch_enabled_, wheel_scroll_latching_enabled_);
OfferToRenderer(input_event, latency_info,
should_block
? InputEventDispatchType::DISPATCH_TYPE_BLOCKING
: InputEventDispatchType::DISPATCH_TYPE_NON_BLOCKING);
// Generate a synthetic ack if the event was sent so it doesn't block.
if (!should_block) {
ProcessInputEventAck(
input_event.GetType(), INPUT_EVENT_ACK_STATE_IGNORED, latency_info,
WebInputEventTraits::GetUniqueTouchEventId(input_event),
IGNORING_DISPOSITION);
}
}
bool LegacyInputRouterImpl::OfferToClient(const WebInputEvent& input_event,
const ui::LatencyInfo& latency_info) {
bool consumed = false;
InputEventAckState filter_ack =
client_->FilterInputEvent(input_event, latency_info);
switch (filter_ack) {
case INPUT_EVENT_ACK_STATE_CONSUMED:
case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
// Send the ACK and early exit.
ProcessInputEventAck(
input_event.GetType(), filter_ack, latency_info,
WebInputEventTraits::GetUniqueTouchEventId(input_event), CLIENT);
// WARNING: |this| may be deleted at this point.
consumed = true;
break;
case INPUT_EVENT_ACK_STATE_UNKNOWN:
// Simply drop the event.
consumed = true;
break;
default:
break;
}
return consumed;
}
bool LegacyInputRouterImpl::OfferToRenderer(
const WebInputEvent& input_event,
const ui::LatencyInfo& latency_info,
InputEventDispatchType dispatch_type) {
// This conversion is temporary. WebInputEvent should be generated
// directly from ui::Event with the viewport coordinates. See
// crbug.com/563730.
std::unique_ptr<blink::WebInputEvent> event_in_viewport =
ui::ScaleWebInputEvent(input_event, device_scale_factor_);
const WebInputEvent* event_to_send =
event_in_viewport ? event_in_viewport.get() : &input_event;
if (Send(new InputMsg_HandleInputEvent(
routing_id(), event_to_send, std::vector<IPC::WebInputEventPointer>(),
latency_info, dispatch_type))) {
// Ack messages for ignored ack event types should never be sent by the
// renderer. Consequently, such event types should not affect event time
// or in-flight event count metrics.
if (dispatch_type == InputEventDispatchType::DISPATCH_TYPE_BLOCKING)
client_->IncrementInFlightEventCount(input_event.GetType());
return true;
}
return false;
}
void LegacyInputRouterImpl::OnInputEventAck(const InputEventAck& ack) {
client_->DecrementInFlightEventCount(ack.source);
if (ack.overscroll) {
DCHECK(ack.type == WebInputEvent::kMouseWheel ||
ack.type == WebInputEvent::kGestureScrollUpdate);
OnDidOverscroll(*ack.overscroll);
}
// Since input messages over mojo require the touch action in the
// ACK we mirror that behavior in Chrome IPC for simplicity.
if (ack.touch_action.has_value())
OnSetTouchAction(ack.touch_action.value());
ProcessInputEventAck(ack.type, ack.state, ack.latency,
ack.unique_touch_event_id, RENDERER);
}
void LegacyInputRouterImpl::OnDidOverscroll(
const ui::DidOverscrollParams& params) {
client_->DidOverscroll(params);
}
void LegacyInputRouterImpl::OnMsgMoveCaretAck() {
move_caret_pending_ = false;
if (next_move_caret_)
SendMoveCaret(std::move(next_move_caret_));
}
void LegacyInputRouterImpl::OnSelectMessageAck() {
select_message_pending_ = false;
if (!pending_select_messages_.empty()) {
std::unique_ptr<IPC::Message> next_message =
std::move(pending_select_messages_.front());
pending_select_messages_.pop_front();
SendSelectMessage(std::move(next_message));
}
}
void LegacyInputRouterImpl::OnHasTouchEventHandlers(bool has_handlers) {
TRACE_EVENT1("input", "LegacyInputRouterImpl::OnHasTouchEventHandlers",
"has_handlers", has_handlers);
// Lack of a touch handler indicates that the page either has no touch-action
// modifiers or that all its touch-action modifiers are auto. Resetting the
// touch-action here allows forwarding of subsequent gestures even if the
// underlying touches never reach the router.
if (!has_handlers)
touch_action_filter_.ResetTouchAction();
touch_event_queue_->OnHasTouchEventHandlers(has_handlers);
client_->OnHasTouchEventHandlers(has_handlers);
}
void LegacyInputRouterImpl::OnSetTouchAction(cc::TouchAction touch_action) {
// Synthetic touchstart events should get filtered out in RenderWidget.
DCHECK(touch_event_queue_->IsPendingAckTouchStart());
TRACE_EVENT1("input", "LegacyInputRouterImpl::OnSetTouchAction", "action",
touch_action);
touch_action_filter_.OnSetTouchAction(touch_action);
// kTouchActionNone should disable the touch ack timeout.
UpdateTouchAckTimeoutEnabled();
}
void LegacyInputRouterImpl::OnSetWhiteListedTouchAction(
cc::TouchAction white_listed_touch_action,
uint32_t unique_touch_event_id,
InputEventAckState ack_result) {
// TODO(hayleyferr): Catch the cases that we have filtered out sending the
// touchstart.
touch_action_filter_.OnSetWhiteListedTouchAction(white_listed_touch_action);
client_->OnSetWhiteListedTouchAction(white_listed_touch_action);
}
void LegacyInputRouterImpl::OnDidStopFlinging() {
DCHECK_GT(active_renderer_fling_count_, 0);
// Note that we're only guaranteed to get a fling end notification from the
// renderer, not from any other consumers. Consequently, the GestureEventQueue
// cannot use this bookkeeping for logic like tap suppression.
--active_renderer_fling_count_;
client_->DidStopFlinging();
}
void LegacyInputRouterImpl::ProcessInputEventAck(
WebInputEvent::Type event_type,
InputEventAckState ack_result,
const ui::LatencyInfo& latency_info,
uint32_t unique_touch_event_id,
AckSource ack_source) {
TRACE_EVENT2("input", "LegacyInputRouterImpl::ProcessInputEventAck", "type",
WebInputEvent::GetName(event_type), "ack",
GetEventAckName(ack_result));
// Note: The keyboard ack must be treated carefully, as it may result in
// synchronous destruction of |this|. Handling immediately guards against
// future references to |this|, as with |auto_reset_current_ack_source| below.
if (WebInputEvent::IsKeyboardEventType(event_type)) {
ProcessKeyboardAck(event_type, ack_result, latency_info);
// WARNING: |this| may be deleted at this point.
return;
}
base::AutoReset<AckSource> auto_reset_current_ack_source(&current_ack_source_,
ack_source);
if (WebInputEvent::IsMouseEventType(event_type)) {
ProcessMouseAck(event_type, ack_result, latency_info);
} else if (event_type == WebInputEvent::kMouseWheel) {
ProcessWheelAck(ack_result, latency_info);
} else if (WebInputEvent::IsTouchEventType(event_type)) {
ProcessTouchAck(ack_result, latency_info, unique_touch_event_id);
} else if (WebInputEvent::IsGestureEventType(event_type)) {
ProcessGestureAck(event_type, ack_result, latency_info);
} else if (event_type != WebInputEvent::kUndefined) {
disposition_handler_->OnUnexpectedEventAck(
InputDispositionHandler::BAD_ACK_MESSAGE);
}
}
void LegacyInputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type,
InputEventAckState ack_result,
const ui::LatencyInfo& latency) {
if (key_queue_.empty()) {
disposition_handler_->OnUnexpectedEventAck(
InputDispositionHandler::UNEXPECTED_ACK);
} else if (key_queue_.front().event.GetType() != type) {
// Something must be wrong. Clear the |key_queue_| and char event
// suppression so that we can resume from the error.
key_queue_.clear();
disposition_handler_->OnUnexpectedEventAck(
InputDispositionHandler::UNEXPECTED_EVENT_TYPE);
} else {
NativeWebKeyboardEventWithLatencyInfo front_item = key_queue_.front();
front_item.latency.AddNewLatencyFrom(latency);
key_queue_.pop_front();
disposition_handler_->OnKeyboardEventAck(front_item, ack_result);
// WARNING: This LegacyInputRouterImpl can be deallocated at this point
// (i.e. in the case of Ctrl+W, where the call to
// HandleKeyboardEvent destroys this LegacyInputRouterImpl).
// TODO(jdduke): crbug.com/274029 - Make ack-triggered shutdown async.
}
}
void LegacyInputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type,
InputEventAckState ack_result,
const ui::LatencyInfo& latency) {
if (mouse_event_queue_.empty()) {
disposition_handler_->OnUnexpectedEventAck(
InputDispositionHandler::UNEXPECTED_ACK);
} else {
MouseEventWithLatencyInfo front_item = mouse_event_queue_.front();
front_item.latency.AddNewLatencyFrom(latency);
mouse_event_queue_.pop_front();
disposition_handler_->OnMouseEventAck(front_item, ack_result);
}
}
void LegacyInputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
const ui::LatencyInfo& latency) {
wheel_event_queue_.ProcessMouseWheelAck(ack_result, latency);
}
void LegacyInputRouterImpl::ProcessGestureAck(WebInputEvent::Type type,
InputEventAckState ack_result,
const ui::LatencyInfo& latency) {
if (type == blink::WebInputEvent::kGestureFlingStart &&
ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
++active_renderer_fling_count_;
}
// |gesture_event_queue_| will forward to OnGestureEventAck when appropriate.
gesture_event_queue_.ProcessGestureAck(ack_result, type, latency);
}
void LegacyInputRouterImpl::ProcessTouchAck(InputEventAckState ack_result,
const ui::LatencyInfo& latency,
uint32_t unique_touch_event_id) {
// |touch_event_queue_| will forward to OnTouchEventAck when appropriate.
touch_event_queue_->ProcessTouchAck(ack_result, latency,
unique_touch_event_id);
}
void LegacyInputRouterImpl::UpdateTouchAckTimeoutEnabled() {
// kTouchActionNone will prevent scrolling, in which case the timeout serves
// little purpose. It's also a strong signal that touch handling is critical
// to page functionality, so the timeout could do more harm than good.
const bool touch_ack_timeout_enabled =
touch_action_filter_.allowed_touch_action() != cc::kTouchActionNone;
touch_event_queue_->SetAckTimeoutEnabled(touch_ack_timeout_enabled);
}
void LegacyInputRouterImpl::SetFrameTreeNodeId(int frameTreeNodeId) {
frame_tree_node_id_ = frameTreeNodeId;
}
cc::TouchAction LegacyInputRouterImpl::AllowedTouchAction() {
return touch_action_filter_.allowed_touch_action();
}
void LegacyInputRouterImpl::SetForceEnableZoom(bool enabled) {
touch_action_filter_.SetForceEnableZoom(enabled);
}
void LegacyInputRouterImpl::SetMovementXYForTouchPoints(
blink::WebTouchEvent* event) {
for (size_t i = 0; i < event->touches_length; ++i) {
blink::WebTouchPoint* touch_point = &event->touches[i];
if (touch_point->state == blink::WebTouchPoint::kStateMoved) {
const gfx::Point& last_position = global_touch_position_[touch_point->id];
touch_point->movement_x =
touch_point->PositionInScreen().x - last_position.x();
touch_point->movement_y =
touch_point->PositionInScreen().y - last_position.y();
global_touch_position_[touch_point->id].SetPoint(
touch_point->PositionInScreen().x, touch_point->PositionInScreen().y);
} else {
touch_point->movement_x = 0;
touch_point->movement_y = 0;
if (touch_point->state == blink::WebTouchPoint::kStateReleased ||
touch_point->state == blink::WebTouchPoint::kStateCancelled) {
global_touch_position_.erase(touch_point->id);
} else if (touch_point->state == blink::WebTouchPoint::kStatePressed) {
DCHECK(global_touch_position_.find(touch_point->id) ==
global_touch_position_.end());
global_touch_position_[touch_point->id] =
gfx::Point(touch_point->PositionInScreen().x,
touch_point->PositionInScreen().y);
}
}
}
}
} // namespace content