Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / renderer / input / input_event_filter.cc
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.
4
5 #include "content/renderer/input/input_event_filter.h"
6
7 #include "base/auto_reset.h"
8 #include "base/bind.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"
22
23 using blink::WebInputEvent;
24
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;
29
30 const char* GetInputMessageTypeName(const IPC::Message& message) {
31   switch (message.type()) {
32 #include "content/common/input_messages.h"
33     default:
34       NOTREACHED() << "Invalid message type: " << message.type();
35       break;
36   };
37   return "NonInputMsgType";
38 }
39
40 namespace content {
41
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),
47       sender_(NULL),
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);
55 }
56
57 void InputEventFilter::SetBoundHandler(const Handler& handler) {
58   DCHECK(main_loop_->BelongsToCurrentThread());
59   handler_ = handler;
60 }
61
62 void InputEventFilter::DidAddInputHandler(int routing_id,
63                                           cc::InputHandler* input_handler) {
64   base::AutoLock locked(routes_lock_);
65   routes_.insert(routing_id);
66 }
67
68 void InputEventFilter::DidRemoveInputHandler(int routing_id) {
69   base::AutoLock locked(routes_lock_);
70   routes_.erase(routing_id);
71 }
72
73 void InputEventFilter::DidOverscroll(int routing_id,
74                                      const DidOverscrollParams& params) {
75   if (!overscroll_notifications_enabled_)
76     return;
77
78   if (current_overscroll_params_) {
79     current_overscroll_params_->reset(new DidOverscrollParams(params));
80     return;
81   }
82
83   SendMessage(scoped_ptr<IPC::Message>(
84       new InputHostMsg_DidOverscroll(routing_id, params)));
85 }
86
87 void InputEventFilter::DidStopFlinging(int routing_id) {
88   SendMessage(
89       scoped_ptr<IPC::Message>(new ViewHostMsg_DidStopFlinging(routing_id)));
90 }
91
92 void InputEventFilter::OnFilterAdded(IPC::Sender* sender) {
93   io_loop_ = base::MessageLoopProxy::current();
94   sender_ = sender;
95 }
96
97 void InputEventFilter::OnFilterRemoved() {
98   sender_ = NULL;
99 }
100
101 void InputEventFilter::OnChannelClosing() {
102   sender_ = NULL;
103 }
104
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
109 // use with care.
110 static bool RequiresThreadBounce(const IPC::Message& message) {
111   return IPC_MESSAGE_ID_CLASS(message.type()) == InputMsgStart;
112 }
113
114 bool InputEventFilter::OnMessageReceived(const IPC::Message& message) {
115   if (!RequiresThreadBounce(message))
116     return false;
117
118   TRACE_EVENT0("input", "InputEventFilter::OnMessageReceived::InputMessage");
119
120   {
121     base::AutoLock locked(routes_lock_);
122     if (routes_.find(message.routing_id()) == routes_.end())
123       return false;
124   }
125
126   target_loop_->PostTask(
127       FROM_HERE,
128       base::Bind(&InputEventFilter::ForwardToHandler, this, message));
129   return true;
130 }
131
132 InputEventFilter::~InputEventFilter() {
133   DCHECK(!current_overscroll_params_);
134 }
135
136 void InputEventFilter::ForwardToMainListener(const IPC::Message& message) {
137   main_listener_->OnMessageReceived(message);
138 }
139
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));
145
146   if (message.type() != InputMsg_HandleInputEvent::ID) {
147     TRACE_EVENT_INSTANT0(
148         "input",
149         "InputEventFilter::ForwardToHandler::ForwardToMainListener",
150         TRACE_EVENT_SCOPE_THREAD);
151     main_loop_->PostTask(
152         FROM_HERE,
153         base::Bind(&InputEventFilter::ForwardToMainListener,
154                    this, message));
155     return;
156   }
157
158   int routing_id = message.routing_id();
159   InputMsg_HandleInputEvent::Param params;
160   if (!InputMsg_HandleInputEvent::Read(&message, &params))
161     return;
162   const WebInputEvent* event = params.a;
163   ui::LatencyInfo latency_info = params.b;
164   bool is_keyboard_shortcut = params.c;
165   DCHECK(event);
166
167   const bool send_ack = !WebInputEventTraits::IgnoresAckDisposition(*event);
168
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           &current_overscroll_params_, send_ack ? &overscroll_params : NULL);
175
176   InputEventAckState ack_state = handler_.Run(routing_id, event, &latency_info);
177
178   if (ack_state == INPUT_EVENT_ACK_STATE_NOT_CONSUMED) {
179     DCHECK(!overscroll_params);
180     TRACE_EVENT_INSTANT0(
181         "input",
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(
187         FROM_HERE,
188         base::Bind(&InputEventFilter::ForwardToMainListener,
189                    this, new_msg));
190     return;
191   }
192
193   if (!send_ack)
194     return;
195
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)));
203 }
204
205 void InputEventFilter::SendMessage(scoped_ptr<IPC::Message> message) {
206   DCHECK(target_loop_->BelongsToCurrentThread());
207
208   io_loop_->PostTask(FROM_HERE,
209                      base::Bind(&InputEventFilter::SendMessageOnIOThread,
210                                 this,
211                                 base::Passed(&message)));
212 }
213
214 void InputEventFilter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) {
215   DCHECK(io_loop_->BelongsToCurrentThread());
216
217   if (!sender_)
218     return;  // Filter was removed.
219
220   sender_->Send(message.release());
221 }
222
223 }  // namespace content