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

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

Issue 20356003: Provided batched input delivery with a BufferedInputRouter (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Code review Created 7 years, 4 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/input_ack_handler.h"
9 #include "content/browser/renderer_host/input/input_queue.h"
10 #include "content/browser/renderer_host/render_widget_host_impl.h"
11 #include "content/common/input/input_event_utils.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 base::Time;
aelias_OOO_until_Jul13 2013/08/15 00:52:15 Shouldn't need this.
jdduke (slow) 2013/08/15 23:22:26 Done.
18 using base::TimeDelta;
19 using base::TimeTicks;
20 using WebKit::WebGestureEvent;
21 using WebKit::WebInputEvent;
22 using WebKit::WebKeyboardEvent;
23 using WebKit::WebMouseEvent;
24 using WebKit::WebMouseWheelEvent;
25 using WebKit::WebTouchEvent;
26
27 namespace content {
28
29 namespace {
30
31 InputEventAckState FromState(InputEventState state) {
32 switch (state) {
33 case INPUT_EVENT_UNHANDLED:
34 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
35 case INPUT_EVENT_IMPL_THREAD_ABSORBED:
36 return INPUT_EVENT_ACK_STATE_CONSUMED;
37 case INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS:
38 return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
39 case INPUT_EVENT_IMPL_THREAD_BOUNCE_TO_MAIN:
40 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
41 case INPUT_EVENT_IMPL_THREAD_COULD_NOT_DELIVER:
42 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
43 case INPUT_EVENT_MAIN_THREAD_ABSORBED:
44 return INPUT_EVENT_ACK_STATE_CONSUMED;
45 case INPUT_EVENT_MAIN_THREAD_PREVENT_DEFAULTED:
46 return INPUT_EVENT_ACK_STATE_CONSUMED;
47 case INPUT_EVENT_MAIN_THREAD_NOT_PREVENT_DEFAULTED:
48 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
49 case INPUT_EVENT_MAIN_THREAD_NO_HANDLER_EXISTS:
50 return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
51 case INPUT_EVENT_MAIN_THREAD_COULD_NOT_DELIVER:
52 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
53 }
54
55 NOTREACHED();
56 return INPUT_EVENT_ACK_STATE_UNKNOWN;
57 }
58
59 } // namespace
60
61 BufferedInputRouter::BufferedInputRouter(IPC::Sender* sender,
62 InputRouterClient* client,
63 InputAckHandler* ack_handler,
64 int routing_id)
65 : client_(client),
66 ack_handler_(ack_handler),
67 sender_(sender),
68 routing_id_(routing_id),
69 queued_gesture_count_(0),
70 has_touch_handler_(false),
71 queued_touch_count_(0),
72 input_queue_override_(NULL),
73 next_input_id_(1),
74 in_flight_packet_id_(0) {
75 input_queue_.reset(new InputQueue(this));
76 }
77
78 BufferedInputRouter::~BufferedInputRouter() {}
79
80 void BufferedInputRouter::Flush() {
81 TRACE_EVENT0("input", "BufferedInputRouter::Flush");
82 DCHECK_EQ(0, in_flight_packet_id_);
83
84 input_queue_->FlushEventsInCurrentFrame();
85 }
86
87 bool BufferedInputRouter::SendInput(scoped_ptr<IPC::Message> message) {
88 DCHECK_EQ(InputMsgStart, IPC_MESSAGE_ID_CLASS(message->type()));
89 DCHECK_NE(InputMsg_HandleEventPacket::ID, message->type());
90 input_queue_->QueueEvent(InputEvent(NextInputID(),
91 INPUT_EVENT_ONE_WAY,
92 *message), NULL);
93 return true;
94 }
95
96 void BufferedInputRouter::SendMouseEvent(
97 const MouseEventWithLatencyInfo& mouse_event) {
98 if (!client_->OnSendMouseEvent(mouse_event))
99 return;
100 QueueWebEvent(mouse_event.event, mouse_event.latency, false, false);
101 }
102
103 void BufferedInputRouter::SendWheelEvent(
104 const MouseWheelEventWithLatencyInfo& wheel_event) {
105 if (!client_->OnSendWheelEvent(wheel_event))
106 return;
107 QueueWebEvent(wheel_event.event, wheel_event.latency, false, false);
108 }
109
110 void BufferedInputRouter::SendKeyboardEvent(
111 const NativeWebKeyboardEvent& key_event,
112 const ui::LatencyInfo& latency_info) {
113 bool is_shortcut = false;
114 if (!client_->OnSendKeyboardEvent(key_event, latency_info, &is_shortcut))
115 return;
116 int64 event_id = QueueWebEvent(key_event, latency_info, is_shortcut, false);
117 if (event_id) {
118 DCHECK(queued_key_map_.find(event_id) == queued_key_map_.end());
119 queued_key_map_[event_id] = key_event;
120 }
121 }
122
123 void BufferedInputRouter::SendGestureEvent(
124 const GestureEventWithLatencyInfo& gesture_event) {
125 if (!client_->OnSendGestureEvent(gesture_event))
126 return;
127 if (QueueWebEvent(gesture_event.event, gesture_event.latency, false, false))
128 ++queued_gesture_count_;
129 }
130
131 void BufferedInputRouter::SendTouchEvent(
132 const TouchEventWithLatencyInfo& touch_event) {
133 if (!client_->OnSendTouchEvent(touch_event))
134 return;
135 if (QueueWebEvent(touch_event.event, touch_event.latency, false, true))
136 ++queued_touch_count_;
137 }
138
139 void BufferedInputRouter::SendMouseEventImmediately(
140 const MouseEventWithLatencyInfo& mouse_event) {
141 if (!client_->OnSendMouseEventImmediately(mouse_event))
142 return;
143 QueueWebEvent(mouse_event.event, mouse_event.latency, false, false);
144 }
145
146 void BufferedInputRouter::SendTouchEventImmediately(
147 const TouchEventWithLatencyInfo& touch_event) {
148 if (!client_->OnSendTouchEventImmediately(touch_event))
149 return;
150 QueueWebEvent(touch_event.event, touch_event.latency, false, false);
151 }
152
153 void BufferedInputRouter::SendGestureEventImmediately(
154 const GestureEventWithLatencyInfo& gesture_event) {
155 if (!client_->OnSendGestureEventImmediately(gesture_event))
156 return;
157 QueueWebEvent(gesture_event.event, gesture_event.latency, false, false);
158 }
159
160 void BufferedInputRouter::Deliver(const EventPacket& packet) {
161 TRACE_EVENT2("input", "BufferedInputRouter::DeliverPacket",
162 "id", packet.id,
163 "events", packet.events.size());
164 DCHECK(packet.id);
165 DCHECK(!in_flight_packet_id_);
166 if (!sender_->Send(new InputMsg_HandleEventPacket(routing_id_, packet)))
167 return;
168
169 in_flight_packet_id_ = packet.id;
170 client_->IncrementInFlightEventCount();
171 }
172
173 void BufferedInputRouter::DidFlush() {
174 TRACE_EVENT0("input", "BufferedInputRouter::DidFlush");
175 client_->DidFlush();
176 }
177
178 void BufferedInputRouter::SetNeedsFlush() {
179 TRACE_EVENT0("input", "BufferedInputRouter::SetNeedsFlush");
180 client_->SetNeedsFlush();
181 }
182
183 std::vector<InputEvent> BufferedInputRouter::OnInputEventAck(
184 const InputEvent& acked_event) {
185 DCHECK(IsWebInputEventMessage(acked_event.message));
186
187 const WebKit::WebInputEvent* web_event = NULL;
188 ui::LatencyInfo latency_info;
189 DCHECK(CrackWebInputEventMessage(acked_event.message,
190 &web_event,
191 &latency_info,
192 NULL));
193
194 InputEventAckState ack_state = FromState(acked_event.state);
195
196 if (acked_event.type == INPUT_EVENT_NEEDS_ACK_AND_HAS_FOLLOWUP) {
197 std::vector<InputEvent> followup_events;
198 base::AutoReset<std::vector<InputEvent>*> input_queue_override(
199 &input_queue_override_, &followup_events);
200 OnInputEventAck(acked_event.id, *web_event, latency_info, ack_state, true);
201 return followup_events;
202 }
203
204 OnInputEventAck(acked_event.id, *web_event, latency_info, ack_state, true);
205 return std::vector<InputEvent>();
206 }
207
208 bool BufferedInputRouter::OnMessageReceived(const IPC::Message& message) {
209 bool handled = true;
210 bool message_is_ok = true;
211 IPC_BEGIN_MESSAGE_MAP_EX(BufferedInputRouter, message, message_is_ok)
212 IPC_MESSAGE_HANDLER(InputHostMsg_HandleEventPacket_ACK, OnEventPacketAck)
213 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
214 OnHasTouchEventHandlers)
215 IPC_MESSAGE_UNHANDLED(handled = false)
216 IPC_END_MESSAGE_MAP()
217
218 if (!message_is_ok)
219 ack_handler_->OnUnexpectedEventAck(true);
220
221 return handled;
222 }
223
224 const NativeWebKeyboardEvent*
225 BufferedInputRouter::GetLastKeyboardEvent() const {
226 return queued_key_map_.empty() ? NULL : &queued_key_map_.begin()->second;
227 }
228
229 bool BufferedInputRouter::ShouldForwardTouchEvent() const {
230 return has_touch_handler_ && queued_touch_count_ > 0;
231 }
232
233 bool BufferedInputRouter::ShouldForwardGestureEvent(
234 const GestureEventWithLatencyInfo& touch_event) const {
235 return true;
236 }
237
238 bool BufferedInputRouter::HasQueuedGestureEvents() const {
239 return queued_gesture_count_ > 0;
240 }
241
242 void BufferedInputRouter::OnInputEventAck(
aelias_OOO_until_Jul13 2013/08/15 00:52:15 Please rename to OnWebInputEventAck.
jdduke (slow) 2013/08/15 23:22:26 Done.
243 int64 event_id,
244 const WebKit::WebInputEvent& web_event,
245 const ui::LatencyInfo& latency_info,
246 InputEventAckState acked_result,
247 bool ack_from_input_queue) {
248 if (WebInputEvent::isKeyboardEventType(web_event.type)) {
249 if (ack_from_input_queue) {
250 KeyMap::iterator key_it = queued_key_map_.find(event_id);
251 DCHECK(key_it != queued_key_map_.end());
252 NativeWebKeyboardEvent key_event = key_it->second;
253 queued_key_map_.erase(key_it);
254 ack_handler_->OnKeyboardEventAck(key_event, acked_result);
255 } else {
256 DCHECK_EQ(0, event_id);
257 ack_handler_->OnKeyboardEventAck(
258 static_cast<const NativeWebKeyboardEvent&>(web_event), acked_result);
259 }
260 // WARNING: This BufferedInputRouter can be deallocated at this point
261 // (i.e. in the case of Ctrl+W, where the call to
262 // HandleKeyboardEvent destroys this BufferedInputRouter).
263 } else if (web_event.type == WebInputEvent::MouseWheel) {
264 ack_handler_->OnWheelEventAck(
265 static_cast<const WebMouseWheelEvent&>(web_event), acked_result);
266 } else if (WebInputEvent::isTouchEventType(web_event.type)) {
267 if (ack_from_input_queue) {
268 DCHECK_GT(queued_touch_count_, 0);
269 --queued_touch_count_;
270 }
271 ack_handler_->OnTouchEventAck(
272 TouchEventWithLatencyInfo(static_cast<const WebTouchEvent&>(web_event),
273 latency_info), acked_result);
274 } else if (WebInputEvent::isGestureEventType(web_event.type)) {
275 if (ack_from_input_queue) {
276 DCHECK_GT(queued_gesture_count_, 0);
277 --queued_gesture_count_;
278 }
279 ack_handler_->OnGestureEventAck(
280 static_cast<const WebGestureEvent&>(web_event), acked_result);
281 } else {
aelias_OOO_until_Jul13 2013/08/15 00:52:15 nit: remove this else {}
jdduke (slow) 2013/08/15 23:22:26 Done.
282 NOTREACHED() << "Unexpected WebInputEvent in OnInputEventAck";
283 }
284 }
285
286 void BufferedInputRouter::OnEventPacketAck(const EventPacket& packet) {
287 TRACE_EVENT1("input", "BufferedInputRouter::OnEventPacketAck",
288 "id", packet.id);
289 if (!in_flight_packet_id_ || packet.id != in_flight_packet_id_) {
290 ack_handler_->OnUnexpectedEventAck(false);
291 return;
292 }
293
294 in_flight_packet_id_ = 0;
295 client_->DecrementInFlightEventCount();
296
297 InputQueue::AckResult ack_result = input_queue_->OnEventPacketAck(packet);
298 if (ack_result == InputQueue::ACK_UNEXPECTED)
299 ack_handler_->OnUnexpectedEventAck(false);
300 else if (ack_result == InputQueue::ACK_INVALID)
301 ack_handler_->OnUnexpectedEventAck(true);
302 }
303
304 void BufferedInputRouter::OnHasTouchEventHandlers(bool has_handlers) {
305 if (has_touch_handler_ == has_handlers)
306 return;
307 has_touch_handler_ = has_handlers;
308 client_->OnHasTouchEventHandlers(has_handlers);
309 }
310
311 int64 BufferedInputRouter::QueueWebEvent(const WebKit::WebInputEvent& web_event,
312 const ui::LatencyInfo& latency_info,
313 bool is_keyboard_shortcut,
314 bool has_followup) {
315 TRACE_EVENT0("input", "BufferedInputRouter::QueueWebEvent");
316
317 if (FilterWebEvent(web_event, latency_info)) {
318 TRACE_EVENT_INSTANT0("input",
319 "BufferedInputRouter::QueueWebEvent::Filtered",
320 TRACE_EVENT_SCOPE_THREAD);
321 return 0;
322 }
323
324 InputEventType type = has_followup ? INPUT_EVENT_NEEDS_ACK_AND_HAS_FOLLOWUP
325 : INPUT_EVENT_NEEDS_ACK;
326 InputEvent event(NextInputID(),
327 type,
328 InputMsg_HandleInputEvent(routing_id_,
329 &web_event,
330 latency_info,
331 is_keyboard_shortcut));
332
333 // The presence of |input_queue_override_| implies that we are in the
334 // scope of OnInputEventAck with an event that has followup.
335 // TODO(jdduke): Remove when InputAckHandler returns followup events directly.
aelias_OOO_until_Jul13 2013/08/15 00:52:15 Delete this comment since it's not clear we're goi
jdduke (slow) 2013/08/15 23:22:26 Done.
336 if (input_queue_override_)
337 input_queue_override_->push_back(event);
338 else
339 input_queue_->QueueEvent(event, NULL);
340
341 return event.id;
342 }
343
344 bool BufferedInputRouter::FilterWebEvent(const WebKit::WebInputEvent& web_event,
345 const ui::LatencyInfo& latency_info) {
346 // Perform optional, synchronous event handling, sending ACK messages for
347 // processed events, or proceeding as usual.
348 InputEventAckState filter_ack = client_->FilterInputEvent(web_event,
349 latency_info);
350 switch (filter_ack) {
351 // Send the ACK and early exit.
352 case INPUT_EVENT_ACK_STATE_CONSUMED:
353 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
354 OnInputEventAck(0, web_event, latency_info, filter_ack, false);
355 // WARNING: |this| may be deleted at this point.
356 return true;
357
358 // Drop the event.
359 case INPUT_EVENT_ACK_STATE_UNKNOWN:
360 return true;
361
362 // Proceed as normal.
363 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED:
364 default:
365 break;
366 };
367
368 return false;
369 }
370
371 int64 BufferedInputRouter::NextInputID() {
372 return next_input_id_++;
373 }
374
375 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698