Home | History | Annotate | Download | only in gpu
      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