Home | History | Annotate | Download | only in input
      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   // Intercept |DidOverscroll| notifications, bundling any triggered overscroll
    168   // response with the input event ack.
    169   scoped_ptr<DidOverscrollParams> overscroll_params;
    170   base::AutoReset<scoped_ptr<DidOverscrollParams>*>
    171       auto_reset_current_overscroll_params(&current_overscroll_params_,
    172                                            &overscroll_params);
    173 
    174   InputEventAckState ack_state = handler_.Run(routing_id, event, &latency_info);
    175 
    176   if (ack_state == INPUT_EVENT_ACK_STATE_NOT_CONSUMED) {
    177     DCHECK(!overscroll_params);
    178     TRACE_EVENT_INSTANT0(
    179         "input",
    180         "InputEventFilter::ForwardToHandler::ForwardToMainListener",
    181         TRACE_EVENT_SCOPE_THREAD);
    182     IPC::Message new_msg = InputMsg_HandleInputEvent(
    183         routing_id, event, latency_info, is_keyboard_shortcut);
    184     main_loop_->PostTask(
    185         FROM_HERE,
    186         base::Bind(&InputEventFilter::ForwardToMainListener,
    187                    this, new_msg));
    188     return;
    189   }
    190 
    191   if (WebInputEventTraits::IgnoresAckDisposition(*event))
    192     return;
    193 
    194   InputHostMsg_HandleInputEvent_ACK_Params ack;
    195   ack.type = event->type;
    196   ack.state = ack_state;
    197   ack.latency = latency_info;
    198   ack.overscroll = overscroll_params.Pass();
    199   SendMessage(scoped_ptr<IPC::Message>(
    200       new InputHostMsg_HandleInputEvent_ACK(routing_id, ack)));
    201 }
    202 
    203 void InputEventFilter::SendMessage(scoped_ptr<IPC::Message> message) {
    204   DCHECK(target_loop_->BelongsToCurrentThread());
    205 
    206   io_loop_->PostTask(FROM_HERE,
    207                      base::Bind(&InputEventFilter::SendMessageOnIOThread,
    208                                 this,
    209                                 base::Passed(&message)));
    210 }
    211 
    212 void InputEventFilter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) {
    213   DCHECK(io_loop_->BelongsToCurrentThread());
    214 
    215   if (!sender_)
    216     return;  // Filter was removed.
    217 
    218   sender_->Send(message.release());
    219 }
    220 
    221 }  // namespace content
    222