Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(673)

Side by Side Diff: content/browser/renderer_host/input/buffered_input_router.cc

Issue 19220002: [WIP] BufferedInputRouter (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix client assignment Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 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/browser/renderer_host/input/buffered_input_router.h"
6
7 #include "base/auto_reset.h"
8 #include "content/browser/renderer_host/input/browser_input_event.h"
9 #include "content/browser/renderer_host/input/input_ack_handler.h"
10 #include "content/browser/renderer_host/input/input_queue.h"
11 #include "content/browser/renderer_host/render_widget_host_impl.h"
12 #include "content/common/input_messages.h"
13 #include "content/common/view_messages.h"
14 #include "content/public/browser/native_web_keyboard_event.h"
15 #include "content/public/browser/user_metrics.h"
16
17 using WebKit::WebGestureEvent;
18 using WebKit::WebInputEvent;
19 using WebKit::WebKeyboardEvent;
20 using WebKit::WebMouseEvent;
21 using WebKit::WebMouseWheelEvent;
22 using WebKit::WebTouchEvent;
23
24 namespace content {
25
26 BufferedInputRouter::BufferedInputRouter(IPC::Sender* sender,
27 InputRouterClient* client,
28 InputAckHandler* ack_handler,
29 int routing_id)
30 : client_(client),
31 ack_handler_(ack_handler),
32 sender_(sender),
33 routing_id_(routing_id),
34 queued_gesture_count_(0),
35 has_touch_handler_(false),
36 queued_touch_count_(0),
37 input_queue_override_(NULL),
38 next_input_id_(1),
39 in_flight_packet_id_(0) {
40 input_queue_.reset(new InputQueue(this));
41 }
42
43 BufferedInputRouter::~BufferedInputRouter() {}
44
45 void BufferedInputRouter::Flush() {
46 TRACE_EVENT0("input", "BufferedInputRouter::Flush");
47 DCHECK_EQ(0, in_flight_packet_id_);
48 input_queue_->BeginFlush();
49 }
50
51 bool BufferedInputRouter::SendInput(scoped_ptr<IPC::Message> message) {
52 DCHECK_EQ(InputMsgStart, IPC_MESSAGE_ID_CLASS(message->type()));
53 DCHECK_NE(InputMsg_HandleEventPacket::ID, message->type());
54 input_queue_->QueueEvent(BrowserInputEvent::Create(
55 NextInputID(), IPCInputEventPayload::Create(message.Pass()), this));
56 return true;
57 }
58
59 void BufferedInputRouter::SendMouseEvent(
60 const MouseEventWithLatencyInfo& mouse_event) {
61 if (!client_->OnSendMouseEvent(mouse_event))
62 return;
63 QueueWebEvent(mouse_event.event, mouse_event.latency, false);
64 }
65
66 void BufferedInputRouter::SendWheelEvent(
67 const MouseWheelEventWithLatencyInfo& wheel_event) {
68 if (!client_->OnSendWheelEvent(wheel_event))
69 return;
70 QueueWebEvent(wheel_event.event, wheel_event.latency, false);
71 }
72
73 void BufferedInputRouter::SendKeyboardEvent(
74 const NativeWebKeyboardEvent& key_event,
75 const ui::LatencyInfo& latency_info) {
76 bool is_shortcut = false;
77 if (!client_->OnSendKeyboardEvent(key_event, latency_info, &is_shortcut))
78 return;
79 int64 event_id = QueueWebEvent(key_event, latency_info, is_shortcut);
80 if (event_id) {
81 DCHECK(queued_key_map_.find(event_id) == queued_key_map_.end());
82 queued_key_map_[event_id] = key_event;
83 }
84 }
85
86 void BufferedInputRouter::SendGestureEvent(
87 const GestureEventWithLatencyInfo& gesture_event) {
88 if (!client_->OnSendGestureEvent(gesture_event))
89 return;
90 if (QueueWebEvent(gesture_event.event, gesture_event.latency, false))
91 ++queued_gesture_count_;
92 }
93
94 void BufferedInputRouter::SendTouchEvent(
95 const TouchEventWithLatencyInfo& touch_event) {
96 if (!client_->OnSendTouchEvent(touch_event))
97 return;
98 if (QueueWebEvent(touch_event.event, touch_event.latency, false))
99 ++queued_touch_count_;
100 }
101
102 void BufferedInputRouter::SendMouseEventImmediately(
103 const MouseEventWithLatencyInfo& mouse_event) {
104 if (!client_->OnSendMouseEventImmediately(mouse_event))
105 return;
106 QueueWebEvent(mouse_event.event, mouse_event.latency, false);
107 }
108
109 void BufferedInputRouter::SendTouchEventImmediately(
110 const TouchEventWithLatencyInfo& touch_event) {
111 if (!client_->OnSendTouchEventImmediately(touch_event))
112 return;
113 QueueWebEvent(touch_event.event, touch_event.latency, false);
114 }
115
116 void BufferedInputRouter::SendGestureEventImmediately(
117 const GestureEventWithLatencyInfo& gesture_event) {
118 if (!client_->OnSendGestureEventImmediately(gesture_event))
119 return;
120 QueueWebEvent(gesture_event.event, gesture_event.latency, false);
121 }
122
123 void BufferedInputRouter::Deliver(const EventPacket& packet) {
124 TRACE_EVENT2("input", "BufferedInputRouter::DeliverPacket",
125 "id", packet.id(),
126 "events", packet.size());
127 DCHECK(packet.id());
128 DCHECK(!in_flight_packet_id_);
129 if (!sender_->Send(new InputMsg_HandleEventPacket(
130 routing_id_, packet, InputEventDispositions()))) {
131 return;
132 }
133
134 in_flight_packet_id_ = packet.id();
135 client_->IncrementInFlightEventCount();
136 }
137
138 void BufferedInputRouter::DidFinishFlush() {
139 TRACE_EVENT0("input", "BufferedInputRouter::DidFinishFlush");
140 client_->DidFlush();
141 }
142
143 void BufferedInputRouter::SetNeedsFlush() {
144 TRACE_EVENT0("input", "BufferedInputRouter::SetNeedsFlush");
145 client_->SetNeedsFlush();
146 }
147
148 void BufferedInputRouter::OnDispatched(const BrowserInputEvent& event,
149 InputEventDisposition disposition) {
150 // Only WebInputEvents currently have ack response.
151 if (event.payload()->GetType() != InputEvent::Payload::WEB_INPUT_EVENT)
152 return;
153
154 const WebInputEventPayload* web_payload =
155 WebInputEventPayload::Cast(event.payload());
156
157 OnWebInputEventAck(event.id(),
158 *web_payload->web_event(),
159 web_payload->latency_info(),
160 ToAckState(disposition),
161 true);
162 }
163
164 void BufferedInputRouter::OnDispatched(
165 const BrowserInputEvent& event,
166 InputEventDisposition disposition,
167 ScopedVector<BrowserInputEvent>* followup) {
168 DCHECK(followup);
169 DCHECK_NE(INPUT_EVENT_ACK_STATE_CONSUMED, ToAckState(disposition));
170
171 // Events sent to the router within this scope will be added to |followup|.
172 base::AutoReset<ScopedVector<BrowserInputEvent>*> input_queue_override(
173 &input_queue_override_, followup);
174
175 OnDispatched(event, disposition);
176 }
177
178 bool BufferedInputRouter::OnMessageReceived(const IPC::Message& message) {
179 bool handled = true;
180 bool message_is_ok = true;
181 IPC_BEGIN_MESSAGE_MAP_EX(BufferedInputRouter, message, message_is_ok)
182 IPC_MESSAGE_HANDLER(InputHostMsg_HandleEventPacket_ACK, OnEventPacketAck)
183 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
184 OnHasTouchEventHandlers)
185 IPC_MESSAGE_UNHANDLED(handled = false)
186 IPC_END_MESSAGE_MAP()
187
188 if (!message_is_ok)
189 ack_handler_->OnUnexpectedEventAck(true);
190
191 return handled;
192 }
193
194 const NativeWebKeyboardEvent*
195 BufferedInputRouter::GetLastKeyboardEvent() const {
196 return queued_key_map_.empty() ? NULL : &queued_key_map_.begin()->second;
197 }
198
199 bool BufferedInputRouter::ShouldForwardTouchEvent() const {
200 return has_touch_handler_ && queued_touch_count_ > 0;
201 }
202
203 bool BufferedInputRouter::ShouldForwardGestureEvent(
204 const GestureEventWithLatencyInfo& touch_event) const {
205 return true;
206 }
207
208 bool BufferedInputRouter::HasQueuedGestureEvents() const {
209 return queued_gesture_count_ > 0;
210 }
211
212 void BufferedInputRouter::OnWebInputEventAck(
213 int64 event_id,
214 const WebKit::WebInputEvent& web_event,
215 const ui::LatencyInfo& latency_info,
216 InputEventAckState acked_result,
217 bool ack_from_input_queue) {
218 if (WebInputEvent::isKeyboardEventType(web_event.type)) {
219 if (ack_from_input_queue) {
220 KeyMap::iterator key_it = queued_key_map_.find(event_id);
221 DCHECK(key_it != queued_key_map_.end());
222 NativeWebKeyboardEvent key_event = key_it->second;
223 queued_key_map_.erase(key_it);
224 ack_handler_->OnKeyboardEventAck(key_event, acked_result);
225 } else {
226 DCHECK_EQ(0, event_id);
227 ack_handler_->OnKeyboardEventAck(
228 static_cast<const NativeWebKeyboardEvent&>(web_event), acked_result);
229 }
230 // WARNING: This BufferedInputRouter can be deallocated at this point
231 // (i.e. in the case of Ctrl+W, where the call to
232 // HandleKeyboardEvent destroys this BufferedInputRouter).
233 } else if (web_event.type == WebInputEvent::MouseWheel) {
234 ack_handler_->OnWheelEventAck(
235 static_cast<const WebMouseWheelEvent&>(web_event), acked_result);
236 } else if (WebInputEvent::isTouchEventType(web_event.type)) {
237 if (ack_from_input_queue) {
238 DCHECK_GT(queued_touch_count_, 0);
239 --queued_touch_count_;
240 }
241 ack_handler_->OnTouchEventAck(
242 TouchEventWithLatencyInfo(static_cast<const WebTouchEvent&>(web_event),
243 latency_info),
244 acked_result);
245 } else if (WebInputEvent::isGestureEventType(web_event.type)) {
246 if (ack_from_input_queue) {
247 DCHECK_GT(queued_gesture_count_, 0);
248 --queued_gesture_count_;
249 }
250 ack_handler_->OnGestureEventAck(
251 static_cast<const WebGestureEvent&>(web_event), acked_result);
252 } else
253 NOTREACHED() << "Unexpected WebInputEvent in OnWebInputEventAck";
254 }
255
256 void BufferedInputRouter::OnEventPacketAck(
257 int64 packet_id,
258 const InputEventDispositions& dispositions) {
259 TRACE_EVENT2("input", "BufferedInputRouter::OnEventPacketAck",
260 "id", packet_id,
261 "dispositions", dispositions.size());
262 if (!in_flight_packet_id_ || packet_id != in_flight_packet_id_) {
263 ack_handler_->OnUnexpectedEventAck(false);
264 return;
265 }
266
267 in_flight_packet_id_ = 0;
268 client_->DecrementInFlightEventCount();
269
270 InputQueue::AckResult ack_result =
271 input_queue_->OnEventPacketAck(packet_id, dispositions);
272 if (ack_result == InputQueue::ACK_UNEXPECTED)
273 ack_handler_->OnUnexpectedEventAck(false);
274 else if (ack_result == InputQueue::ACK_INVALID)
275 ack_handler_->OnUnexpectedEventAck(true);
276 }
277
278 void BufferedInputRouter::OnHasTouchEventHandlers(bool has_handlers) {
279 if (has_touch_handler_ == has_handlers)
280 return;
281 has_touch_handler_ = has_handlers;
282 client_->OnHasTouchEventHandlers(has_handlers);
283 }
284
285 int64 BufferedInputRouter::QueueWebEvent(const WebKit::WebInputEvent& web_event,
286 const ui::LatencyInfo& latency_info,
287 bool is_key_shortcut) {
288 TRACE_EVENT0("input", "BufferedInputRouter::QueueWebEvent");
289
290 if (FilterWebEvent(web_event, latency_info)) {
291 TRACE_EVENT_INSTANT0("input",
292 "BufferedInputRouter::QueueWebEvent::Filtered",
293 TRACE_EVENT_SCOPE_THREAD);
294 return 0;
295 }
296
297 int64 event_id = NextInputID();
298 scoped_ptr<BrowserInputEvent> event = BrowserInputEvent::Create(
299 event_id,
300 WebInputEventPayload::Create(web_event,
301 latency_info,
302 is_key_shortcut),
303 this);
304
305 // The presence of |input_queue_override_| implies that we are in the
306 // scope of |OnInputEventDispatched()| with an event can create followup.
307 if (input_queue_override_)
308 input_queue_override_->push_back(event.release());
309 else
310 input_queue_->QueueEvent(event.Pass());
311
312 return event_id;
313 }
314
315 bool BufferedInputRouter::FilterWebEvent(const WebKit::WebInputEvent& web_event,
316 const ui::LatencyInfo& latency_info) {
317 // Perform optional, synchronous event handling, sending ACK messages for
318 // processed events, or proceeding as usual.
319 InputEventAckState filter_ack =
320 client_->FilterInputEvent(web_event, latency_info);
321 switch (filter_ack) {
322 // Send the ACK and early exit.
323 case INPUT_EVENT_ACK_STATE_CONSUMED:
324 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
325 OnWebInputEventAck(0, web_event, latency_info, filter_ack, false);
326 // WARNING: |this| may be deleted at this point.
327 return true;
328
329 // Drop the event.
330 case INPUT_EVENT_ACK_STATE_UNKNOWN:
331 return true;
332
333 // Proceed as normal.
334 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED:
335 default:
336 break;
337 };
338
339 return false;
340 }
341
342 int64 BufferedInputRouter::NextInputID() { return next_input_id_++; }
343
344 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698