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_handler_manager.h"
6
7#include "base/bind.h"
8#include "base/debug/trace_event.h"
9#include "base/message_loop/message_loop_proxy.h"
10#include "cc/input/input_handler.h"
11#include "content/renderer/input/input_event_filter.h"
12#include "content/renderer/input/input_handler_manager_client.h"
13#include "content/renderer/input/input_handler_wrapper.h"
14
15using blink::WebInputEvent;
16
17namespace content {
18
19namespace {
20
21InputEventAckState InputEventDispositionToAck(
22    InputHandlerProxy::EventDisposition disposition) {
23  switch (disposition) {
24    case InputHandlerProxy::DID_HANDLE:
25      return INPUT_EVENT_ACK_STATE_CONSUMED;
26    case InputHandlerProxy::DID_NOT_HANDLE:
27      return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
28    case InputHandlerProxy::DROP_EVENT:
29      return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
30  }
31  NOTREACHED();
32  return INPUT_EVENT_ACK_STATE_UNKNOWN;
33}
34
35} // namespace
36
37InputHandlerManager::InputHandlerManager(
38    const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
39    InputHandlerManagerClient* client)
40    : message_loop_proxy_(message_loop_proxy),
41      client_(client) {
42  DCHECK(client_);
43  client_->SetBoundHandler(base::Bind(&InputHandlerManager::HandleInputEvent,
44                                      base::Unretained(this)));
45}
46
47InputHandlerManager::~InputHandlerManager() {
48  client_->SetBoundHandler(InputHandlerManagerClient::Handler());
49}
50
51void InputHandlerManager::AddInputHandler(
52    int routing_id,
53    const base::WeakPtr<cc::InputHandler>& input_handler,
54    const base::WeakPtr<RenderViewImpl>& render_view_impl) {
55  if (message_loop_proxy_->BelongsToCurrentThread()) {
56    AddInputHandlerOnCompositorThread(routing_id,
57                                      base::MessageLoopProxy::current(),
58                                      input_handler,
59                                      render_view_impl);
60  } else {
61    message_loop_proxy_->PostTask(
62        FROM_HERE,
63        base::Bind(&InputHandlerManager::AddInputHandlerOnCompositorThread,
64                   base::Unretained(this),
65                   routing_id,
66                   base::MessageLoopProxy::current(),
67                   input_handler,
68                   render_view_impl));
69  }
70}
71
72void InputHandlerManager::AddInputHandlerOnCompositorThread(
73    int routing_id,
74    const scoped_refptr<base::MessageLoopProxy>& main_loop,
75    const base::WeakPtr<cc::InputHandler>& input_handler,
76    const base::WeakPtr<RenderViewImpl>& render_view_impl) {
77  DCHECK(message_loop_proxy_->BelongsToCurrentThread());
78
79  // The handler could be gone by this point if the compositor has shut down.
80  if (!input_handler)
81    return;
82
83  // The same handler may be registered for a route multiple times.
84  if (input_handlers_.count(routing_id) != 0)
85    return;
86
87  TRACE_EVENT1("input",
88      "InputHandlerManager::AddInputHandlerOnCompositorThread",
89      "result", "AddingRoute");
90  client_->DidAddInputHandler(routing_id, input_handler.get());
91  input_handlers_.add(routing_id,
92      make_scoped_ptr(new InputHandlerWrapper(this,
93          routing_id, main_loop, input_handler, render_view_impl)));
94}
95
96void InputHandlerManager::RemoveInputHandler(int routing_id) {
97  DCHECK(message_loop_proxy_->BelongsToCurrentThread());
98  DCHECK(input_handlers_.contains(routing_id));
99
100  TRACE_EVENT0("input", "InputHandlerManager::RemoveInputHandler");
101
102  client_->DidRemoveInputHandler(routing_id);
103  input_handlers_.erase(routing_id);
104}
105
106InputEventAckState InputHandlerManager::HandleInputEvent(
107    int routing_id,
108    const WebInputEvent* input_event,
109    ui::LatencyInfo* latency_info) {
110  DCHECK(message_loop_proxy_->BelongsToCurrentThread());
111
112  InputHandlerMap::iterator it = input_handlers_.find(routing_id);
113  if (it == input_handlers_.end()) {
114    TRACE_EVENT1("input", "InputHandlerManager::HandleInputEvent",
115                 "result", "NoInputHandlerFound");
116    // Oops, we no longer have an interested input handler..
117    return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
118  }
119
120  InputHandlerProxy* proxy = it->second->input_handler_proxy();
121  return InputEventDispositionToAck(
122      proxy->HandleInputEventWithLatencyInfo(*input_event, latency_info));
123}
124
125void InputHandlerManager::DidOverscroll(int routing_id,
126                                        const DidOverscrollParams& params) {
127  client_->DidOverscroll(routing_id, params);
128}
129
130void InputHandlerManager::DidStopFlinging(int routing_id) {
131  client_->DidStopFlinging(routing_id);
132}
133
134}  // namespace content
135