| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "base/time/time.h" |
| #include "content/browser/renderer_host/input/synthetic_gesture.h" |
| #include "content/browser/renderer_host/input/synthetic_gesture_controller.h" |
| #include "content/browser/renderer_host/input/synthetic_gesture_target.h" |
| #include "content/browser/renderer_host/input/synthetic_pinch_gesture.h" |
| #include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h" |
| #include "content/browser/renderer_host/input/synthetic_tap_gesture.h" |
| #include "content/browser/renderer_host/render_widget_host_delegate.h" |
| #include "content/common/input/input_event.h" |
| #include "content/common/input/synthetic_pinch_gesture_params.h" |
| #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" |
| #include "content/common/input/synthetic_tap_gesture_params.h" |
| #include "content/public/test/mock_render_process_host.h" |
| #include "content/public/test/test_browser_context.h" |
| #include "content/test/test_render_view_host.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/WebKit/public/web/WebInputEvent.h" |
| #include "ui/gfx/point.h" |
| #include "ui/gfx/point_f.h" |
| #include "ui/gfx/vector2d.h" |
| #include "ui/gfx/vector2d_f.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| const int kFlushInputRateInMs = 16; |
| const int kPointerAssumedStoppedTimeMs = 43; |
| const int kTouchSlopInDips = 7; |
| |
| class MockSyntheticGesture : public SyntheticGesture { |
| public: |
| MockSyntheticGesture(bool* finished, int num_steps) |
| : finished_(finished), |
| num_steps_(num_steps), |
| step_count_(0) { |
| *finished_ = false; |
| } |
| virtual ~MockSyntheticGesture() {} |
| |
| virtual Result ForwardInputEvents(const base::TimeDelta& interval, |
| SyntheticGestureTarget* target) OVERRIDE { |
| step_count_++; |
| if (step_count_ == num_steps_) { |
| *finished_ = true; |
| return SyntheticGesture::GESTURE_FINISHED; |
| } else if (step_count_ > num_steps_) { |
| *finished_ = true; |
| // Return arbitrary failure. |
| return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED; |
| } |
| |
| return SyntheticGesture::GESTURE_RUNNING; |
| } |
| |
| protected: |
| bool* finished_; |
| int num_steps_; |
| int step_count_; |
| }; |
| |
| class MockSyntheticGestureTarget : public SyntheticGestureTarget { |
| public: |
| MockSyntheticGestureTarget() |
| : num_success_(0), |
| num_failure_(0), |
| flush_requested_(false), |
| pointer_assumed_stopped_time_ms_(kPointerAssumedStoppedTimeMs) {} |
| virtual ~MockSyntheticGestureTarget() {} |
| |
| // SyntheticGestureTarget: |
| virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE {} |
| |
| virtual void OnSyntheticGestureCompleted( |
| SyntheticGesture::Result result) OVERRIDE { |
| DCHECK_NE(result, SyntheticGesture::GESTURE_RUNNING); |
| if (result == SyntheticGesture::GESTURE_FINISHED) |
| num_success_++; |
| else |
| num_failure_++; |
| } |
| |
| virtual void SetNeedsFlush() OVERRIDE { |
| flush_requested_ = true; |
| } |
| |
| virtual SyntheticGestureParams::GestureSourceType |
| GetDefaultSyntheticGestureSourceType() const OVERRIDE { |
| return SyntheticGestureParams::TOUCH_INPUT; |
| } |
| virtual bool SupportsSyntheticGestureSourceType( |
| SyntheticGestureParams::GestureSourceType gesture_source_type) |
| const OVERRIDE { |
| return true; |
| } |
| |
| virtual base::TimeDelta PointerAssumedStoppedTime() const OVERRIDE { |
| return base::TimeDelta::FromMilliseconds(pointer_assumed_stopped_time_ms_); |
| } |
| |
| void set_pointer_assumed_stopped_time_ms(int time_ms) { |
| pointer_assumed_stopped_time_ms_ = time_ms; |
| } |
| |
| virtual int GetTouchSlopInDips() const OVERRIDE { |
| return kTouchSlopInDips; |
| } |
| |
| int num_success() const { return num_success_; } |
| int num_failure() const { return num_failure_; } |
| |
| bool flush_requested() const { return flush_requested_; } |
| void ClearFlushRequest() { flush_requested_ = false; } |
| |
| private: |
| int num_success_; |
| int num_failure_; |
| |
| bool flush_requested_; |
| |
| int pointer_assumed_stopped_time_ms_; |
| }; |
| |
| class MockSyntheticSmoothScrollGestureTarget |
| : public MockSyntheticGestureTarget { |
| public: |
| MockSyntheticSmoothScrollGestureTarget() {} |
| virtual ~MockSyntheticSmoothScrollGestureTarget() {} |
| |
| gfx::Vector2dF scroll_distance() const { return scroll_distance_; } |
| |
| protected: |
| gfx::Vector2dF scroll_distance_; |
| }; |
| |
| class MockSyntheticSmoothScrollMouseTarget |
| : public MockSyntheticSmoothScrollGestureTarget { |
| public: |
| MockSyntheticSmoothScrollMouseTarget() {} |
| virtual ~MockSyntheticSmoothScrollMouseTarget() {} |
| |
| virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE { |
| const blink::WebInputEvent* web_event = event.web_event.get(); |
| ASSERT_EQ(web_event->type, blink::WebInputEvent::MouseWheel); |
| const blink::WebMouseWheelEvent* mouse_wheel_event = |
| static_cast<const blink::WebMouseWheelEvent*>(web_event); |
| scroll_distance_ -= gfx::Vector2dF(mouse_wheel_event->deltaX, |
| mouse_wheel_event->deltaY); |
| } |
| }; |
| |
| class MockSyntheticSmoothScrollTouchTarget |
| : public MockSyntheticSmoothScrollGestureTarget { |
| public: |
| MockSyntheticSmoothScrollTouchTarget() |
| : started_(false) {} |
| virtual ~MockSyntheticSmoothScrollTouchTarget() {} |
| |
| virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE { |
| const blink::WebInputEvent* web_event = event.web_event.get(); |
| ASSERT_TRUE(blink::WebInputEvent::isTouchEventType(web_event->type)); |
| const blink::WebTouchEvent* touch_event = |
| static_cast<const blink::WebTouchEvent*>(web_event); |
| ASSERT_EQ(touch_event->touchesLength, (unsigned int)1); |
| |
| if (!started_) { |
| ASSERT_EQ(touch_event->type, blink::WebInputEvent::TouchStart); |
| anchor_.SetPoint(touch_event->touches[0].position.x, |
| touch_event->touches[0].position.y); |
| started_ = true; |
| } else { |
| ASSERT_NE(touch_event->type, blink::WebInputEvent::TouchStart); |
| ASSERT_NE(touch_event->type, blink::WebInputEvent::TouchCancel); |
| // Ignore move events. |
| |
| if (touch_event->type == blink::WebInputEvent::TouchEnd) |
| scroll_distance_ = |
| anchor_ - gfx::PointF(touch_event->touches[0].position.x, |
| touch_event->touches[0].position.y); |
| } |
| } |
| |
| protected: |
| gfx::Point anchor_; |
| bool started_; |
| }; |
| |
| class MockSyntheticPinchTouchTarget : public MockSyntheticGestureTarget { |
| public: |
| enum ZoomDirection { |
| ZOOM_DIRECTION_UNKNOWN, |
| ZOOM_IN, |
| ZOOM_OUT |
| }; |
| |
| MockSyntheticPinchTouchTarget() |
| : total_num_pixels_covered_(0), |
| last_pointer_distance_(0), |
| zoom_direction_(ZOOM_DIRECTION_UNKNOWN), |
| started_(false) {} |
| virtual ~MockSyntheticPinchTouchTarget() {} |
| |
| virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE { |
| const blink::WebInputEvent* web_event = event.web_event.get(); |
| ASSERT_TRUE(blink::WebInputEvent::isTouchEventType(web_event->type)); |
| const blink::WebTouchEvent* touch_event = |
| static_cast<const blink::WebTouchEvent*>(web_event); |
| ASSERT_EQ(touch_event->touchesLength, (unsigned int)2); |
| |
| if (!started_) { |
| ASSERT_EQ(touch_event->type, blink::WebInputEvent::TouchStart); |
| |
| start_0_ = gfx::Point(touch_event->touches[0].position); |
| start_1_ = gfx::Point(touch_event->touches[1].position); |
| last_pointer_distance_ = (start_0_ - start_1_).Length(); |
| |
| started_ = true; |
| } else { |
| ASSERT_NE(touch_event->type, blink::WebInputEvent::TouchStart); |
| ASSERT_NE(touch_event->type, blink::WebInputEvent::TouchCancel); |
| |
| gfx::PointF current_0 = gfx::Point(touch_event->touches[0].position); |
| gfx::PointF current_1 = gfx::Point(touch_event->touches[1].position); |
| |
| total_num_pixels_covered_ = |
| (current_0 - start_0_).Length() + (current_1 - start_1_).Length(); |
| float pointer_distance = (current_0 - current_1).Length(); |
| |
| if (last_pointer_distance_ != pointer_distance) { |
| if (zoom_direction_ == ZOOM_DIRECTION_UNKNOWN) |
| zoom_direction_ = |
| ComputeZoomDirection(last_pointer_distance_, pointer_distance); |
| else |
| EXPECT_EQ( |
| zoom_direction_, |
| ComputeZoomDirection(last_pointer_distance_, pointer_distance)); |
| } |
| |
| last_pointer_distance_ = pointer_distance; |
| } |
| } |
| |
| float total_num_pixels_covered() const { return total_num_pixels_covered_; } |
| ZoomDirection zoom_direction() const { return zoom_direction_; } |
| |
| private: |
| ZoomDirection ComputeZoomDirection(float last_pointer_distance, |
| float current_pointer_distance) { |
| DCHECK_NE(last_pointer_distance, current_pointer_distance); |
| return last_pointer_distance < current_pointer_distance ? ZOOM_IN |
| : ZOOM_OUT; |
| } |
| |
| float total_num_pixels_covered_; |
| float last_pointer_distance_; |
| ZoomDirection zoom_direction_; |
| gfx::PointF start_0_; |
| gfx::PointF start_1_; |
| bool started_; |
| }; |
| |
| class MockSyntheticTapGestureTarget : public MockSyntheticGestureTarget { |
| public: |
| MockSyntheticTapGestureTarget() : state_(NOT_STARTED) {} |
| virtual ~MockSyntheticTapGestureTarget() {} |
| |
| bool GestureFinished() const { return state_ == FINISHED; } |
| gfx::Point position() const { return position_; } |
| |
| protected: |
| enum GestureState { |
| NOT_STARTED, |
| STARTED, |
| FINISHED |
| }; |
| |
| gfx::Point position_; |
| GestureState state_; |
| }; |
| |
| class MockSyntheticTapTouchTarget : public MockSyntheticTapGestureTarget { |
| public: |
| MockSyntheticTapTouchTarget() {} |
| virtual ~MockSyntheticTapTouchTarget() {} |
| |
| virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE { |
| const blink::WebInputEvent* web_event = event.web_event.get(); |
| ASSERT_TRUE(blink::WebInputEvent::isTouchEventType(web_event->type)); |
| const blink::WebTouchEvent* touch_event = |
| static_cast<const blink::WebTouchEvent*>(web_event); |
| ASSERT_EQ(touch_event->touchesLength, (unsigned int)1); |
| |
| switch (state_) { |
| case NOT_STARTED: |
| EXPECT_EQ(touch_event->type, blink::WebInputEvent::TouchStart); |
| position_ = gfx::Point(touch_event->touches[0].position); |
| state_ = STARTED; |
| break; |
| case STARTED: |
| EXPECT_EQ(touch_event->type, blink::WebInputEvent::TouchEnd); |
| EXPECT_EQ(position_, gfx::Point(touch_event->touches[0].position)); |
| state_ = FINISHED; |
| break; |
| case FINISHED: |
| EXPECT_FALSE(true); |
| break; |
| } |
| } |
| }; |
| |
| class MockSyntheticTapMouseTarget : public MockSyntheticTapGestureTarget { |
| public: |
| MockSyntheticTapMouseTarget() {} |
| virtual ~MockSyntheticTapMouseTarget() {} |
| |
| virtual void DispatchInputEventToPlatform(const InputEvent& event) OVERRIDE { |
| const blink::WebInputEvent* web_event = event.web_event.get(); |
| ASSERT_TRUE(blink::WebInputEvent::isMouseEventType(web_event->type)); |
| const blink::WebMouseEvent* mouse_event = |
| static_cast<const blink::WebMouseEvent*>(web_event); |
| |
| switch (state_) { |
| case NOT_STARTED: |
| EXPECT_EQ(mouse_event->type, blink::WebInputEvent::MouseDown); |
| EXPECT_EQ(mouse_event->button, blink::WebMouseEvent::ButtonLeft); |
| EXPECT_EQ(mouse_event->clickCount, 1); |
| position_ = gfx::Point(mouse_event->x, mouse_event->y); |
| state_ = STARTED; |
| break; |
| case STARTED: |
| EXPECT_EQ(mouse_event->type, blink::WebInputEvent::MouseUp); |
| EXPECT_EQ(mouse_event->button, blink::WebMouseEvent::ButtonLeft); |
| EXPECT_EQ(mouse_event->clickCount, 1); |
| EXPECT_EQ(position_, gfx::Point(mouse_event->x, mouse_event->y)); |
| state_ = FINISHED; |
| break; |
| case FINISHED: |
| EXPECT_FALSE(true); |
| break; |
| } |
| } |
| }; |
| |
| class SyntheticGestureControllerTest : public testing::Test { |
| public: |
| SyntheticGestureControllerTest() {} |
| virtual ~SyntheticGestureControllerTest() {} |
| |
| protected: |
| template<typename MockGestureTarget> |
| void CreateControllerAndTarget() { |
| target_ = new MockGestureTarget(); |
| |
| controller_.reset(new SyntheticGestureController( |
| scoped_ptr<SyntheticGestureTarget>(target_))); |
| } |
| |
| virtual void SetUp() OVERRIDE { |
| start_time_ = base::TimeTicks::Now(); |
| time_ = start_time_; |
| } |
| |
| virtual void TearDown() OVERRIDE { |
| controller_.reset(); |
| target_ = NULL; |
| time_ = base::TimeTicks(); |
| } |
| |
| void FlushInputUntilComplete() { |
| while (target_->flush_requested()) { |
| target_->ClearFlushRequest(); |
| time_ += base::TimeDelta::FromMilliseconds(kFlushInputRateInMs); |
| controller_->Flush(time_); |
| } |
| } |
| |
| base::TimeDelta GetTotalTime() const { return time_ - start_time_; } |
| |
| MockSyntheticGestureTarget* target_; |
| scoped_ptr<SyntheticGestureController> controller_; |
| base::TimeTicks start_time_; |
| base::TimeTicks time_; |
| }; |
| |
| TEST_F(SyntheticGestureControllerTest, SingleGesture) { |
| CreateControllerAndTarget<MockSyntheticGestureTarget>(); |
| |
| bool finished; |
| scoped_ptr<MockSyntheticGesture> gesture( |
| new MockSyntheticGesture(&finished, 3)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, GestureFailed) { |
| CreateControllerAndTarget<MockSyntheticGestureTarget>(); |
| |
| bool finished; |
| scoped_ptr<MockSyntheticGesture> gesture( |
| new MockSyntheticGesture(&finished, 0)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished); |
| EXPECT_EQ(1, target_->num_failure()); |
| EXPECT_EQ(0, target_->num_success()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SuccessiveGestures) { |
| CreateControllerAndTarget<MockSyntheticGestureTarget>(); |
| |
| bool finished_1, finished_2; |
| scoped_ptr<MockSyntheticGesture> gesture_1( |
| new MockSyntheticGesture(&finished_1, 2)); |
| scoped_ptr<MockSyntheticGesture> gesture_2( |
| new MockSyntheticGesture(&finished_2, 4)); |
| |
| // Queue first gesture and wait for it to finish |
| controller_->QueueSyntheticGesture(gesture_1.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished_1); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| |
| // Queue second gesture. |
| controller_->QueueSyntheticGesture(gesture_2.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished_2); |
| EXPECT_EQ(2, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TwoGesturesInFlight) { |
| CreateControllerAndTarget<MockSyntheticGestureTarget>(); |
| |
| bool finished_1, finished_2; |
| scoped_ptr<MockSyntheticGesture> gesture_1( |
| new MockSyntheticGesture(&finished_1, 2)); |
| scoped_ptr<MockSyntheticGesture> gesture_2( |
| new MockSyntheticGesture(&finished_2, 4)); |
| |
| controller_->QueueSyntheticGesture(gesture_1.PassAs<SyntheticGesture>()); |
| controller_->QueueSyntheticGesture(gesture_2.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished_1); |
| EXPECT_TRUE(finished_2); |
| |
| EXPECT_EQ(2, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| } |
| |
| gfx::Vector2d AddTouchSlopToVector(const gfx::Vector2d& vector, |
| SyntheticGestureTarget* target) { |
| const int kTouchSlop = target->GetTouchSlopInDips(); |
| |
| int x = vector.x(); |
| if (x > 0) |
| x += kTouchSlop; |
| else if (x < 0) |
| x -= kTouchSlop; |
| |
| int y = vector.y(); |
| if (y > 0) |
| y += kTouchSlop; |
| else if (y < 0) |
| y -= kTouchSlop; |
| |
| return gfx::Vector2d(x, y); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureTouchVertical) { |
| CreateControllerAndTarget<MockSyntheticSmoothScrollTouchTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.distance = gfx::Vector2d(0, 123); |
| params.anchor.SetPoint(89, 32); |
| |
| scoped_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticSmoothScrollGestureTarget* smooth_scroll_target = |
| static_cast<MockSyntheticSmoothScrollGestureTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_EQ(AddTouchSlopToVector(params.distance, target_), |
| smooth_scroll_target->scroll_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureTouchHorizontal) { |
| CreateControllerAndTarget<MockSyntheticSmoothScrollTouchTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.distance = gfx::Vector2d(-234, 0); |
| params.anchor.SetPoint(12, -23); |
| |
| scoped_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticSmoothScrollGestureTarget* smooth_scroll_target = |
| static_cast<MockSyntheticSmoothScrollGestureTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_EQ(AddTouchSlopToVector(params.distance, target_), |
| smooth_scroll_target->scroll_distance()); |
| } |
| |
| void CheckIsWithinRange(float scroll_distance, |
| int target_distance, |
| SyntheticGestureTarget* target) { |
| if (target_distance > 0) { |
| EXPECT_LE(target_distance, scroll_distance); |
| EXPECT_LE(scroll_distance, target_distance + target->GetTouchSlopInDips()); |
| } else { |
| EXPECT_GE(target_distance, scroll_distance); |
| EXPECT_GE(scroll_distance, target_distance - target->GetTouchSlopInDips()); |
| } |
| } |
| |
| void CheckScrollDistanceIsWithinRange(const gfx::Vector2dF& scroll_distance, |
| const gfx::Vector2d& target_distance, |
| SyntheticGestureTarget* target) { |
| CheckIsWithinRange(scroll_distance.x(), target_distance.x(), target); |
| CheckIsWithinRange(scroll_distance.y(), target_distance.y(), target); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureTouchDiagonal) { |
| CreateControllerAndTarget<MockSyntheticSmoothScrollTouchTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.distance = gfx::Vector2d(413, -83); |
| params.anchor.SetPoint(0, 7); |
| |
| scoped_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticSmoothScrollGestureTarget* smooth_scroll_target = |
| static_cast<MockSyntheticSmoothScrollGestureTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| CheckScrollDistanceIsWithinRange( |
| smooth_scroll_target->scroll_distance(), params.distance, target_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureTouchLongStop) { |
| CreateControllerAndTarget<MockSyntheticSmoothScrollTouchTarget>(); |
| |
| // Create a smooth scroll with a short distance and set the pointer assumed |
| // stopped time high, so that the stopping should dominate the time the |
| // gesture is active. |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.distance = gfx::Vector2d(21, -12); |
| params.prevent_fling = true; |
| params.anchor.SetPoint(-98, -23); |
| |
| target_->set_pointer_assumed_stopped_time_ms(543); |
| |
| scoped_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticSmoothScrollGestureTarget* smooth_scroll_target = |
| static_cast<MockSyntheticSmoothScrollGestureTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| CheckScrollDistanceIsWithinRange( |
| smooth_scroll_target->scroll_distance(), params.distance, target_); |
| EXPECT_GE(GetTotalTime(), target_->PointerAssumedStoppedTime()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureTouchFling) { |
| CreateControllerAndTarget<MockSyntheticSmoothScrollTouchTarget>(); |
| |
| // Create a smooth scroll with a short distance and set the pointer assumed |
| // stopped time high. Disable 'prevent_fling' and check that the gesture |
| // finishes without waiting before it stops. |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.distance = gfx::Vector2d(-43, 19); |
| params.prevent_fling = false; |
| params.anchor.SetPoint(-89, 78); |
| |
| target_->set_pointer_assumed_stopped_time_ms(543); |
| |
| scoped_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticSmoothScrollGestureTarget* smooth_scroll_target = |
| static_cast<MockSyntheticSmoothScrollGestureTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| CheckScrollDistanceIsWithinRange( |
| smooth_scroll_target->scroll_distance(), params.distance, target_); |
| EXPECT_LE(GetTotalTime(), target_->PointerAssumedStoppedTime()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureTouchZeroDistance) { |
| CreateControllerAndTarget<MockSyntheticSmoothScrollTouchTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.distance = gfx::Vector2d(0, 0); |
| params.anchor.SetPoint(-32, 43); |
| |
| scoped_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticSmoothScrollGestureTarget* smooth_scroll_target = |
| static_cast<MockSyntheticSmoothScrollGestureTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_EQ(gfx::Vector2dF(0, 0), smooth_scroll_target->scroll_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureMouseVertical) { |
| CreateControllerAndTarget<MockSyntheticSmoothScrollMouseTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT; |
| params.distance = gfx::Vector2d(0, -234); |
| params.anchor.SetPoint(432, 89); |
| |
| scoped_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticSmoothScrollGestureTarget* smooth_scroll_target = |
| static_cast<MockSyntheticSmoothScrollGestureTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_EQ(params.distance, smooth_scroll_target->scroll_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureMouseHorizontal) { |
| CreateControllerAndTarget<MockSyntheticSmoothScrollMouseTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT; |
| params.distance = gfx::Vector2d(345, 0); |
| params.anchor.SetPoint(90, 12); |
| |
| scoped_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticSmoothScrollGestureTarget* smooth_scroll_target = |
| static_cast<MockSyntheticSmoothScrollGestureTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_EQ(params.distance, smooth_scroll_target->scroll_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SmoothScrollGestureMouseDiagonal) { |
| CreateControllerAndTarget<MockSyntheticSmoothScrollMouseTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT; |
| params.distance = gfx::Vector2d(-194, 303); |
| params.anchor.SetPoint(90, 12); |
| |
| scoped_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticSmoothScrollGestureTarget* smooth_scroll_target = |
| static_cast<MockSyntheticSmoothScrollGestureTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_EQ(params.distance, smooth_scroll_target->scroll_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomIn) { |
| CreateControllerAndTarget<MockSyntheticPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.zoom_in = true; |
| params.total_num_pixels_covered = 345; |
| params.anchor.SetPoint(54, 89); |
| |
| scoped_ptr<SyntheticPinchGesture> gesture(new SyntheticPinchGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticPinchTouchTarget* pinch_target = |
| static_cast<MockSyntheticPinchTouchTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_EQ(pinch_target->zoom_direction(), |
| MockSyntheticPinchTouchTarget::ZOOM_IN); |
| EXPECT_EQ(params.total_num_pixels_covered + 2 * target_->GetTouchSlopInDips(), |
| pinch_target->total_num_pixels_covered()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomOut) { |
| CreateControllerAndTarget<MockSyntheticPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.zoom_in = false; |
| params.total_num_pixels_covered = 456; |
| params.anchor.SetPoint(-12, 93); |
| |
| scoped_ptr<SyntheticPinchGesture> gesture(new SyntheticPinchGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticPinchTouchTarget* pinch_target = |
| static_cast<MockSyntheticPinchTouchTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_EQ(pinch_target->zoom_direction(), |
| MockSyntheticPinchTouchTarget::ZOOM_OUT); |
| EXPECT_EQ(params.total_num_pixels_covered + 2 * target_->GetTouchSlopInDips(), |
| pinch_target->total_num_pixels_covered()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZeroPixelsCovered) { |
| CreateControllerAndTarget<MockSyntheticPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.zoom_in = true; |
| params.total_num_pixels_covered = 0; |
| |
| scoped_ptr<SyntheticPinchGesture> gesture(new SyntheticPinchGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticPinchTouchTarget* pinch_target = |
| static_cast<MockSyntheticPinchTouchTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_EQ(pinch_target->zoom_direction(), |
| MockSyntheticPinchTouchTarget::ZOOM_DIRECTION_UNKNOWN); |
| EXPECT_EQ(0, pinch_target->total_num_pixels_covered()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TapGestureTouch) { |
| CreateControllerAndTarget<MockSyntheticTapTouchTarget>(); |
| |
| SyntheticTapGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| params.duration_ms = 123; |
| params.position.SetPoint(87, -124); |
| |
| scoped_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTapTouchTarget* tap_target = |
| static_cast<MockSyntheticTapTouchTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_TRUE(tap_target->GestureFinished()); |
| EXPECT_EQ(tap_target->position(), params.position); |
| EXPECT_GE(GetTotalTime(), |
| base::TimeDelta::FromMilliseconds(params.duration_ms)); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TapGestureMouse) { |
| CreateControllerAndTarget<MockSyntheticTapMouseTarget>(); |
| |
| SyntheticTapGestureParams params; |
| params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT; |
| params.duration_ms = 79; |
| params.position.SetPoint(98, 123); |
| |
| scoped_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params)); |
| controller_->QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>()); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTapMouseTarget* tap_target = |
| static_cast<MockSyntheticTapMouseTarget*>(target_); |
| EXPECT_EQ(1, target_->num_success()); |
| EXPECT_EQ(0, target_->num_failure()); |
| EXPECT_TRUE(tap_target->GestureFinished()); |
| EXPECT_EQ(tap_target->position(), params.position); |
| EXPECT_GE(GetTotalTime(), |
| base::TimeDelta::FromMilliseconds(params.duration_ms)); |
| } |
| |
| } // namespace |
| |
| } // namespace content |