OLD | NEW |
| (Empty) |
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 <vector> | |
6 | |
7 #include "base/memory/scoped_ptr.h" | |
8 #include "content/browser/renderer_host/input/browser_input_event.h" | |
9 #include "content/browser/renderer_host/input/input_queue.h" | |
10 #include "content/browser/renderer_host/input/input_queue_client.h" | |
11 #include "content/common/input/event_packet.h" | |
12 #include "content/common/input/input_event.h" | |
13 #include "content/common/input/ipc_input_event_payload.h" | |
14 #include "content/common/input/web_input_event_payload.h" | |
15 #include "content/common/input_messages.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 #include "ui/events/latency_info.h" | |
18 | |
19 namespace content { | |
20 namespace { | |
21 | |
22 using WebKit::WebGestureEvent; | |
23 using WebKit::WebInputEvent; | |
24 using WebKit::WebKeyboardEvent; | |
25 using WebKit::WebMouseEvent; | |
26 using WebKit::WebMouseWheelEvent; | |
27 using WebKit::WebTouchEvent; | |
28 | |
29 class InputQueueTest : public testing::Test, | |
30 public InputQueueClient, | |
31 public BrowserInputEventClient { | |
32 public: | |
33 InputQueueTest() | |
34 : queue_(new InputQueue(this)), | |
35 routing_id_(0), | |
36 num_flush_completions_(0), | |
37 num_flush_requests_(0), | |
38 num_packet_deliveries_(0), | |
39 next_input_id_(1) {} | |
40 | |
41 // InputQueueClient | |
42 virtual void Deliver(const EventPacket& packet) OVERRIDE { | |
43 EXPECT_LT(0u, packet.size()); | |
44 ++num_packet_deliveries_; | |
45 current_packet_id_ = packet.id(); | |
46 current_packet_dispositions_.resize(packet.size(), INPUT_EVENT_UNHANDLED); | |
47 } | |
48 | |
49 virtual void DidFinishFlush() OVERRIDE { ++num_flush_completions_; } | |
50 virtual void SetNeedsFlush() OVERRIDE { ++num_flush_requests_; } | |
51 | |
52 // BrowserInputEventClient | |
53 virtual void OnDispatched(const BrowserInputEvent& event, | |
54 InputEventDisposition disposition) OVERRIDE { | |
55 acked_dispositions_.push_back(disposition); | |
56 } | |
57 | |
58 virtual void OnDispatched( | |
59 const BrowserInputEvent& event, | |
60 InputEventDisposition disposition, | |
61 ScopedVector<BrowserInputEvent>* followup) OVERRIDE { | |
62 acked_followup_dispositions_.push_back(disposition); | |
63 if (event_to_inject_) | |
64 followup->push_back(event_to_inject_.release()); | |
65 } | |
66 | |
67 int num_flush_requests() const { return num_flush_requests_; } | |
68 int num_flush_completions() const { return num_flush_completions_; } | |
69 int num_packet_deliveries() const { return num_packet_deliveries_; } | |
70 | |
71 protected: | |
72 scoped_ptr<BrowserInputEvent> CreateIPCInputEvent(IPC::Message* message) { | |
73 return BrowserInputEvent::Create( | |
74 NextInputID(), | |
75 IPCInputEventPayload::Create(make_scoped_ptr(message)), | |
76 this); | |
77 } | |
78 | |
79 scoped_ptr<BrowserInputEvent> CreateWebInputEvent( | |
80 WebInputEvent::Type web_type) { | |
81 WebKit::WebMouseEvent mouse; | |
82 WebKit::WebMouseWheelEvent wheel; | |
83 WebKit::WebTouchEvent touch; | |
84 WebKit::WebGestureEvent gesture; | |
85 WebKit::WebKeyboardEvent keyboard; | |
86 | |
87 WebKit::WebInputEvent* web_event = NULL; | |
88 if (WebInputEvent::isMouseEventType(web_type)) | |
89 web_event = &mouse; | |
90 else if (WebInputEvent::isKeyboardEventType(web_type)) | |
91 web_event = &keyboard; | |
92 else if (WebInputEvent::isTouchEventType(web_type)) | |
93 web_event = &touch; | |
94 else if (WebInputEvent::isGestureEventType(web_type)) | |
95 web_event = &gesture; | |
96 else | |
97 web_event = &wheel; | |
98 web_event->type = web_type; | |
99 | |
100 return BrowserInputEvent::Create( | |
101 NextInputID(), | |
102 WebInputEventPayload::Create(*web_event, ui::LatencyInfo(), false), | |
103 this); | |
104 } | |
105 | |
106 void QueueEvent(IPC::Message* message) { | |
107 queue_->QueueEvent(CreateIPCInputEvent(message)); | |
108 } | |
109 | |
110 void QueueEvent(WebInputEvent::Type web_type) { | |
111 queue_->QueueEvent(CreateWebInputEvent(web_type)); | |
112 } | |
113 | |
114 bool Flush(InputEventDisposition disposition) { | |
115 StartFlush(); | |
116 return FinishFlush(disposition); | |
117 } | |
118 | |
119 void StartFlush() { | |
120 acked_dispositions_.clear(); | |
121 acked_followup_dispositions_.clear(); | |
122 current_packet_id_ = 0; | |
123 current_packet_dispositions_.clear(); | |
124 queue_->BeginFlush(); | |
125 } | |
126 | |
127 bool FinishFlush(InputEventDisposition disposition) { | |
128 if (!current_packet_id_) | |
129 return false; | |
130 current_packet_dispositions_ = InputEventDispositions( | |
131 current_packet_dispositions_.size(), disposition); | |
132 return InputQueue::ACK_OK == | |
133 queue_->OnEventPacketAck(current_packet_id_, | |
134 current_packet_dispositions_); | |
135 } | |
136 | |
137 int64 NextInputID() { return next_input_id_++; } | |
138 | |
139 scoped_ptr<InputQueue> queue_; | |
140 | |
141 int routing_id_; | |
142 int64 current_packet_id_; | |
143 InputEventDispositions current_packet_dispositions_; | |
144 | |
145 InputEventDispositions acked_dispositions_; | |
146 InputEventDispositions acked_followup_dispositions_; | |
147 scoped_ptr<BrowserInputEvent> event_to_inject_; | |
148 | |
149 int num_flush_completions_; | |
150 int num_flush_requests_; | |
151 int num_packet_deliveries_; | |
152 int next_input_id_; | |
153 }; | |
154 | |
155 TEST_F(InputQueueTest, SetNeedsFlushOnQueueEvent) { | |
156 EXPECT_EQ(0, num_flush_requests()); | |
157 | |
158 QueueEvent(WebInputEvent::MouseDown); | |
159 EXPECT_EQ(1, num_flush_requests()); | |
160 | |
161 // Additional queued events should not trigger additional flush requests. | |
162 QueueEvent(WebInputEvent::MouseUp); | |
163 EXPECT_EQ(1, num_flush_requests()); | |
164 QueueEvent(WebInputEvent::TouchStart); | |
165 EXPECT_EQ(1, num_flush_requests()); | |
166 } | |
167 | |
168 TEST_F(InputQueueTest, NoSetNeedsFlushOnQueueIfFlushing) { | |
169 QueueEvent(WebInputEvent::GestureScrollBegin); | |
170 EXPECT_EQ(1, num_flush_requests()); | |
171 | |
172 StartFlush(); | |
173 EXPECT_EQ(1, num_flush_requests()); | |
174 EXPECT_EQ(1, num_packet_deliveries()); | |
175 | |
176 // Events queued after a flush will not trigger an additional flush request. | |
177 QueueEvent(WebInputEvent::GestureScrollBegin); | |
178 EXPECT_EQ(1, num_flush_requests()); | |
179 QueueEvent(WebInputEvent::GestureScrollEnd); | |
180 EXPECT_EQ(1, num_flush_requests()); | |
181 } | |
182 | |
183 TEST_F(InputQueueTest, SetNeedsFlushAfterDidFinishFlushIfEventsQueued) { | |
184 QueueEvent(WebInputEvent::GestureScrollBegin); | |
185 EXPECT_EQ(1, num_flush_requests()); | |
186 | |
187 StartFlush(); | |
188 EXPECT_EQ(1, num_packet_deliveries()); | |
189 | |
190 QueueEvent(WebInputEvent::GestureScrollBegin); | |
191 EXPECT_EQ(1, num_flush_requests()); | |
192 | |
193 // An additional flush request is sent for the event queued after the flush. | |
194 ASSERT_TRUE(current_packet_id_); | |
195 ASSERT_TRUE(FinishFlush(INPUT_EVENT_IMPL_THREAD_CONSUMED)); | |
196 EXPECT_EQ(1, num_flush_completions()); | |
197 EXPECT_EQ(2, num_flush_requests()); | |
198 } | |
199 | |
200 TEST_F(InputQueueTest, EventPacketSentAfterFlush) { | |
201 EXPECT_EQ(0, num_packet_deliveries()); | |
202 QueueEvent(WebInputEvent::GestureScrollBegin); | |
203 EXPECT_EQ(0, num_packet_deliveries()); | |
204 StartFlush(); | |
205 EXPECT_EQ(1, num_packet_deliveries()); | |
206 } | |
207 | |
208 TEST_F(InputQueueTest, AcksHandledInProperOrder) { | |
209 QueueEvent(WebInputEvent::GestureScrollBegin); | |
210 QueueEvent(WebInputEvent::GestureScrollEnd); | |
211 QueueEvent(WebInputEvent::GestureFlingStart); | |
212 | |
213 queue_->BeginFlush(); | |
214 ASSERT_EQ(3u, current_packet_dispositions_.size()); | |
215 current_packet_dispositions_[0] = INPUT_EVENT_IMPL_THREAD_CONSUMED; | |
216 current_packet_dispositions_[1] = INPUT_EVENT_MAIN_THREAD_CONSUMED; | |
217 current_packet_dispositions_[2] = INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS; | |
218 queue_->OnEventPacketAck(current_packet_id_, current_packet_dispositions_); | |
219 EXPECT_EQ(1, num_flush_completions()); | |
220 | |
221 ASSERT_EQ(3u, acked_dispositions_.size()); | |
222 EXPECT_EQ(acked_dispositions_[0], INPUT_EVENT_IMPL_THREAD_CONSUMED); | |
223 EXPECT_EQ(acked_dispositions_[1], INPUT_EVENT_MAIN_THREAD_CONSUMED); | |
224 EXPECT_EQ(acked_dispositions_[2], INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS); | |
225 } | |
226 | |
227 TEST_F(InputQueueTest, FollowupWhenFollowupEventNotConsumed) { | |
228 InputEventDisposition unconsumed_dispositions[] = { | |
229 INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS, | |
230 INPUT_EVENT_MAIN_THREAD_NOT_PREVENT_DEFAULTED, | |
231 INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS | |
232 }; | |
233 for (size_t i = 0; i < arraysize(unconsumed_dispositions); ++i) { | |
234 QueueEvent(WebInputEvent::GestureScrollBegin); | |
235 QueueEvent(WebInputEvent::TouchStart); | |
236 QueueEvent(WebInputEvent::TouchMove); | |
237 | |
238 Flush(unconsumed_dispositions[i]); | |
239 EXPECT_EQ(1u, acked_dispositions_.size()) << i; | |
240 EXPECT_EQ(2u, acked_followup_dispositions_.size()) << i; | |
241 } | |
242 } | |
243 | |
244 TEST_F(InputQueueTest, NoFollowupWhenFollowupEventConsumed) { | |
245 InputEventDisposition consumed_dispositions[] = { | |
246 INPUT_EVENT_IMPL_THREAD_CONSUMED, | |
247 INPUT_EVENT_MAIN_THREAD_PREVENT_DEFAULTED, | |
248 INPUT_EVENT_MAIN_THREAD_CONSUMED | |
249 }; | |
250 for (size_t i = 0; i < arraysize(consumed_dispositions); ++i) { | |
251 QueueEvent(WebInputEvent::GestureScrollBegin); | |
252 QueueEvent(WebInputEvent::TouchStart); | |
253 QueueEvent(WebInputEvent::TouchMove); | |
254 | |
255 Flush(consumed_dispositions[i]); | |
256 EXPECT_EQ(3u, acked_dispositions_.size()) << i; | |
257 EXPECT_EQ(0u, acked_followup_dispositions_.size()) << i; | |
258 } | |
259 } | |
260 | |
261 TEST_F(InputQueueTest, FlushOnEmptyQueueIgnored) { | |
262 Flush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | |
263 EXPECT_EQ(0, num_flush_requests()); | |
264 EXPECT_EQ(0, num_flush_completions()); | |
265 | |
266 QueueEvent(WebInputEvent::GestureScrollBegin); | |
267 Flush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | |
268 EXPECT_EQ(1, num_flush_requests()); | |
269 EXPECT_EQ(1, num_flush_completions()); | |
270 | |
271 Flush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | |
272 EXPECT_EQ(1, num_flush_requests()); | |
273 EXPECT_EQ(1, num_flush_completions()); | |
274 } | |
275 | |
276 TEST_F(InputQueueTest, FlushContinuesUntilAllEventsProcessed) { | |
277 QueueEvent(WebInputEvent::GestureScrollBegin); | |
278 QueueEvent(WebInputEvent::GestureScrollEnd); | |
279 QueueEvent(WebInputEvent::GestureFlingStart); | |
280 | |
281 EXPECT_EQ(1, num_flush_requests()); | |
282 Flush(INPUT_EVENT_COULD_NOT_DELIVER); | |
283 EXPECT_EQ(0, num_flush_completions()); | |
284 | |
285 FinishFlush(INPUT_EVENT_COULD_NOT_DELIVER); | |
286 EXPECT_EQ(0, num_flush_completions()); | |
287 | |
288 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED)); | |
289 EXPECT_EQ(1, num_flush_completions()); | |
290 } | |
291 | |
292 TEST_F(InputQueueTest, InvalidPacketAckIgnored) { | |
293 // Packet never flushed, any ack should be ignored. | |
294 InputQueue::AckResult result = | |
295 queue_->OnEventPacketAck(0, InputEventDispositions()); | |
296 EXPECT_EQ(InputQueue::ACK_UNEXPECTED, result); | |
297 | |
298 QueueEvent(WebInputEvent::GestureScrollBegin); | |
299 StartFlush(); | |
300 // Tamper with the sent packet by adding an extra event. | |
301 current_packet_dispositions_.push_back(INPUT_EVENT_MAIN_THREAD_CONSUMED); | |
302 bool valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | |
303 EXPECT_EQ(0, num_flush_completions()); | |
304 EXPECT_FALSE(valid_packet_ack); | |
305 | |
306 // Fix the packet. | |
307 current_packet_dispositions_.pop_back(); | |
308 valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | |
309 EXPECT_EQ(1, num_flush_completions()); | |
310 EXPECT_TRUE(valid_packet_ack); | |
311 | |
312 // Tamper with the packet by changing the id. | |
313 QueueEvent(WebInputEvent::GestureScrollBegin); | |
314 StartFlush(); | |
315 int64 packet_ack_id = -1; | |
316 std::swap(current_packet_id_, packet_ack_id); | |
317 valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | |
318 EXPECT_EQ(1, num_flush_completions()); | |
319 EXPECT_FALSE(valid_packet_ack); | |
320 | |
321 // Fix the packet. | |
322 std::swap(current_packet_id_, packet_ack_id); | |
323 valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | |
324 EXPECT_EQ(2, num_flush_completions()); | |
325 EXPECT_TRUE(valid_packet_ack); | |
326 } | |
327 | |
328 TEST_F(InputQueueTest, InjectedEventsAckedBeforeDidFinishFlush) { | |
329 QueueEvent(WebInputEvent::GestureScrollBegin); | |
330 QueueEvent(WebInputEvent::TouchMove); | |
331 | |
332 event_to_inject_ = CreateIPCInputEvent(new InputMsg_Copy(routing_id_)); | |
333 Flush(INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS); | |
334 EXPECT_EQ(0, num_flush_completions()); | |
335 | |
336 // The injected event should now be in the event packet. | |
337 EXPECT_EQ(1u, current_packet_dispositions_.size()); | |
338 EXPECT_EQ(1u, acked_followup_dispositions_.size()); | |
339 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED)); | |
340 EXPECT_EQ(1, num_flush_completions()); | |
341 | |
342 QueueEvent(WebInputEvent::GestureScrollBegin); | |
343 QueueEvent(WebInputEvent::TouchStart); | |
344 event_to_inject_ = CreateWebInputEvent(WebInputEvent::TouchMove); | |
345 Flush(INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS); | |
346 // |event_to_inject_| is now in the event packet. | |
347 EXPECT_EQ(1u, acked_followup_dispositions_.size()); | |
348 EXPECT_EQ(1u, current_packet_dispositions_.size()); | |
349 | |
350 event_to_inject_ = CreateWebInputEvent(WebInputEvent::TouchMove); | |
351 // the next |event_to_inject_| is now in the event packet. | |
352 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS)); | |
353 | |
354 EXPECT_EQ(2u, acked_followup_dispositions_.size()); | |
355 EXPECT_EQ(1u, current_packet_dispositions_.size()); | |
356 EXPECT_EQ(1, num_flush_completions()); | |
357 | |
358 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED)); | |
359 EXPECT_EQ(2, num_flush_completions()); | |
360 } | |
361 | |
362 } // namespace | |
363 } // namespace content | |
OLD | NEW |