1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/input/input_event_filter.h"
7 #include "base/auto_reset.h"
9 #include "base/command_line.h"
10 #include "base/debug/trace_event.h"
11 #include "base/location.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "cc/input/input_handler.h"
14 #include "content/common/input/did_overscroll_params.h"
15 #include "content/common/input/web_input_event_traits.h"
16 #include "content/common/input_messages.h"
17 #include "content/common/view_messages.h"
18 #include "content/public/common/content_switches.h"
19 #include "ipc/ipc_listener.h"
20 #include "ipc/ipc_sender.h"
21 #include "ui/gfx/vector2d_f.h"
23 using blink::WebInputEvent;
25 #include "ipc/ipc_message_null_macros.h"
26 #undef IPC_MESSAGE_DECL
27 #define IPC_MESSAGE_DECL(kind, type, name, in, out, ilist, olist) \
28 case name::ID: return #name;
30 const char* GetInputMessageTypeName(const IPC::Message& message) {
31 switch (message.type()) {
32 #include "content/common/input_messages.h"
34 NOTREACHED() << "Invalid message type: " << message.type();
37 return "NonInputMsgType";
42 InputEventFilter::InputEventFilter(
43 IPC::Listener* main_listener,
44 const scoped_refptr<base::MessageLoopProxy>& target_loop)
45 : main_loop_(base::MessageLoopProxy::current()),
46 main_listener_(main_listener),
48 target_loop_(target_loop),
49 overscroll_notifications_enabled_(false),
50 current_overscroll_params_(NULL) {
51 DCHECK(target_loop_.get());
52 overscroll_notifications_enabled_ =
53 CommandLine::ForCurrentProcess()->HasSwitch(
54 switches::kEnableOverscrollNotifications);
57 void InputEventFilter::SetBoundHandler(const Handler& handler) {
58 DCHECK(main_loop_->BelongsToCurrentThread());
62 void InputEventFilter::DidAddInputHandler(int routing_id,
63 cc::InputHandler* input_handler) {
64 base::AutoLock locked(routes_lock_);
65 routes_.insert(routing_id);
68 void InputEventFilter::DidRemoveInputHandler(int routing_id) {
69 base::AutoLock locked(routes_lock_);
70 routes_.erase(routing_id);
73 void InputEventFilter::DidOverscroll(int routing_id,
74 const DidOverscrollParams& params) {
75 if (!overscroll_notifications_enabled_)
78 if (current_overscroll_params_) {
79 current_overscroll_params_->reset(new DidOverscrollParams(params));
83 SendMessage(scoped_ptr<IPC::Message>(
84 new InputHostMsg_DidOverscroll(routing_id, params)));
87 void InputEventFilter::DidStopFlinging(int routing_id) {
89 scoped_ptr<IPC::Message>(new ViewHostMsg_DidStopFlinging(routing_id)));
92 void InputEventFilter::OnFilterAdded(IPC::Sender* sender) {
93 io_loop_ = base::MessageLoopProxy::current();
97 void InputEventFilter::OnFilterRemoved() {
101 void InputEventFilter::OnChannelClosing() {
105 // This function returns true if the IPC message is one that the compositor
106 // thread can handle *or* one that needs to preserve relative order with
107 // messages that the compositor thread can handle. Returning true for a message
108 // type means that the message will go through an extra copy and thread hop, so
110 static bool RequiresThreadBounce(const IPC::Message& message) {
111 return IPC_MESSAGE_ID_CLASS(message.type()) == InputMsgStart;
114 bool InputEventFilter::OnMessageReceived(const IPC::Message& message) {
115 if (!RequiresThreadBounce(message))
118 TRACE_EVENT0("input", "InputEventFilter::OnMessageReceived::InputMessage");
121 base::AutoLock locked(routes_lock_);
122 if (routes_.find(message.routing_id()) == routes_.end())
126 target_loop_->PostTask(
128 base::Bind(&InputEventFilter::ForwardToHandler, this, message));
132 InputEventFilter::~InputEventFilter() {
133 DCHECK(!current_overscroll_params_);
136 void InputEventFilter::ForwardToMainListener(const IPC::Message& message) {
137 main_listener_->OnMessageReceived(message);
140 void InputEventFilter::ForwardToHandler(const IPC::Message& message) {
141 DCHECK(!handler_.is_null());
142 DCHECK(target_loop_->BelongsToCurrentThread());
143 TRACE_EVENT1("input", "InputEventFilter::ForwardToHandler",
144 "message_type", GetInputMessageTypeName(message));
146 if (message.type() != InputMsg_HandleInputEvent::ID) {
147 TRACE_EVENT_INSTANT0(
149 "InputEventFilter::ForwardToHandler::ForwardToMainListener",
150 TRACE_EVENT_SCOPE_THREAD);
151 main_loop_->PostTask(
153 base::Bind(&InputEventFilter::ForwardToMainListener,
158 int routing_id = message.routing_id();
159 InputMsg_HandleInputEvent::Param params;
160 if (!InputMsg_HandleInputEvent::Read(&message, ¶ms))
162 const WebInputEvent* event = params.a;
163 ui::LatencyInfo latency_info = params.b;
164 bool is_keyboard_shortcut = params.c;
167 const bool send_ack = !WebInputEventTraits::IgnoresAckDisposition(*event);
169 // Intercept |DidOverscroll| notifications, bundling any triggered overscroll
170 // response with the input event ack.
171 scoped_ptr<DidOverscrollParams> overscroll_params;
172 base::AutoReset<scoped_ptr<DidOverscrollParams>*>
173 auto_reset_current_overscroll_params(
174 ¤t_overscroll_params_, send_ack ? &overscroll_params : NULL);
176 InputEventAckState ack_state = handler_.Run(routing_id, event, &latency_info);
178 if (ack_state == INPUT_EVENT_ACK_STATE_NOT_CONSUMED) {
179 DCHECK(!overscroll_params);
180 TRACE_EVENT_INSTANT0(
182 "InputEventFilter::ForwardToHandler::ForwardToMainListener",
183 TRACE_EVENT_SCOPE_THREAD);
184 IPC::Message new_msg = InputMsg_HandleInputEvent(
185 routing_id, event, latency_info, is_keyboard_shortcut);
186 main_loop_->PostTask(
188 base::Bind(&InputEventFilter::ForwardToMainListener,
196 InputHostMsg_HandleInputEvent_ACK_Params ack;
197 ack.type = event->type;
198 ack.state = ack_state;
199 ack.latency = latency_info;
200 ack.overscroll = overscroll_params.Pass();
201 SendMessage(scoped_ptr<IPC::Message>(
202 new InputHostMsg_HandleInputEvent_ACK(routing_id, ack)));
205 void InputEventFilter::SendMessage(scoped_ptr<IPC::Message> message) {
206 DCHECK(target_loop_->BelongsToCurrentThread());
208 io_loop_->PostTask(FROM_HERE,
209 base::Bind(&InputEventFilter::SendMessageOnIOThread,
211 base::Passed(&message)));
214 void InputEventFilter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) {
215 DCHECK(io_loop_->BelongsToCurrentThread());
218 return; // Filter was removed.
220 sender_->Send(message.release());
223 } // namespace content