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 "base/memory/scoped_ptr.h" | |
6 #include "base/time/time.h" | |
7 #include "content/browser/renderer_host/input/synthetic_gesture.h" | |
8 #include "content/browser/renderer_host/input/synthetic_gesture_controller.h" | |
9 #include "content/browser/renderer_host/input/synthetic_gesture_target.h" | |
10 #include "content/browser/renderer_host/input/synthetic_pinch_gesture.h" | |
11 #include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h" | |
12 #include "content/browser/renderer_host/render_widget_host_delegate.h" | |
13 #include "content/browser/renderer_host/test_render_view_host.h" | |
14 #include "content/common/input/input_event.h" | |
15 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" | |
16 #include "content/public/test/mock_render_process_host.h" | |
17 #include "content/public/test/test_browser_context.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 #include "third_party/WebKit/public/web/WebInputEvent.h" | |
20 #include "ui/gfx/point_f.h" | |
21 | |
22 namespace content { | |
23 | |
24 namespace { | |
25 | |
26 const int kFlushInputRateInMs = 16; | |
27 | |
28 class MockSyntheticGesture : public SyntheticGesture { | |
29 public: | |
30 MockSyntheticGesture(bool* finished, int num_steps) | |
31 : finished_(finished), | |
32 num_steps_(num_steps), | |
33 step_count_(0) { | |
34 *finished_ = false; | |
35 } | |
36 virtual ~MockSyntheticGesture() {} | |
37 | |
38 virtual Result ForwardInputEvents(const base::TimeDelta& interval, | |
39 SyntheticGestureTarget* target) OVERRIDE { | |
40 step_count_++; | |
41 if (step_count_ == num_steps_) { | |
42 *finished_ = true; | |
43 return SyntheticGesture::GESTURE_FINISHED; | |
44 } else if (step_count_ > num_steps_) { | |
45 *finished_ = true; | |
46 // Return arbitrary failure. | |
47 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED; | |
48 } | |
49 | |
50 return SyntheticGesture::GESTURE_RUNNING; | |
51 } | |
52 | |
53 protected: | |
54 bool* finished_; | |
55 int num_steps_; | |
56 int step_count_; | |
57 }; | |
58 | |
59 class MockSyntheticGestureTarget : public SyntheticGestureTarget { | |
60 public: | |
61 MockSyntheticGestureTarget() | |
62 : num_success_(0), | |
63 num_failure_(0), | |
64 flush_requested_(false) {} | |
65 virtual ~MockSyntheticGestureTarget() {} | |
66 | |
67 // SyntheticGestureTarget: | |
68 virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE {} | |
69 | |
70 virtual void OnSyntheticGestureCompleted( | |
71 SyntheticGesture::Result result) OVERRIDE { | |
72 DCHECK_NE(result, SyntheticGesture::GESTURE_RUNNING); | |
73 if (result == SyntheticGesture::GESTURE_FINISHED) | |
74 num_success_++; | |
75 else | |
76 num_failure_++; | |
77 } | |
78 | |
79 virtual void SetNeedsFlush() OVERRIDE { | |
80 flush_requested_ = true; | |
81 } | |
82 | |
83 virtual SyntheticGestureParams::GestureSourceType | |
84 GetDefaultSyntheticGestureSourceType() const OVERRIDE { | |
85 return SyntheticGestureParams::TOUCH_INPUT; | |
86 } | |
87 virtual bool SupportsSyntheticGestureSourceType( | |
88 SyntheticGestureParams::GestureSourceType gesture_source_type) | |
89 const OVERRIDE { | |
90 return true; | |
91 } | |
92 | |
93 int num_success() const { return num_success_; } | |
94 int num_failure() const { return num_failure_; } | |
95 | |
96 bool flush_requested() const { return flush_requested_; } | |
97 void ClearFlushRequest() { flush_requested_ = false; } | |
98 | |
99 private: | |
100 int num_success_; | |
101 int num_failure_; | |
102 | |
103 bool flush_requested_; | |
104 }; | |
105 | |
106 class MockSyntheticSmoothScrollMouseTarget : public MockSyntheticGestureTarget { | |
107 public: | |
108 MockSyntheticSmoothScrollMouseTarget() : scroll_distance_(0) {} | |
109 virtual ~MockSyntheticSmoothScrollMouseTarget() {} | |
110 | |
111 virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE { | |
112 const blink::WebInputEvent* web_event = event.web_event.get(); | |
113 ASSERT_EQ(web_event->type, blink::WebInputEvent::MouseWheel); | |
114 const blink::WebMouseWheelEvent* mouse_wheel_event = | |
115 static_cast<const blink::WebMouseWheelEvent*>(web_event); | |
116 ASSERT_EQ(mouse_wheel_event->deltaX, 0); | |
117 scroll_distance_ -= mouse_wheel_event->deltaY; | |
118 } | |
119 | |
120 float scroll_distance() const { return scroll_distance_; } | |
121 | |
122 private: | |
123 float scroll_distance_; | |
124 }; | |
125 | |
126 class MockSyntheticSmoothScrollTouchTarget : public MockSyntheticGestureTarget { | |
127 public: | |
128 MockSyntheticSmoothScrollTouchTarget() | |
129 : scroll_distance_(0), anchor_y_(0), started_(false) {} | |
130 virtual ~MockSyntheticSmoothScrollTouchTarget() {} | |
131 | |
132 virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE { | |
133 const blink::WebInputEvent* web_event = event.web_event.get(); | |
134 ASSERT_TRUE(blink::WebInputEvent::isTouchEventType(web_event->type)); | |
135 const blink::WebTouchEvent* touch_event = | |
136 static_cast<const blink::WebTouchEvent*>(web_event); | |
137 ASSERT_EQ(touch_event->touchesLength, (unsigned int)1); | |
138 | |
139 if (!started_) { | |
140 ASSERT_EQ(touch_event->type, blink::WebInputEvent::TouchStart); | |
141 anchor_y_ = touch_event->touches[0].position.y; | |
142 started_ = true; | |
143 } else { | |
144 ASSERT_NE(touch_event->type, blink::WebInputEvent::TouchStart); | |
145 ASSERT_NE(touch_event->type, blink::WebInputEvent::TouchCancel); | |
146 // Ignore move events. | |
147 | |
148 if (touch_event->type == blink::WebInputEvent::TouchEnd) | |
149 scroll_distance_ = anchor_y_ - touch_event->touches[0].position.y; | |
150 } | |
151 } | |
152 | |
153 float scroll_distance() const { return scroll_distance_; } | |
154 | |
155 private: | |
156 float scroll_distance_; | |
157 float anchor_y_; | |
158 bool started_; | |
159 }; | |
160 | |
161 class MockSyntheticPinchTouchTarget : public MockSyntheticGestureTarget { | |
162 public: | |
163 enum ZoomDirection { | |
164 ZOOM_DIRECTION_UNKNOWN, | |
165 ZOOM_IN, | |
166 ZOOM_OUT | |
167 }; | |
168 | |
169 MockSyntheticPinchTouchTarget() | |
170 : total_num_pixels_covered_(0), | |
171 last_pointer_distance_(0), | |
172 zoom_direction_(ZOOM_DIRECTION_UNKNOWN), | |
173 started_(false) {} | |
174 virtual ~MockSyntheticPinchTouchTarget() {} | |
175 | |
176 virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE { | |
177 const blink::WebInputEvent* web_event = event.web_event.get(); | |
178 ASSERT_TRUE(blink::WebInputEvent::isTouchEventType(web_event->type)); | |
179 const blink::WebTouchEvent* touch_event = | |
180 static_cast<const blink::WebTouchEvent*>(web_event); | |
181 ASSERT_EQ(touch_event->touchesLength, (unsigned int)2); | |
182 | |
183 if (!started_) { | |
184 ASSERT_EQ(touch_event->type, blink::WebInputEvent::TouchStart); | |
185 | |
186 start_0_ = gfx::Point(touch_event->touches[0].position); | |
187 start_1_ = gfx::Point(touch_event->touches[1].position); | |
188 last_pointer_distance_ = (start_0_ - start_1_).Length(); | |
189 | |
190 started_ = true; | |
191 } else { | |
192 ASSERT_NE(touch_event->type, blink::WebInputEvent::TouchStart); | |
193 ASSERT_NE(touch_event->type, blink::WebInputEvent::TouchCancel); | |
194 | |
195 gfx::PointF current_0 = gfx::Point(touch_event->touches[0].position); | |
196 gfx::PointF current_1 = gfx::Point(touch_event->touches[1].position); | |
197 | |
198 total_num_pixels_covered_ = | |
199 (current_0 - start_0_).Length() + (current_1 - start_1_).Length(); | |
200 float pointer_distance = (current_0 - current_1).Length(); | |
201 | |
202 if (last_pointer_distance_ != pointer_distance) { | |
203 if (zoom_direction_ == ZOOM_DIRECTION_UNKNOWN) | |
204 zoom_direction_ = | |
205 ComputeZoomDirection(last_pointer_distance_, pointer_distance); | |
206 else | |
207 EXPECT_EQ( | |
208 zoom_direction_, | |
209 ComputeZoomDirection(last_pointer_distance_, pointer_distance)); | |
210 } | |
211 | |
212 last_pointer_distance_ = pointer_distance; | |
213 } | |
214 } | |
215 | |
216 float total_num_pixels_covered() const { return total_num_pixels_covered_; } | |
217 ZoomDirection zoom_direction() const { return zoom_direction_; } | |
218 | |
219 private: | |
220 ZoomDirection ComputeZoomDirection(float last_pointer_distance, | |
221 float current_pointer_distance) { | |
222 DCHECK_NE(last_pointer_distance, current_pointer_distance); | |
223 return last_pointer_distance < current_pointer_distance ? ZOOM_IN | |
224 : ZOOM_OUT; | |
225 } | |
226 | |
227 float total_num_pixels_covered_; | |
228 float last_pointer_distance_; | |
229 ZoomDirection zoom_direction_; | |
230 gfx::PointF start_0_; | |
231 gfx::PointF start_1_; | |
232 bool started_; | |
233 }; | |
234 | |
235 class SyntheticGestureControllerTest : public testing::Test { | |
236 public: | |
237 SyntheticGestureControllerTest() {} | |
238 virtual ~SyntheticGestureControllerTest() {} | |
239 | |
240 protected: | |
241 template<typename MockGestureTarget> | |
242 void CreateControllerAndTarget() { | |
243 target_ = new MockGestureTarget(); | |
244 | |
245 controller_.reset(new SyntheticGestureController( | |
246 scoped_ptr<SyntheticGestureTarget>(target_))); | |
247 } | |
248 | |
249 virtual void SetUp() OVERRIDE { | |
250 time_ = base::TimeTicks::Now(); | |
251 } | |
252 | |
253 virtual void TearDown() OVERRIDE { | |
254 controller_.reset(); | |
255 target_ = NULL; | |
256 time_ = base::TimeTicks(); | |
257 } | |
258 | |
259 void FlushInputUntilComplete() { | |
260 while (target_->flush_requested()) { | |
261 target_->ClearFlushRequest(); | |
262 time_ += base::TimeDelta::FromMilliseconds(kFlushInputRateInMs); | |
263 controller_->Flush(time_); | |
264 } | |
265 } | |
266 | |
267 MockSyntheticGestureTarget* target_; | |
268 scoped_ptr<SyntheticGestureController> controller_; | |
269 base::TimeTicks time_; | |
270 }; | |
271 | |
272 TEST_F(SyntheticGestureControllerTest, SingleGesture) { | |
273 CreateControllerAndTarget<MockSyntheticGestureTarget>(); | |
274 | |
275 bool finished; | |
276 scoped_ptr<MockSyntheticGesture> gesture( | |
277 new MockSyntheticGesture(&finished, 3)); | |
278 controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); | |
279 FlushInputUntilComplete(); | |
280 | |
281 EXPECT_TRUE(finished); | |
282 EXPECT_EQ(1, target_->num_success()); | |
283 EXPECT_EQ(0, target_->num_failure()); | |
284 } | |
285 | |
286 TEST_F(SyntheticGestureControllerTest, GestureFailed) { | |
287 CreateControllerAndTarget<MockSyntheticGestureTarget>(); | |
288 | |
289 bool finished; | |
290 scoped_ptr<MockSyntheticGesture> gesture( | |
291 new MockSyntheticGesture(&finished, 0)); | |
292 controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); | |
293 FlushInputUntilComplete(); | |
294 | |
295 EXPECT_TRUE(finished); | |
296 EXPECT_EQ(1, target_->num_failure()); | |
297 EXPECT_EQ(0, target_->num_success()); | |
298 } | |
299 | |
300 TEST_F(SyntheticGestureControllerTest, SuccessiveGestures) { | |
301 CreateControllerAndTarget<MockSyntheticGestureTarget>(); | |
302 | |
303 bool finished_1, finished_2; | |
304 scoped_ptr<MockSyntheticGesture> gesture_1( | |
305 new MockSyntheticGesture(&finished_1, 2)); | |
306 scoped_ptr<MockSyntheticGesture> gesture_2( | |
307 new MockSyntheticGesture(&finished_2, 4)); | |
308 | |
309 // Queue first gesture and wait for it to finish | |
310 controller_->QueueSyntheticGesture(gesture_1.PassAs<SyntheticGesture>()); | |
311 FlushInputUntilComplete(); | |
312 | |
313 EXPECT_TRUE(finished_1); | |
314 EXPECT_EQ(1, target_->num_success()); | |
315 EXPECT_EQ(0, target_->num_failure()); | |
316 | |
317 // Queue second gesture. | |
318 controller_->QueueSyntheticGesture(gesture_2.PassAs<SyntheticGesture>()); | |
319 FlushInputUntilComplete(); | |
320 | |
321 EXPECT_TRUE(finished_2); | |
322 EXPECT_EQ(2, target_->num_success()); | |
323 EXPECT_EQ(0, target_->num_failure()); | |
324 } | |
325 | |
326 TEST_F(SyntheticGestureControllerTest, TwoGesturesInFlight) { | |
327 CreateControllerAndTarget<MockSyntheticGestureTarget>(); | |
328 | |
329 bool finished_1, finished_2; | |
330 scoped_ptr<MockSyntheticGesture> gesture_1( | |
331 new MockSyntheticGesture(&finished_1, 2)); | |
332 scoped_ptr<MockSyntheticGesture> gesture_2( | |
333 new MockSyntheticGesture(&finished_2, 4)); | |
334 | |
335 controller_->QueueSyntheticGesture(gesture_1.PassAs<SyntheticGesture>()); | |
336 controller_->QueueSyntheticGesture(gesture_2.PassAs<SyntheticGesture>()); | |
337 FlushInputUntilComplete(); | |
338 | |
339 EXPECT_TRUE(finished_1); | |
340 EXPECT_TRUE(finished_2); | |
341 | |
342 EXPECT_EQ(2, target_->num_success()); | |
343 EXPECT_EQ(0, target_->num_failure()); | |
344 } | |
345 | |
346 TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureTouch) { | |
347 CreateControllerAndTarget<MockSyntheticSmoothScrollTouchTarget>(); | |
348 | |
349 SyntheticSmoothScrollGestureParams params; | |
350 params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; | |
351 params.distance = 100; | |
352 | |
353 scoped_ptr<SyntheticSmoothScrollGesture> gesture( | |
354 new SyntheticSmoothScrollGesture(params)); | |
355 controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); | |
356 FlushInputUntilComplete(); | |
357 | |
358 EXPECT_EQ(1, target_->num_success()); | |
359 EXPECT_EQ(0, target_->num_failure()); | |
360 EXPECT_LE(params.distance, static_cast<MockSyntheticSmoothScrollTouchTarget*>( | |
361 target_)->scroll_distance()); | |
362 } | |
363 | |
364 TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureMouse) { | |
365 CreateControllerAndTarget<MockSyntheticSmoothScrollMouseTarget>(); | |
366 | |
367 SyntheticSmoothScrollGestureParams params; | |
368 params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT; | |
369 params.distance = -100; | |
370 | |
371 scoped_ptr<SyntheticSmoothScrollGesture> gesture( | |
372 new SyntheticSmoothScrollGesture(params)); | |
373 controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); | |
374 FlushInputUntilComplete(); | |
375 | |
376 EXPECT_EQ(1, target_->num_success()); | |
377 EXPECT_EQ(0, target_->num_failure()); | |
378 EXPECT_GE(params.distance, static_cast<MockSyntheticSmoothScrollTouchTarget*>( | |
379 target_)->scroll_distance()); | |
380 } | |
381 | |
382 TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomIn) { | |
383 CreateControllerAndTarget<MockSyntheticPinchTouchTarget>(); | |
384 | |
385 SyntheticPinchGestureParams params; | |
386 params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; | |
387 params.zoom_in = true; | |
388 params.total_num_pixels_covered = 100; | |
389 | |
390 scoped_ptr<SyntheticPinchGesture> gesture( | |
391 new SyntheticPinchGesture(params)); | |
392 controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); | |
393 FlushInputUntilComplete(); | |
394 | |
395 EXPECT_EQ(1, target_->num_success()); | |
396 EXPECT_EQ(0, target_->num_failure()); | |
397 EXPECT_EQ( | |
398 static_cast<MockSyntheticPinchTouchTarget*>(target_)->zoom_direction(), | |
399 MockSyntheticPinchTouchTarget::ZOOM_IN); | |
400 EXPECT_LE( | |
401 params.total_num_pixels_covered, | |
402 static_cast<MockSyntheticPinchTouchTarget*>(target_) | |
403 ->total_num_pixels_covered()); | |
404 } | |
405 | |
406 TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomOut) { | |
407 CreateControllerAndTarget<MockSyntheticPinchTouchTarget>(); | |
408 | |
409 SyntheticPinchGestureParams params; | |
410 params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; | |
411 params.zoom_in = false; | |
412 params.total_num_pixels_covered = 100; | |
413 | |
414 scoped_ptr<SyntheticPinchGesture> gesture( | |
415 new SyntheticPinchGesture(params)); | |
416 controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); | |
417 FlushInputUntilComplete(); | |
418 | |
419 EXPECT_EQ(1, target_->num_success()); | |
420 EXPECT_EQ(0, target_->num_failure()); | |
421 EXPECT_EQ( | |
422 static_cast<MockSyntheticPinchTouchTarget*>(target_)->zoom_direction(), | |
423 MockSyntheticPinchTouchTarget::ZOOM_OUT); | |
424 EXPECT_LE( | |
425 params.total_num_pixels_covered, | |
426 static_cast<MockSyntheticPinchTouchTarget*>(target_) | |
427 ->total_num_pixels_covered()); | |
428 } | |
429 | |
430 } // namespace | |
431 | |
432 } // namespace content | |
OLD | NEW |