- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / gpu / input_event_filter.cc
1 // Copyright (c) 2012 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 "base/bind.h"
6 #include "base/command_line.h"
7 #include "base/debug/trace_event.h"
8 #include "base/location.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "cc/input/input_handler.h"
11 #include "content/common/input_messages.h"
12 #include "content/common/view_messages.h"
13 #include "content/public/common/content_switches.h"
14 #include "content/renderer/gpu/input_event_filter.h"
15 #include "ui/gfx/vector2d_f.h"
16
17 using WebKit::WebInputEvent;
18
19 namespace content {
20
21 InputEventFilter::InputEventFilter(
22     IPC::Listener* main_listener,
23     const scoped_refptr<base::MessageLoopProxy>& target_loop)
24     : main_loop_(base::MessageLoopProxy::current()),
25       main_listener_(main_listener),
26       sender_(NULL),
27       target_loop_(target_loop),
28       overscroll_notifications_enabled_(false) {
29   DCHECK(target_loop_.get());
30   overscroll_notifications_enabled_ =
31       CommandLine::ForCurrentProcess()->HasSwitch(
32           switches::kEnableOverscrollNotifications);
33 }
34
35 void InputEventFilter::SetBoundHandler(const Handler& handler) {
36   DCHECK(main_loop_->BelongsToCurrentThread());
37   handler_ = handler;
38 }
39
40 void InputEventFilter::DidAddInputHandler(int routing_id,
41                                           cc::InputHandler* input_handler) {
42   base::AutoLock locked(routes_lock_);
43   routes_.insert(routing_id);
44 }
45
46 void InputEventFilter::DidRemoveInputHandler(int routing_id) {
47   base::AutoLock locked(routes_lock_);
48   routes_.erase(routing_id);
49 }
50
51 void InputEventFilter::DidOverscroll(int routing_id,
52                                      const cc::DidOverscrollParams& params) {
53   DCHECK(target_loop_->BelongsToCurrentThread());
54
55   if (!overscroll_notifications_enabled_)
56     return;
57
58   io_loop_->PostTask(
59       FROM_HERE,
60       base::Bind(&InputEventFilter::SendMessageOnIOThread, this,
61                  ViewHostMsg_DidOverscroll(routing_id,
62                                            params.accumulated_overscroll,
63                                            params.current_fling_velocity)));
64 }
65
66 void InputEventFilter::OnFilterAdded(IPC::Channel* channel) {
67   io_loop_ = base::MessageLoopProxy::current();
68   sender_ = channel;
69 }
70
71 void InputEventFilter::OnFilterRemoved() {
72   sender_ = NULL;
73 }
74
75 void InputEventFilter::OnChannelClosing() {
76   sender_ = NULL;
77 }
78
79 // This function returns true if the IPC message is one that the compositor
80 // thread can handle *or* one that needs to preserve relative order with
81 // messages that the compositor thread can handle. Returning true for a message
82 // type means that the message will go through an extra copy and thread hop, so
83 // use with care.
84 static bool RequiresThreadBounce(const IPC::Message& message) {
85   return IPC_MESSAGE_ID_CLASS(message.type()) == InputMsgStart;
86 }
87
88 bool InputEventFilter::OnMessageReceived(const IPC::Message& message) {
89   TRACE_EVENT0("input", "InputEventFilter::OnMessageReceived");
90
91   if (!RequiresThreadBounce(message))
92     return false;
93
94   {
95     base::AutoLock locked(routes_lock_);
96     if (routes_.find(message.routing_id()) == routes_.end())
97       return false;
98   }
99
100   target_loop_->PostTask(
101       FROM_HERE,
102       base::Bind(&InputEventFilter::ForwardToHandler, this, message));
103   return true;
104 }
105
106 InputEventFilter::~InputEventFilter() {
107 }
108
109 void InputEventFilter::ForwardToMainListener(const IPC::Message& message) {
110   main_listener_->OnMessageReceived(message);
111 }
112
113 void InputEventFilter::ForwardToHandler(const IPC::Message& message) {
114   DCHECK(!handler_.is_null());
115   DCHECK(target_loop_->BelongsToCurrentThread());
116
117   if (message.type() != InputMsg_HandleInputEvent::ID) {
118     main_loop_->PostTask(
119         FROM_HERE,
120         base::Bind(&InputEventFilter::ForwardToMainListener,
121                    this, message));
122     return;
123   }
124
125   int routing_id = message.routing_id();
126   ui::LatencyInfo latency_info;
127   const WebInputEvent* event = NULL;
128   bool is_keyboard_shortcut;
129   if (!InputMsg_HandleInputEvent::Read(
130           &message, &event, &latency_info, &is_keyboard_shortcut))
131     return;
132   DCHECK(event);
133
134   InputEventAckState ack =
135       handler_.Run(routing_id, event, latency_info);
136
137   if (ack == INPUT_EVENT_ACK_STATE_NOT_CONSUMED) {
138     TRACE_EVENT0("input", "InputEventFilter::ForwardToHandler");
139     IPC::Message new_msg = InputMsg_HandleInputEvent(
140         routing_id, event, latency_info, is_keyboard_shortcut);
141     main_loop_->PostTask(
142         FROM_HERE,
143         base::Bind(&InputEventFilter::ForwardToMainListener,
144                    this, new_msg));
145     return;
146   }
147
148   SendACK(event->type, ack, latency_info, routing_id);
149 }
150
151 void InputEventFilter::SendACK(WebKit::WebInputEvent::Type type,
152                                InputEventAckState ack_result,
153                                const ui::LatencyInfo& latency_info,
154                                int routing_id) {
155   DCHECK(target_loop_->BelongsToCurrentThread());
156
157   io_loop_->PostTask(
158       FROM_HERE,
159       base::Bind(&InputEventFilter::SendMessageOnIOThread, this,
160                  InputHostMsg_HandleInputEvent_ACK(
161                      routing_id, type, ack_result, latency_info)));
162 }
163
164 void InputEventFilter::SendMessageOnIOThread(const IPC::Message& message) {
165   DCHECK(io_loop_->BelongsToCurrentThread());
166
167   if (!sender_)
168     return;  // Filter was removed.
169
170   sender_->Send(new IPC::Message(message));
171 }
172
173 }  // namespace content