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.
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"
17 using WebKit::WebInputEvent;
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),
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);
35 void InputEventFilter::SetBoundHandler(const Handler& handler) {
36 DCHECK(main_loop_->BelongsToCurrentThread());
40 void InputEventFilter::DidAddInputHandler(int routing_id,
41 cc::InputHandler* input_handler) {
42 base::AutoLock locked(routes_lock_);
43 routes_.insert(routing_id);
46 void InputEventFilter::DidRemoveInputHandler(int routing_id) {
47 base::AutoLock locked(routes_lock_);
48 routes_.erase(routing_id);
51 void InputEventFilter::DidOverscroll(int routing_id,
52 const cc::DidOverscrollParams& params) {
53 DCHECK(target_loop_->BelongsToCurrentThread());
55 if (!overscroll_notifications_enabled_)
60 base::Bind(&InputEventFilter::SendMessageOnIOThread, this,
61 ViewHostMsg_DidOverscroll(routing_id,
62 params.accumulated_overscroll,
63 params.current_fling_velocity)));
66 void InputEventFilter::OnFilterAdded(IPC::Channel* channel) {
67 io_loop_ = base::MessageLoopProxy::current();
71 void InputEventFilter::OnFilterRemoved() {
75 void InputEventFilter::OnChannelClosing() {
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
84 static bool RequiresThreadBounce(const IPC::Message& message) {
85 return IPC_MESSAGE_ID_CLASS(message.type()) == InputMsgStart;
88 bool InputEventFilter::OnMessageReceived(const IPC::Message& message) {
89 TRACE_EVENT0("input", "InputEventFilter::OnMessageReceived");
91 if (!RequiresThreadBounce(message))
95 base::AutoLock locked(routes_lock_);
96 if (routes_.find(message.routing_id()) == routes_.end())
100 target_loop_->PostTask(
102 base::Bind(&InputEventFilter::ForwardToHandler, this, message));
106 InputEventFilter::~InputEventFilter() {
109 void InputEventFilter::ForwardToMainListener(const IPC::Message& message) {
110 main_listener_->OnMessageReceived(message);
113 void InputEventFilter::ForwardToHandler(const IPC::Message& message) {
114 DCHECK(!handler_.is_null());
115 DCHECK(target_loop_->BelongsToCurrentThread());
117 if (message.type() != InputMsg_HandleInputEvent::ID) {
118 main_loop_->PostTask(
120 base::Bind(&InputEventFilter::ForwardToMainListener,
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))
134 InputEventAckState ack =
135 handler_.Run(routing_id, event, latency_info);
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(
143 base::Bind(&InputEventFilter::ForwardToMainListener,
148 SendACK(event->type, ack, latency_info, routing_id);
151 void InputEventFilter::SendACK(WebKit::WebInputEvent::Type type,
152 InputEventAckState ack_result,
153 const ui::LatencyInfo& latency_info,
155 DCHECK(target_loop_->BelongsToCurrentThread());
159 base::Bind(&InputEventFilter::SendMessageOnIOThread, this,
160 InputHostMsg_HandleInputEvent_ACK(
161 routing_id, type, ack_result, latency_info)));
164 void InputEventFilter::SendMessageOnIOThread(const IPC::Message& message) {
165 DCHECK(io_loop_->BelongsToCurrentThread());
168 return; // Filter was removed.
170 sender_->Send(new IPC::Message(message));
173 } // namespace content