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

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

Powered by Google App Engine
This is Rietveld 408576698