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 174