| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifdef UNSAFE_BUFFERS_BUILD |
| // TODO(crbug.com/342213636): Remove this and spanify to fix the errors. |
| #pragma allow_unsafe_buffers |
| #endif |
| |
| #include "content/common/input/synthetic_gesture_controller.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <array> |
| #include <memory> |
| #include <utility> |
| |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/test/task_environment.h" |
| #include "base/time/time.h" |
| #include "content/common/input/synthetic_gesture.h" |
| #include "content/common/input/synthetic_gesture_target.h" |
| #include "content/common/input/synthetic_pinch_gesture.h" |
| #include "content/common/input/synthetic_pinch_gesture_params.h" |
| #include "content/common/input/synthetic_pointer_action.h" |
| #include "content/common/input/synthetic_smooth_drag_gesture.h" |
| #include "content/common/input/synthetic_smooth_drag_gesture_params.h" |
| #include "content/common/input/synthetic_smooth_move_gesture.h" |
| #include "content/common/input/synthetic_smooth_scroll_gesture.h" |
| #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" |
| #include "content/common/input/synthetic_tap_gesture.h" |
| #include "content/common/input/synthetic_tap_gesture_params.h" |
| #include "content/common/input/synthetic_touchpad_pinch_gesture.h" |
| #include "content/common/input/synthetic_touchscreen_pinch_gesture.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/input/web_input_event.h" |
| #include "ui/gfx/geometry/point.h" |
| #include "ui/gfx/geometry/point_f.h" |
| #include "ui/gfx/geometry/vector2d.h" |
| #include "ui/gfx/geometry/vector2d_f.h" |
| |
| using blink::WebInputEvent; |
| using blink::WebMouseEvent; |
| using blink::WebMouseWheelEvent; |
| using blink::WebTouchEvent; |
| using blink::WebTouchPoint; |
| |
| namespace content { |
| |
| namespace { |
| |
| const int kFlushInputRateInMs = 16; |
| const int kPointerAssumedStoppedTimeMs = 43; |
| const float kTouchSlopInDips = 7.0f; |
| const float kMinScalingSpanInDips = 27.5f; |
| const int kTouchPointersLength = 16; |
| const int kMouseWheelTickMultiplier = 0; |
| |
| enum TouchGestureType { TOUCH_SCROLL, TOUCH_DRAG }; |
| |
| WebTouchPoint::State ToWebTouchPointState( |
| SyntheticPointerActionParams::PointerActionType action_type) { |
| switch (action_type) { |
| case SyntheticPointerActionParams::PointerActionType::PRESS: |
| return WebTouchPoint::State::kStatePressed; |
| case SyntheticPointerActionParams::PointerActionType::MOVE: |
| return WebTouchPoint::State::kStateMoved; |
| case SyntheticPointerActionParams::PointerActionType::RELEASE: |
| return WebTouchPoint::State::kStateReleased; |
| case SyntheticPointerActionParams::PointerActionType::CANCEL: |
| return WebTouchPoint::State::kStateCancelled; |
| case SyntheticPointerActionParams::PointerActionType::IDLE: |
| return WebTouchPoint::State::kStateStationary; |
| case SyntheticPointerActionParams::PointerActionType::LEAVE: |
| case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED: |
| NOTREACHED() |
| << "Invalid SyntheticPointerActionParams::PointerActionType."; |
| } |
| NOTREACHED() << "Invalid SyntheticPointerActionParams::PointerActionType."; |
| } |
| |
| WebInputEvent::Type ToWebMouseEventType( |
| SyntheticPointerActionParams::PointerActionType action_type) { |
| switch (action_type) { |
| case SyntheticPointerActionParams::PointerActionType::PRESS: |
| return WebInputEvent::Type::kMouseDown; |
| case SyntheticPointerActionParams::PointerActionType::MOVE: |
| return WebInputEvent::Type::kMouseMove; |
| case SyntheticPointerActionParams::PointerActionType::RELEASE: |
| return WebInputEvent::Type::kMouseUp; |
| case SyntheticPointerActionParams::PointerActionType::LEAVE: |
| return WebInputEvent::Type::kMouseLeave; |
| case SyntheticPointerActionParams::PointerActionType::CANCEL: |
| case SyntheticPointerActionParams::PointerActionType::IDLE: |
| case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED: |
| NOTREACHED() |
| << "Invalid SyntheticPointerActionParams::PointerActionType."; |
| } |
| NOTREACHED() << "Invalid SyntheticPointerActionParams::PointerActionType."; |
| } |
| |
| WebInputEvent::Type WebTouchPointStateToEventType( |
| blink::WebTouchPoint::State state) { |
| switch (state) { |
| case blink::WebTouchPoint::State::kStateReleased: |
| return WebInputEvent::Type::kTouchEnd; |
| case blink::WebTouchPoint::State::kStatePressed: |
| return WebInputEvent::Type::kTouchStart; |
| case blink::WebTouchPoint::State::kStateMoved: |
| return WebInputEvent::Type::kTouchMove; |
| case blink::WebTouchPoint::State::kStateCancelled: |
| return WebInputEvent::Type::kTouchCancel; |
| default: |
| return WebInputEvent::Type::kUndefined; |
| } |
| } |
| |
| class MockGestureParams : public SyntheticGestureParams { |
| public: |
| GestureType GetGestureType() const override { |
| return SyntheticGestureParams::TAP_GESTURE; |
| } |
| }; |
| |
| class MockSyntheticGesture : public SyntheticGestureBase<MockGestureParams> { |
| public: |
| MockSyntheticGesture(bool* finished, int num_steps) |
| : SyntheticGestureBase(MockGestureParams()), |
| finished_(finished), |
| num_steps_(num_steps), |
| step_count_(0) { |
| *finished_ = false; |
| } |
| ~MockSyntheticGesture() override {} |
| |
| Result ForwardInputEvents(const base::TimeTicks& timestamp, |
| 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: |
| raw_ptr<bool> finished_; |
| int num_steps_; |
| int step_count_; |
| }; |
| |
| class MockSyntheticGestureTarget : public SyntheticGestureTarget { |
| public: |
| MockSyntheticGestureTarget() |
| : flush_requested_(false), |
| pointer_assumed_stopped_time_ms_(kPointerAssumedStoppedTimeMs) {} |
| ~MockSyntheticGestureTarget() override {} |
| |
| // SyntheticGestureTarget: |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| if (!(event.GetModifiers() & blink::WebInputEvent::kFromDebugger)) { |
| all_from_debugger_ = false; |
| } |
| } |
| |
| void GetVSyncParameters(base::TimeTicks& timebase, |
| base::TimeDelta& interval) const override { |
| timebase = base::TimeTicks(); |
| interval = base::Microseconds(16667); |
| } |
| |
| content::mojom::GestureSourceType GetDefaultSyntheticGestureSourceType() |
| const override { |
| return content::mojom::GestureSourceType::kTouchInput; |
| } |
| |
| base::TimeDelta PointerAssumedStoppedTime() const override { |
| return base::Milliseconds(pointer_assumed_stopped_time_ms_); |
| } |
| |
| void set_pointer_assumed_stopped_time_ms(int time_ms) { |
| pointer_assumed_stopped_time_ms_ = time_ms; |
| } |
| |
| float GetTouchSlopInDips() const override { return kTouchSlopInDips; } |
| float GetSpanSlopInDips() const override { return 2 * kTouchSlopInDips; } |
| |
| int GetMouseWheelMinimumGranularity() const override { |
| return kMouseWheelTickMultiplier; |
| } |
| |
| float GetMinScalingSpanInDips() const override { |
| return kMinScalingSpanInDips; |
| } |
| |
| bool flush_requested() const { return flush_requested_; } |
| void ClearFlushRequest() { flush_requested_ = false; } |
| |
| void WaitForTargetAck(SyntheticGestureParams::GestureType type, |
| content::mojom::GestureSourceType source, |
| base::OnceClosure callback) const override { |
| // Must resolve synchronously since FlushInputUntilComplete will try the |
| // next gesture after this one. |
| std::move(callback).Run(); |
| } |
| |
| bool all_from_debugger() { return all_from_debugger_; } |
| |
| private: |
| bool flush_requested_; |
| |
| int pointer_assumed_stopped_time_ms_; |
| bool all_from_debugger_ = true; |
| }; |
| |
| class MockMoveGestureTarget : public MockSyntheticGestureTarget { |
| public: |
| MockMoveGestureTarget() |
| : total_abs_move_distance_length_(0), |
| granularity_(ui::ScrollGranularity::kScrollByPixel) {} |
| ~MockMoveGestureTarget() override {} |
| |
| gfx::Vector2dF start_to_end_distance() const { |
| return start_to_end_distance_; |
| } |
| float total_abs_move_distance_length() const { |
| return total_abs_move_distance_length_; |
| } |
| |
| ui::ScrollGranularity granularity() const { return granularity_; } |
| |
| protected: |
| gfx::Vector2dF start_to_end_distance_; |
| float total_abs_move_distance_length_; |
| ui::ScrollGranularity granularity_; |
| }; |
| |
| class MockScrollMouseTarget : public MockMoveGestureTarget { |
| public: |
| MockScrollMouseTarget() {} |
| ~MockScrollMouseTarget() override {} |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| ASSERT_EQ(event.GetType(), WebInputEvent::Type::kMouseWheel); |
| const WebMouseWheelEvent& mouse_wheel_event = |
| static_cast<const WebMouseWheelEvent&>(event); |
| gfx::Vector2dF delta(mouse_wheel_event.delta_x, mouse_wheel_event.delta_y); |
| start_to_end_distance_ += delta; |
| total_abs_move_distance_length_ += delta.Length(); |
| granularity_ = mouse_wheel_event.delta_units; |
| } |
| }; |
| |
| class MockMoveTouchTarget : public MockMoveGestureTarget { |
| public: |
| MockMoveTouchTarget() : started_(false) {} |
| ~MockMoveTouchTarget() override {} |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| ASSERT_TRUE(WebInputEvent::IsTouchEventType(event.GetType())); |
| const WebTouchEvent& touch_event = static_cast<const WebTouchEvent&>(event); |
| ASSERT_EQ(touch_event.touches_length, 1U); |
| |
| if (!started_) { |
| ASSERT_EQ(touch_event.GetType(), WebInputEvent::Type::kTouchStart); |
| start_ = touch_event.touches[0].PositionInWidget(); |
| last_touch_point_ = start_; |
| started_ = true; |
| } else { |
| ASSERT_NE(touch_event.GetType(), WebInputEvent::Type::kTouchStart); |
| ASSERT_NE(touch_event.GetType(), WebInputEvent::Type::kTouchCancel); |
| |
| gfx::PointF touch_point(touch_event.touches[0].PositionInWidget()); |
| gfx::Vector2dF delta = touch_point - last_touch_point_; |
| total_abs_move_distance_length_ += delta.Length(); |
| |
| if (touch_event.GetType() == WebInputEvent::Type::kTouchEnd) |
| start_to_end_distance_ = touch_point - start_; |
| |
| last_touch_point_ = touch_point; |
| } |
| } |
| |
| protected: |
| gfx::PointF start_; |
| gfx::PointF last_touch_point_; |
| bool started_; |
| }; |
| |
| class MockFlingGestureTarget : public MockMoveGestureTarget { |
| public: |
| MockFlingGestureTarget() : fling_velocity_x_(0), fling_velocity_y_(0) {} |
| ~MockFlingGestureTarget() override {} |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| if (event.GetType() == WebInputEvent::Type::kGestureFlingStart) { |
| const blink::WebGestureEvent& gesture_event = |
| static_cast<const blink::WebGestureEvent&>(event); |
| fling_velocity_x_ = gesture_event.data.fling_start.velocity_x; |
| fling_velocity_y_ = gesture_event.data.fling_start.velocity_y; |
| } |
| } |
| |
| float fling_velocity_x() const { return fling_velocity_x_; } |
| float fling_velocity_y() const { return fling_velocity_y_; } |
| |
| private: |
| float fling_velocity_x_; |
| float fling_velocity_y_; |
| }; |
| |
| class MockDragMouseTarget : public MockMoveGestureTarget { |
| public: |
| MockDragMouseTarget() : started_(false) {} |
| ~MockDragMouseTarget() override {} |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| ASSERT_TRUE(WebInputEvent::IsMouseEventType(event.GetType())); |
| const WebMouseEvent& mouse_event = static_cast<const WebMouseEvent&>(event); |
| if (!started_) { |
| EXPECT_EQ(mouse_event.button, WebMouseEvent::Button::kLeft); |
| EXPECT_EQ(mouse_event.click_count, 1); |
| EXPECT_EQ(mouse_event.GetType(), WebInputEvent::Type::kMouseDown); |
| start_ = mouse_event.PositionInWidget(); |
| last_mouse_point_ = start_; |
| started_ = true; |
| } else { |
| EXPECT_EQ(mouse_event.button, WebMouseEvent::Button::kLeft); |
| ASSERT_NE(mouse_event.GetType(), WebInputEvent::Type::kMouseDown); |
| |
| gfx::PointF mouse_point(mouse_event.PositionInWidget()); |
| gfx::Vector2dF delta = mouse_point - last_mouse_point_; |
| total_abs_move_distance_length_ += delta.Length(); |
| if (mouse_event.GetType() == WebInputEvent::Type::kMouseUp) |
| start_to_end_distance_ = mouse_point - start_; |
| last_mouse_point_ = mouse_point; |
| } |
| } |
| |
| private: |
| bool started_; |
| gfx::PointF start_, last_mouse_point_; |
| }; |
| |
| class MockSyntheticTouchscreenPinchTouchTarget |
| : public MockSyntheticGestureTarget { |
| public: |
| enum ZoomDirection { |
| ZOOM_DIRECTION_UNKNOWN, |
| ZOOM_IN, |
| ZOOM_OUT |
| }; |
| |
| MockSyntheticTouchscreenPinchTouchTarget() = default; |
| ~MockSyntheticTouchscreenPinchTouchTarget() override = default; |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| ASSERT_TRUE(WebInputEvent::IsTouchEventType(event.GetType())); |
| const WebTouchEvent& touch_event = static_cast<const WebTouchEvent&>(event); |
| if ((touch_event.GetType() == WebInputEvent::Type::kTouchStart && |
| !received_first_touch_start_) || |
| (touch_event.GetType() == WebInputEvent::Type::kTouchEnd && |
| received_first_touch_end_)) { |
| ASSERT_EQ(touch_event.touches_length, 1U); |
| } else { |
| ASSERT_EQ(touch_event.touches_length, 2U); |
| } |
| |
| if (!started_) { |
| ASSERT_EQ(touch_event.GetType(), WebInputEvent::Type::kTouchStart); |
| |
| if (received_first_touch_start_) { |
| start_0_ = gfx::PointF(touch_event.touches[0].PositionInWidget()); |
| start_1_ = gfx::PointF(touch_event.touches[1].PositionInWidget()); |
| last_pointer_distance_ = (start_0_ - start_1_).Length(); |
| initial_pointer_distance_ = last_pointer_distance_; |
| EXPECT_GE(initial_pointer_distance_, GetMinScalingSpanInDips()); |
| started_ = true; |
| } |
| } else { |
| ASSERT_NE(touch_event.GetType(), WebInputEvent::Type::kTouchStart); |
| ASSERT_NE(touch_event.GetType(), WebInputEvent::Type::kTouchCancel); |
| |
| if (!received_first_touch_end_) { |
| gfx::PointF current_0 = |
| gfx::PointF(touch_event.touches[0].PositionInWidget()); |
| gfx::PointF current_1 = |
| gfx::PointF(touch_event.touches[1].PositionInWidget()); |
| |
| 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; |
| } |
| } |
| |
| received_first_touch_start_ |= |
| touch_event.GetType() == WebInputEvent::Type::kTouchStart; |
| |
| received_first_touch_end_ |= |
| touch_event.GetType() == WebInputEvent::Type::kTouchEnd; |
| } |
| |
| content::mojom::GestureSourceType GetDefaultSyntheticGestureSourceType() |
| const override { |
| return content::mojom::GestureSourceType::kTouchInput; |
| } |
| |
| ZoomDirection zoom_direction() const { return zoom_direction_; } |
| |
| float ComputeScaleFactor() const { |
| switch (zoom_direction_) { |
| case ZOOM_IN: |
| return last_pointer_distance_ / |
| (initial_pointer_distance_ + GetSpanSlopInDips()); |
| case ZOOM_OUT: |
| return last_pointer_distance_ / |
| (initial_pointer_distance_ - GetSpanSlopInDips()); |
| case ZOOM_DIRECTION_UNKNOWN: |
| return 1.0f; |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| 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 initial_pointer_distance_ = 0.f; |
| float last_pointer_distance_ = 0.f; |
| ZoomDirection zoom_direction_ = ZOOM_DIRECTION_UNKNOWN; |
| gfx::PointF start_0_; |
| gfx::PointF start_1_; |
| // Starting and ending pinch zoom involves two events. Much of the unit test |
| // code applies only when both fingers are pressed. These two booleans allow |
| // us to do the required bookkeeping to ensure that we know when to do work |
| // that depends on both fingers being pressed. |
| bool received_first_touch_start_ = false; |
| bool received_first_touch_end_ = false; |
| bool started_ = false; |
| }; |
| |
| class MockSyntheticTouchpadPinchTouchTarget |
| : public MockSyntheticGestureTarget { |
| public: |
| enum ZoomDirection { ZOOM_DIRECTION_UNKNOWN, ZOOM_IN, ZOOM_OUT }; |
| |
| MockSyntheticTouchpadPinchTouchTarget() |
| : zoom_direction_(ZOOM_DIRECTION_UNKNOWN), |
| started_(false), |
| ended_(false), |
| scale_factor_(1.0f) {} |
| ~MockSyntheticTouchpadPinchTouchTarget() override {} |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| EXPECT_TRUE(WebInputEvent::IsGestureEventType(event.GetType())); |
| const blink::WebGestureEvent& gesture_event = |
| static_cast<const blink::WebGestureEvent&>(event); |
| |
| if (gesture_event.GetType() == WebInputEvent::Type::kGesturePinchBegin) { |
| EXPECT_FALSE(started_); |
| EXPECT_FALSE(ended_); |
| started_ = true; |
| } else if (gesture_event.GetType() == |
| WebInputEvent::Type::kGesturePinchEnd) { |
| EXPECT_TRUE(started_); |
| EXPECT_FALSE(ended_); |
| ended_ = true; |
| } else { |
| EXPECT_EQ(WebInputEvent::Type::kGesturePinchUpdate, |
| gesture_event.GetType()); |
| EXPECT_TRUE(started_); |
| EXPECT_FALSE(ended_); |
| const float scale = gesture_event.data.pinch_update.scale; |
| if (scale != 1.0f) { |
| if (zoom_direction_ == ZOOM_DIRECTION_UNKNOWN) { |
| zoom_direction_ = scale > 1.0f ? ZOOM_IN : ZOOM_OUT; |
| } else if (zoom_direction_ == ZOOM_IN) { |
| EXPECT_GT(scale, 1.0f); |
| } else { |
| EXPECT_EQ(ZOOM_OUT, zoom_direction_); |
| EXPECT_LT(scale, 1.0f); |
| } |
| |
| scale_factor_ *= scale; |
| } |
| } |
| } |
| |
| content::mojom::GestureSourceType GetDefaultSyntheticGestureSourceType() |
| const override { |
| return content::mojom::GestureSourceType::kMouseInput; |
| } |
| |
| ZoomDirection zoom_direction() const { return zoom_direction_; } |
| |
| float scale_factor() const { return scale_factor_; } |
| |
| private: |
| ZoomDirection zoom_direction_; |
| bool started_; |
| bool ended_; |
| float scale_factor_; |
| }; |
| |
| class MockSyntheticTapGestureTarget : public MockSyntheticGestureTarget { |
| public: |
| MockSyntheticTapGestureTarget() : state_(NOT_STARTED) {} |
| ~MockSyntheticTapGestureTarget() override {} |
| |
| bool GestureFinished() const { return state_ == FINISHED; } |
| gfx::PointF position() const { return position_; } |
| base::TimeDelta GetDuration() const { return stop_time_ - start_time_; } |
| |
| protected: |
| enum GestureState { |
| NOT_STARTED, |
| STARTED, |
| FINISHED |
| }; |
| |
| gfx::PointF position_; |
| base::TimeDelta start_time_; |
| base::TimeDelta stop_time_; |
| GestureState state_; |
| }; |
| |
| class MockSyntheticTapTouchTarget : public MockSyntheticTapGestureTarget { |
| public: |
| MockSyntheticTapTouchTarget() {} |
| ~MockSyntheticTapTouchTarget() override {} |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| ASSERT_TRUE(WebInputEvent::IsTouchEventType(event.GetType())); |
| const WebTouchEvent& touch_event = static_cast<const WebTouchEvent&>(event); |
| ASSERT_EQ(touch_event.touches_length, 1U); |
| |
| switch (state_) { |
| case NOT_STARTED: |
| EXPECT_EQ(touch_event.GetType(), WebInputEvent::Type::kTouchStart); |
| position_ = gfx::PointF(touch_event.touches[0].PositionInWidget()); |
| start_time_ = touch_event.TimeStamp().since_origin(); |
| state_ = STARTED; |
| break; |
| case STARTED: |
| EXPECT_EQ(touch_event.GetType(), WebInputEvent::Type::kTouchEnd); |
| EXPECT_EQ(position_, |
| gfx::PointF(touch_event.touches[0].PositionInWidget())); |
| stop_time_ = touch_event.TimeStamp().since_origin(); |
| state_ = FINISHED; |
| break; |
| case FINISHED: |
| EXPECT_FALSE(true); |
| break; |
| } |
| } |
| }; |
| |
| class MockSyntheticTapMouseTarget : public MockSyntheticTapGestureTarget { |
| public: |
| MockSyntheticTapMouseTarget() {} |
| ~MockSyntheticTapMouseTarget() override {} |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| ASSERT_TRUE(WebInputEvent::IsMouseEventType(event.GetType())); |
| const WebMouseEvent& mouse_event = static_cast<const WebMouseEvent&>(event); |
| |
| switch (state_) { |
| case NOT_STARTED: |
| EXPECT_EQ(mouse_event.GetType(), WebInputEvent::Type::kMouseDown); |
| EXPECT_EQ(mouse_event.button, WebMouseEvent::Button::kLeft); |
| EXPECT_EQ(mouse_event.click_count, 1); |
| position_ = gfx::PointF(mouse_event.PositionInWidget()); |
| start_time_ = mouse_event.TimeStamp().since_origin(); |
| state_ = STARTED; |
| break; |
| case STARTED: |
| EXPECT_EQ(mouse_event.GetType(), WebInputEvent::Type::kMouseUp); |
| EXPECT_EQ(mouse_event.button, WebMouseEvent::Button::kLeft); |
| EXPECT_EQ(mouse_event.click_count, 1); |
| EXPECT_EQ(position_, gfx::PointF(mouse_event.PositionInWidget())); |
| stop_time_ = mouse_event.TimeStamp().since_origin(); |
| state_ = FINISHED; |
| break; |
| case FINISHED: |
| EXPECT_FALSE(true); |
| break; |
| } |
| } |
| }; |
| |
| class MockSyntheticPointerActionTarget : public MockSyntheticGestureTarget { |
| public: |
| MockSyntheticPointerActionTarget() : num_dispatched_pointer_actions_(0) {} |
| ~MockSyntheticPointerActionTarget() override {} |
| |
| WebInputEvent::Type type() const { return type_; } |
| int num_dispatched_pointer_actions() const { |
| return num_dispatched_pointer_actions_; |
| } |
| void reset_num_dispatched_pointer_actions() { |
| num_dispatched_pointer_actions_ = 0; |
| } |
| |
| protected: |
| WebInputEvent::Type type_; |
| int num_dispatched_pointer_actions_; |
| }; |
| |
| class MockSyntheticPointerTouchActionTarget |
| : public MockSyntheticPointerActionTarget { |
| public: |
| MockSyntheticPointerTouchActionTarget() {} |
| ~MockSyntheticPointerTouchActionTarget() override {} |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| DCHECK(WebInputEvent::IsTouchEventType(event.GetType())); |
| const WebTouchEvent& touch_event = static_cast<const WebTouchEvent&>(event); |
| type_ = touch_event.GetType(); |
| for (size_t i = 0; i < WebTouchEvent::kTouchesLengthCap; ++i) { |
| if (WebTouchPointStateToEventType(touch_event.touches[i].state) != type_) |
| continue; |
| indexes_[num_dispatched_pointer_actions_] = i; |
| positions_[num_dispatched_pointer_actions_] = |
| gfx::PointF(touch_event.touches[i].PositionInWidget()); |
| states_[num_dispatched_pointer_actions_] = touch_event.touches[i].state; |
| num_dispatched_pointer_actions_++; |
| } |
| } |
| |
| testing::AssertionResult SyntheticTouchActionDispatchedCorrectly( |
| const SyntheticPointerActionParams& param, |
| int index, |
| int touch_index) { |
| if (param.pointer_action_type() == |
| SyntheticPointerActionParams::PointerActionType::PRESS || |
| param.pointer_action_type() == |
| SyntheticPointerActionParams::PointerActionType::MOVE) { |
| if (indexes_[index] != touch_index) { |
| return testing::AssertionFailure() |
| << "Pointer index at index " << index << " was " |
| << indexes_[index] << ", expected " << touch_index << "."; |
| } |
| |
| if (positions_[index] != param.position()) { |
| return testing::AssertionFailure() |
| << "Pointer position at index " << index << " was " |
| << positions_[index].ToString() << ", expected " |
| << param.position().ToString() << "."; |
| } |
| } |
| |
| if (states_[index] != ToWebTouchPointState(param.pointer_action_type())) { |
| return testing::AssertionFailure() |
| << "Pointer states at index " << index << " was " << states_[index] |
| << ", expected " |
| << ToWebTouchPointState(param.pointer_action_type()) << "."; |
| } |
| return testing::AssertionSuccess(); |
| } |
| |
| testing::AssertionResult SyntheticTouchActionListDispatchedCorrectly( |
| const std::vector<SyntheticPointerActionParams>& params_list, |
| int start_index, |
| int index_array[]) { |
| testing::AssertionResult result = testing::AssertionSuccess(); |
| for (size_t i = 0; i < params_list.size(); ++i) { |
| if (params_list[i].pointer_action_type() != |
| SyntheticPointerActionParams::PointerActionType::IDLE) |
| result = SyntheticTouchActionDispatchedCorrectly( |
| params_list[i], start_index + i, index_array[i]); |
| if (result == testing::AssertionFailure()) |
| return result; |
| } |
| return testing::AssertionSuccess(); |
| } |
| |
| private: |
| std::array<gfx::PointF, kTouchPointersLength> positions_; |
| std::array<int, kTouchPointersLength> indexes_; |
| std::array<WebTouchPoint::State, kTouchPointersLength> states_; |
| }; |
| |
| class MockSyntheticPointerMouseActionTarget |
| : public MockSyntheticPointerActionTarget { |
| public: |
| MockSyntheticPointerMouseActionTarget() {} |
| ~MockSyntheticPointerMouseActionTarget() override {} |
| |
| void DispatchInputEventToPlatform(const WebInputEvent& event) override { |
| MockSyntheticGestureTarget::DispatchInputEventToPlatform(event); |
| ASSERT_TRUE(WebInputEvent::IsMouseEventType(event.GetType())); |
| const WebMouseEvent& mouse_event = static_cast<const WebMouseEvent&>(event); |
| type_ = mouse_event.GetType(); |
| position_ = gfx::PointF(mouse_event.PositionInWidget()); |
| clickCount_ = mouse_event.click_count; |
| button_ = mouse_event.button; |
| num_dispatched_pointer_actions_++; |
| } |
| |
| testing::AssertionResult SyntheticMouseActionDispatchedCorrectly( |
| const SyntheticPointerActionParams& param, |
| int click_count, |
| SyntheticPointerActionParams::Button button = |
| SyntheticPointerActionParams::Button::NO_BUTTON) { |
| if (type_ != ToWebMouseEventType(param.pointer_action_type())) { |
| return testing::AssertionFailure() |
| << "Pointer type was " << WebInputEvent::GetName(type_) |
| << ", expected " << WebInputEvent::GetName(ToWebMouseEventType( |
| param.pointer_action_type())) << "."; |
| } |
| |
| if (clickCount_ != click_count) { |
| return testing::AssertionFailure() << "Pointer click count was " |
| << clickCount_ << ", expected " |
| << click_count << "."; |
| } |
| |
| if (button_ != WebMouseEvent::Button::kNoButton) { |
| if (param.pointer_action_type() == |
| SyntheticPointerActionParams::PointerActionType::PRESS || |
| param.pointer_action_type() == |
| SyntheticPointerActionParams::PointerActionType::RELEASE) { |
| if (clickCount_ != 1) { |
| return testing::AssertionFailure() << "Pointer click count was " |
| << clickCount_ << ", expected 1."; |
| } |
| } |
| |
| if (param.pointer_action_type() == |
| SyntheticPointerActionParams::PointerActionType::MOVE) { |
| if (clickCount_ != 0) { |
| return testing::AssertionFailure() << "Pointer click count was " |
| << clickCount_ << ", expected 0."; |
| } |
| } |
| |
| if (button_ != |
| SyntheticPointerActionParams::GetWebMouseEventButton(button)) { |
| return testing::AssertionFailure() |
| << "Pointer button was " << static_cast<int>(button_) |
| << ", expected " << static_cast<int>(button) << "."; |
| } |
| } |
| |
| if ((param.pointer_action_type() == |
| SyntheticPointerActionParams::PointerActionType::PRESS || |
| param.pointer_action_type() == |
| SyntheticPointerActionParams::PointerActionType::MOVE) && |
| position_ != param.position()) { |
| return testing::AssertionFailure() |
| << "Pointer position was " << position_.ToString() << ", expected " |
| << param.position().ToString() << "."; |
| } |
| return testing::AssertionSuccess(); |
| } |
| |
| private: |
| gfx::PointF position_; |
| int clickCount_; |
| WebMouseEvent::Button button_; |
| }; |
| |
| class DummySyntheticGestureControllerDelegate |
| : public SyntheticGestureController::Delegate { |
| public: |
| DummySyntheticGestureControllerDelegate() = default; |
| |
| DummySyntheticGestureControllerDelegate( |
| const DummySyntheticGestureControllerDelegate&) = delete; |
| DummySyntheticGestureControllerDelegate& operator=( |
| const DummySyntheticGestureControllerDelegate&) = delete; |
| |
| ~DummySyntheticGestureControllerDelegate() override = default; |
| |
| private: |
| // SyntheticGestureController::Delegate: |
| bool HasGestureStopped() override { return true; } |
| bool IsHidden() const override { return false; } |
| }; |
| |
| } // namespace |
| |
| class SyntheticGestureControllerTestBase { |
| public: |
| SyntheticGestureControllerTestBase() {} |
| ~SyntheticGestureControllerTestBase() {} |
| |
| protected: |
| template <typename MockGestureTarget> |
| void CreateControllerAndTarget() { |
| target_ = new MockGestureTarget(); |
| controller_ = std::make_unique<SyntheticGestureController>( |
| &delegate_, std::unique_ptr<SyntheticGestureTarget>(target_), |
| base::SingleThreadTaskRunner::GetCurrentDefault()); |
| } |
| |
| void QueueSyntheticGesture(std::unique_ptr<SyntheticGesture> gesture) { |
| controller_->QueueSyntheticGesture( |
| std::move(gesture), |
| base::BindOnce( |
| &SyntheticGestureControllerTestBase::OnSyntheticGestureCompleted, |
| base::Unretained(this))); |
| } |
| |
| void FlushInputUntilComplete() { |
| // Start the timer explicitly here, since the test does not need to |
| // wait for begin-frame to start the timer. |
| controller_->StartOrUpdateTimer(); |
| do |
| time_ += base::Milliseconds(kFlushInputRateInMs); |
| while (controller_->DispatchNextEvent(time_)); |
| } |
| |
| void OnSyntheticGestureCompleted(SyntheticGesture::Result result) { |
| DCHECK_NE(result, SyntheticGesture::GESTURE_RUNNING); |
| if (result == SyntheticGesture::GESTURE_FINISHED) |
| num_success_++; |
| else |
| num_failure_++; |
| } |
| |
| bool DispatchTimerRunning() const { |
| return controller_->dispatch_timer_.IsRunning(); |
| } |
| |
| base::TimeDelta GetTotalTime() const { return time_ - start_time_; } |
| |
| base::test::TaskEnvironment env_; |
| raw_ptr<MockSyntheticGestureTarget, DanglingUntriaged> target_; |
| DummySyntheticGestureControllerDelegate delegate_; |
| std::unique_ptr<SyntheticGestureController> controller_; |
| base::TimeTicks start_time_; |
| base::TimeTicks time_; |
| int num_success_; |
| int num_failure_; |
| }; |
| |
| class SyntheticGestureControllerTest |
| : public SyntheticGestureControllerTestBase, |
| public testing::Test { |
| protected: |
| void SetUp() override { |
| start_time_ = base::TimeTicks::Now(); |
| time_ = start_time_; |
| num_success_ = 0; |
| num_failure_ = 0; |
| } |
| |
| void TearDown() override { |
| controller_.reset(); |
| target_ = nullptr; |
| time_ = base::TimeTicks(); |
| } |
| }; |
| |
| class SyntheticGestureControllerTestWithParam |
| : public SyntheticGestureControllerTestBase, |
| public testing::TestWithParam<bool> { |
| protected: |
| void SetUp() override { |
| start_time_ = base::TimeTicks::Now(); |
| time_ = start_time_; |
| num_success_ = 0; |
| num_failure_ = 0; |
| } |
| |
| void TearDown() override { |
| controller_.reset(); |
| target_ = nullptr; |
| time_ = base::TimeTicks(); |
| } |
| }; |
| |
| TEST_F(SyntheticGestureControllerTest, SingleGesture) { |
| CreateControllerAndTarget<MockSyntheticGestureTarget>(); |
| |
| bool finished = false; |
| std::unique_ptr<MockSyntheticGesture> gesture( |
| new MockSyntheticGesture(&finished, 3)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, GestureFailed) { |
| CreateControllerAndTarget<MockSyntheticGestureTarget>(); |
| |
| bool finished = false; |
| std::unique_ptr<MockSyntheticGesture> gesture( |
| new MockSyntheticGesture(&finished, 0)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished); |
| EXPECT_EQ(1, num_failure_); |
| EXPECT_EQ(0, num_success_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SuccessiveGestures) { |
| CreateControllerAndTarget<MockSyntheticGestureTarget>(); |
| |
| bool finished_1 = false; |
| std::unique_ptr<MockSyntheticGesture> gesture_1( |
| new MockSyntheticGesture(&finished_1, 2)); |
| bool finished_2 = false; |
| std::unique_ptr<MockSyntheticGesture> gesture_2( |
| new MockSyntheticGesture(&finished_2, 4)); |
| |
| // Queue first gesture and wait for it to finish |
| QueueSyntheticGesture(std::move(gesture_1)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished_1); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| |
| // Queue second gesture. |
| QueueSyntheticGesture(std::move(gesture_2)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished_2); |
| EXPECT_EQ(2, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TwoGesturesInFlight) { |
| CreateControllerAndTarget<MockSyntheticGestureTarget>(); |
| |
| bool finished_1 = false; |
| std::unique_ptr<MockSyntheticGesture> gesture_1( |
| new MockSyntheticGesture(&finished_1, 2)); |
| bool finished_2 = false; |
| std::unique_ptr<MockSyntheticGesture> gesture_2( |
| new MockSyntheticGesture(&finished_2, 4)); |
| |
| QueueSyntheticGesture(std::move(gesture_1)); |
| QueueSyntheticGesture(std::move(gesture_2)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_TRUE(finished_1); |
| EXPECT_TRUE(finished_2); |
| |
| EXPECT_EQ(2, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, GestureCompletedOnDidFlushInput) { |
| CreateControllerAndTarget<MockSyntheticGestureTarget>(); |
| |
| bool finished_1, finished_2; |
| std::unique_ptr<MockSyntheticGesture> gesture_1( |
| new MockSyntheticGesture(&finished_1, 2)); |
| std::unique_ptr<MockSyntheticGesture> gesture_2( |
| new MockSyntheticGesture(&finished_2, 4)); |
| |
| QueueSyntheticGesture(std::move(gesture_1)); |
| QueueSyntheticGesture(std::move(gesture_2)); |
| |
| FlushInputUntilComplete(); |
| EXPECT_EQ(2, num_success_); |
| } |
| |
| gfx::Vector2d AddTouchSlopToVector(const gfx::Vector2dF& 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_P(SyntheticGestureControllerTestWithParam, |
| SingleMoveGestureTouchVertical) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT; |
| if (GetParam() == TOUCH_DRAG) { |
| params.add_slop = false; |
| } |
| params.start_point.SetPoint(89, 32); |
| params.distances.push_back(gfx::Vector2d(0, 123)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| if (GetParam() == TOUCH_SCROLL) { |
| EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_), |
| scroll_target->start_to_end_distance()); |
| } else { |
| EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance()); |
| } |
| } |
| |
| TEST_P(SyntheticGestureControllerTestWithParam, |
| SingleScrollGestureTouchHorizontal) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT; |
| if (GetParam() == TOUCH_DRAG) { |
| params.add_slop = false; |
| } |
| params.start_point.SetPoint(12, -23); |
| params.distances.push_back(gfx::Vector2d(-234, 0)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| if (GetParam() == TOUCH_SCROLL) { |
| EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_), |
| scroll_target->start_to_end_distance()); |
| } else { |
| EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance()); |
| } |
| } |
| |
| void CheckIsWithinRangeSingle(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 CheckSingleScrollDistanceIsWithinRange( |
| const gfx::Vector2dF& scroll_distance, |
| const gfx::Vector2dF& target_distance, |
| SyntheticGestureTarget* target) { |
| CheckIsWithinRangeSingle(scroll_distance.x(), target_distance.x(), target); |
| CheckIsWithinRangeSingle(scroll_distance.y(), target_distance.y(), target); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchDiagonal) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT; |
| params.start_point.SetPoint(0, 7); |
| params.distances.push_back(gfx::Vector2d(413, -83)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| CheckSingleScrollDistanceIsWithinRange( |
| scroll_target->start_to_end_distance(), params.distances[0], target_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchLongStop) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| // 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. |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT; |
| params.start_point.SetPoint(-98, -23); |
| params.distances.push_back(gfx::Vector2d(21, -12)); |
| params.prevent_fling = true; |
| target_->set_pointer_assumed_stopped_time_ms(543); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| CheckSingleScrollDistanceIsWithinRange( |
| scroll_target->start_to_end_distance(), params.distances[0], target_); |
| EXPECT_GE(GetTotalTime(), target_->PointerAssumedStoppedTime()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchFling) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| // 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. |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT; |
| params.start_point.SetPoint(-89, 78); |
| params.distances.push_back(gfx::Vector2d(-43, 19)); |
| params.prevent_fling = false; |
| |
| target_->set_pointer_assumed_stopped_time_ms(543); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| CheckSingleScrollDistanceIsWithinRange( |
| scroll_target->start_to_end_distance(), params.distances[0], target_); |
| EXPECT_LE(GetTotalTime(), target_->PointerAssumedStoppedTime()); |
| } |
| |
| TEST_P(SyntheticGestureControllerTestWithParam, |
| SingleScrollGestureTouchZeroDistance) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT; |
| if (GetParam() == TOUCH_DRAG) { |
| params.add_slop = false; |
| } |
| params.start_point.SetPoint(-32, 43); |
| params.distances.push_back(gfx::Vector2d(0, 0)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(gfx::Vector2dF(0, 0), scroll_target->start_to_end_distance()); |
| } |
| |
| TEST_P(SyntheticGestureControllerTestWithParam, |
| SingleScrollGestureTouchFromDebugger) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.from_devtools_debugger = true; |
| params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT; |
| if (GetParam() == TOUCH_DRAG) { |
| params.add_slop = false; |
| } |
| params.start_point.SetPoint(89, 32); |
| params.distances.push_back(gfx::Vector2d(0, 123)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseVertical) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT; |
| params.start_point.SetPoint(432, 89); |
| params.distances.push_back(gfx::Vector2d(0, -234)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseHorizontal) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT; |
| params.start_point.SetPoint(90, 12); |
| params.distances.push_back(gfx::Vector2d(345, 0)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseDiagonal) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT; |
| params.start_point.SetPoint(90, 12); |
| params.distances.push_back(gfx::Vector2d(-194, 303)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(params.distances[0], scroll_target->start_to_end_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, MultiScrollGestureMouse) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT; |
| params.start_point.SetPoint(90, 12); |
| params.distances.push_back(gfx::Vector2d(-129, 212)); |
| params.distances.push_back(gfx::Vector2d(8, -9)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(params.distances[0] + params.distances[1], |
| scroll_target->start_to_end_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, MultiScrollGestureMouseHorizontal) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT; |
| params.start_point.SetPoint(90, 12); |
| params.distances.push_back(gfx::Vector2d(-129, 0)); |
| params.distances.push_back(gfx::Vector2d(79, 0)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| // This check only works for horizontal or vertical scrolls because of |
| // floating point precision issues with diagonal scrolls. |
| EXPECT_FLOAT_EQ(params.distances[0].Length() + params.distances[1].Length(), |
| scroll_target->total_abs_move_distance_length()); |
| EXPECT_FLOAT_EQ((params.distances[0] + params.distances[1]).x(), |
| scroll_target->start_to_end_distance().x()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchpadSwipe) { |
| CreateControllerAndTarget<MockFlingGestureTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT; |
| params.start_point.SetPoint(39, 86); |
| params.distances.push_back(gfx::Vector2d(0, -132)); |
| params.fling_velocity_x = 800; |
| params.fling_velocity_y = -1000; |
| params.prevent_fling = false; |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockFlingGestureTarget* swipe_target = |
| static_cast<MockFlingGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(params.fling_velocity_x, swipe_target->fling_velocity_x()); |
| EXPECT_EQ(params.fling_velocity_y, swipe_target->fling_velocity_y()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMousePreciseScroll) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT; |
| params.start_point.SetPoint(39, 86); |
| params.distances.push_back(gfx::Vector2d(0, -132)); |
| params.granularity = ui::ScrollGranularity::kScrollByPrecisePixel; |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(params.granularity, scroll_target->granularity()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseScrollByPage) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT; |
| params.start_point.SetPoint(39, 86); |
| params.distances.push_back(gfx::Vector2d(0, -132)); |
| params.granularity = ui::ScrollGranularity::kScrollByPage; |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(params.granularity, scroll_target->granularity()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseFromDebugger) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.from_devtools_debugger = true; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT; |
| params.start_point.SetPoint(432, 89); |
| params.distances.push_back(gfx::Vector2d(0, -234)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| void CheckIsWithinRangeMulti(float scroll_distance, |
| int target_distance, |
| SyntheticGestureTarget* target) { |
| if (target_distance > 0) { |
| EXPECT_GE(scroll_distance, target_distance - target->GetTouchSlopInDips()); |
| EXPECT_LE(scroll_distance, target_distance + target->GetTouchSlopInDips()); |
| } else { |
| EXPECT_LE(scroll_distance, target_distance + target->GetTouchSlopInDips()); |
| EXPECT_GE(scroll_distance, target_distance - target->GetTouchSlopInDips()); |
| } |
| } |
| |
| void CheckMultiScrollDistanceIsWithinRange( |
| const gfx::Vector2dF& scroll_distance, |
| const gfx::Vector2dF& target_distance, |
| SyntheticGestureTarget* target) { |
| CheckIsWithinRangeMulti(scroll_distance.x(), target_distance.x(), target); |
| CheckIsWithinRangeMulti(scroll_distance.y(), target_distance.y(), target); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, MultiScrollGestureTouch) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT; |
| params.start_point.SetPoint(8, -13); |
| params.distances.push_back(gfx::Vector2d(234, 133)); |
| params.distances.push_back(gfx::Vector2d(-9, 78)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| CheckMultiScrollDistanceIsWithinRange( |
| scroll_target->start_to_end_distance(), |
| params.distances[0] + params.distances[1], |
| target_); |
| } |
| |
| TEST_P(SyntheticGestureControllerTestWithParam, |
| MultiScrollGestureTouchVertical) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::TOUCH_INPUT; |
| if (GetParam() == TOUCH_DRAG) { |
| params.add_slop = false; |
| } |
| params.start_point.SetPoint(234, -13); |
| params.distances.push_back(gfx::Vector2d(0, 133)); |
| params.distances.push_back(gfx::Vector2d(0, 78)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* scroll_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| if (GetParam() == TOUCH_SCROLL) { |
| EXPECT_FLOAT_EQ(params.distances[0].Length() + |
| params.distances[1].Length() + |
| target_->GetTouchSlopInDips(), |
| scroll_target->total_abs_move_distance_length()); |
| EXPECT_EQ(AddTouchSlopToVector(params.distances[0] + params.distances[1], |
| target_), |
| scroll_target->start_to_end_distance()); |
| } else { |
| EXPECT_FLOAT_EQ(params.distances[0].Length() + params.distances[1].Length(), |
| scroll_target->total_abs_move_distance_length()); |
| EXPECT_EQ(params.distances[0] + params.distances[1], |
| scroll_target->start_to_end_distance()); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(Single, |
| SyntheticGestureControllerTestWithParam, |
| testing::Values(TOUCH_SCROLL, TOUCH_DRAG)); |
| |
| TEST_F(SyntheticGestureControllerTest, SingleDragGestureMouseDiagonal) { |
| CreateControllerAndTarget<MockDragMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT; |
| params.start_point.SetPoint(0, 7); |
| params.distances.push_back(gfx::Vector2d(413, -83)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* drag_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(drag_target->start_to_end_distance(), params.distances[0]); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, SingleDragGestureMouseZeroDistance) { |
| CreateControllerAndTarget<MockDragMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT; |
| params.start_point.SetPoint(-32, 43); |
| params.distances.push_back(gfx::Vector2d(0, 0)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* drag_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(gfx::Vector2dF(0, 0), drag_target->start_to_end_distance()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, MultiDragGestureMouse) { |
| CreateControllerAndTarget<MockDragMouseTarget>(); |
| |
| SyntheticSmoothMoveGestureParams params; |
| params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT; |
| params.start_point.SetPoint(8, -13); |
| params.distances.push_back(gfx::Vector2d(234, 133)); |
| params.distances.push_back(gfx::Vector2d(-9, 78)); |
| |
| std::unique_ptr<SyntheticSmoothMoveGesture> gesture( |
| new SyntheticSmoothMoveGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockMoveGestureTarget* drag_target = |
| static_cast<MockMoveGestureTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(drag_target->start_to_end_distance(), |
| params.distances[0] + params.distances[1]); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| SyntheticSmoothDragTestUsingSingleMouseDrag) { |
| CreateControllerAndTarget<MockDragMouseTarget>(); |
| |
| SyntheticSmoothDragGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.distances.push_back(gfx::Vector2d(234, 133)); |
| params.speed_in_pixels_s = 800; |
| |
| std::unique_ptr<SyntheticSmoothDragGesture> gesture( |
| new SyntheticSmoothDragGesture(params)); |
| gesture->DidQueue(controller_->GetWeakPtr()); |
| const base::TimeTicks timestamp; |
| gesture->ForwardInputEvents(timestamp, target_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| SyntheticSmoothDragTestUsingSingleMouseDragFromDebugger) { |
| CreateControllerAndTarget<MockDragMouseTarget>(); |
| |
| SyntheticSmoothDragGestureParams params; |
| params.from_devtools_debugger = true; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.distances.push_back(gfx::Vector2d(234, 133)); |
| params.speed_in_pixels_s = 800; |
| |
| std::unique_ptr<SyntheticSmoothDragGesture> gesture( |
| new SyntheticSmoothDragGesture(params)); |
| gesture->DidQueue(controller_->GetWeakPtr()); |
| const base::TimeTicks timestamp; |
| gesture->ForwardInputEvents(timestamp, target_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| SyntheticSmoothDragTestUsingSingleTouchDrag) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothDragGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.start_point.SetPoint(89, 32); |
| params.distances.push_back(gfx::Vector2d(0, 123)); |
| params.speed_in_pixels_s = 800; |
| |
| std::unique_ptr<SyntheticSmoothDragGesture> gesture( |
| new SyntheticSmoothDragGesture(params)); |
| gesture->DidQueue(controller_->GetWeakPtr()); |
| const base::TimeTicks timestamp; |
| gesture->ForwardInputEvents(timestamp, target_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| SyntheticSmoothDragTestUsingSingleTouchDragFromDebugger) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothDragGestureParams params; |
| params.from_devtools_debugger = true; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.start_point.SetPoint(89, 32); |
| params.distances.push_back(gfx::Vector2d(0, 123)); |
| params.speed_in_pixels_s = 800; |
| |
| std::unique_ptr<SyntheticSmoothDragGesture> gesture( |
| new SyntheticSmoothDragGesture(params)); |
| gesture->DidQueue(controller_->GetWeakPtr()); |
| const base::TimeTicks timestamp; |
| gesture->ForwardInputEvents(timestamp, target_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| SyntheticSmoothScrollTestUsingSingleTouchScroll) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| |
| std::unique_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| gesture->DidQueue(controller_->GetWeakPtr()); |
| const base::TimeTicks timestamp; |
| gesture->ForwardInputEvents(timestamp, target_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| SyntheticSmoothScrollTestUsingSingleTouchScrollFromDebugger) { |
| CreateControllerAndTarget<MockMoveTouchTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.from_devtools_debugger = true; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.anchor.SetPoint(432, 89); |
| params.distances.push_back(gfx::Vector2d(0, -234)); |
| params.speed_in_pixels_s = 800; |
| |
| std::unique_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| SyntheticSmoothScrollTestUsingSingleMouseScroll) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.anchor.SetPoint(432, 89); |
| params.distances.push_back(gfx::Vector2d(0, -234)); |
| params.speed_in_pixels_s = 800; |
| |
| std::unique_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| gesture->DidQueue(controller_->GetWeakPtr()); |
| const base::TimeTicks timestamp; |
| gesture->ForwardInputEvents(timestamp, target_); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| SyntheticSmoothScrollTestUsingSingleMouseScrollFromDebugger) { |
| CreateControllerAndTarget<MockScrollMouseTarget>(); |
| |
| SyntheticSmoothScrollGestureParams params; |
| params.from_devtools_debugger = true; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.anchor.SetPoint(432, 89); |
| params.distances.push_back(gfx::Vector2d(0, -234)); |
| params.speed_in_pixels_s = 800; |
| |
| std::unique_ptr<SyntheticSmoothScrollGesture> gesture( |
| new SyntheticSmoothScrollGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| TouchscreenTouchpadPinchGestureTouchZoomIn) { |
| CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.scale_factor = 2.3f; |
| params.anchor.SetPoint(54, 89); |
| |
| std::unique_ptr<SyntheticTouchscreenPinchGesture> gesture( |
| new SyntheticTouchscreenPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTouchscreenPinchTouchTarget* pinch_target = |
| static_cast<MockSyntheticTouchscreenPinchTouchTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pinch_target->zoom_direction(), |
| MockSyntheticTouchscreenPinchTouchTarget::ZOOM_IN); |
| EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->ComputeScaleFactor()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| TouchscreenTouchpadPinchGestureTouchZoomOut) { |
| CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.scale_factor = 0.4f; |
| params.anchor.SetPoint(-12, 93); |
| |
| std::unique_ptr<SyntheticTouchscreenPinchGesture> gesture( |
| new SyntheticTouchscreenPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTouchscreenPinchTouchTarget* pinch_target = |
| static_cast<MockSyntheticTouchscreenPinchTouchTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pinch_target->zoom_direction(), |
| MockSyntheticTouchscreenPinchTouchTarget::ZOOM_OUT); |
| EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->ComputeScaleFactor()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| TouchscreenTouchpadPinchGestureTouchNoScaling) { |
| CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.scale_factor = 1.0f; |
| |
| std::unique_ptr<SyntheticTouchscreenPinchGesture> gesture( |
| new SyntheticTouchscreenPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTouchscreenPinchTouchTarget* pinch_target = |
| static_cast<MockSyntheticTouchscreenPinchTouchTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pinch_target->zoom_direction(), |
| MockSyntheticTouchscreenPinchTouchTarget::ZOOM_DIRECTION_UNKNOWN); |
| EXPECT_EQ(params.scale_factor, pinch_target->ComputeScaleFactor()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, |
| TouchscreenTouchpadPinchGestureTouchFromDebugger) { |
| CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.from_devtools_debugger = true; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.scale_factor = 2.3f; |
| params.anchor.SetPoint(54, 89); |
| |
| std::unique_ptr<SyntheticTouchscreenPinchGesture> gesture( |
| new SyntheticTouchscreenPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TouchpadPinchGestureTouchZoomIn) { |
| CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.scale_factor = 2.3f; |
| params.anchor.SetPoint(54, 89); |
| |
| std::unique_ptr<SyntheticTouchpadPinchGesture> gesture( |
| new SyntheticTouchpadPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTouchpadPinchTouchTarget* pinch_target = |
| static_cast<MockSyntheticTouchpadPinchTouchTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pinch_target->zoom_direction(), |
| MockSyntheticTouchpadPinchTouchTarget::ZOOM_IN); |
| EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->scale_factor()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TouchpadPinchGestureTouchZoomOut) { |
| CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.scale_factor = 0.4f; |
| params.anchor.SetPoint(-12, 93); |
| |
| std::unique_ptr<SyntheticTouchpadPinchGesture> gesture( |
| new SyntheticTouchpadPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTouchpadPinchTouchTarget* pinch_target = |
| static_cast<MockSyntheticTouchpadPinchTouchTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pinch_target->zoom_direction(), |
| MockSyntheticTouchpadPinchTouchTarget::ZOOM_OUT); |
| EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->scale_factor()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TouchpadPinchGestureTouchNoScaling) { |
| CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.scale_factor = 1.0f; |
| |
| std::unique_ptr<SyntheticTouchpadPinchGesture> gesture( |
| new SyntheticTouchpadPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTouchpadPinchTouchTarget* pinch_target = |
| static_cast<MockSyntheticTouchpadPinchTouchTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pinch_target->zoom_direction(), |
| MockSyntheticTouchpadPinchTouchTarget::ZOOM_DIRECTION_UNKNOWN); |
| EXPECT_EQ(params.scale_factor, pinch_target->scale_factor()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TouchpadPinchGestureTouchFromDebugger) { |
| CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.from_devtools_debugger = true; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.scale_factor = 2.3f; |
| params.anchor.SetPoint(54, 89); |
| |
| std::unique_ptr<SyntheticTouchpadPinchGesture> gesture( |
| new SyntheticTouchpadPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| // Ensure that if SyntheticPinchGesture is instantiated with TOUCH_INPUT it |
| // correctly creates a touchscreen gesture. |
| TEST_F(SyntheticGestureControllerTest, PinchGestureExplicitTouch) { |
| CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.scale_factor = 2.3f; |
| params.anchor.SetPoint(54, 89); |
| |
| std::unique_ptr<SyntheticPinchGesture> gesture( |
| new SyntheticPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| // Gesture target will fail expectations if the wrong underlying |
| // SyntheticPinch*Gesture was instantiated. |
| } |
| |
| // Ensure that if SyntheticPinchGesture is instantiated with MOUSE_INPUT it |
| // correctly creates a touchpad gesture. |
| TEST_F(SyntheticGestureControllerTest, PinchGestureExplicitMouse) { |
| CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.scale_factor = 2.3f; |
| params.anchor.SetPoint(54, 89); |
| |
| std::unique_ptr<SyntheticPinchGesture> gesture( |
| new SyntheticPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| // Gesture target will fail expectations if the wrong underlying |
| // SyntheticPinch*Gesture was instantiated. |
| } |
| |
| // Ensure that if SyntheticPinchGesture is instantiated with DEFAULT_INPUT it |
| // correctly creates a touchscreen gesture for a touchscreen controller. |
| TEST_F(SyntheticGestureControllerTest, PinchGestureDefaultTouch) { |
| CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kDefaultInput; |
| params.scale_factor = 2.3f; |
| params.anchor.SetPoint(54, 89); |
| |
| std::unique_ptr<SyntheticPinchGesture> gesture( |
| new SyntheticPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| // Gesture target will fail expectations if the wrong underlying |
| // SyntheticPinch*Gesture was instantiated. |
| } |
| |
| // Ensure that if SyntheticPinchGesture is instantiated with DEFAULT_INPUT it |
| // correctly creates a touchpad gesture for a touchpad controller. |
| TEST_F(SyntheticGestureControllerTest, PinchGestureDefaultMouse) { |
| CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>(); |
| |
| SyntheticPinchGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kDefaultInput; |
| params.scale_factor = 2.3f; |
| params.anchor.SetPoint(54, 89); |
| |
| std::unique_ptr<SyntheticPinchGesture> gesture( |
| new SyntheticPinchGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| // Gesture target will fail expectations if the wrong underlying |
| // SyntheticPinch*Gesture was instantiated. |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TapGestureTouch) { |
| CreateControllerAndTarget<MockSyntheticTapTouchTarget>(); |
| |
| SyntheticTapGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.duration_ms = 123; |
| params.position.SetPoint(87, -124); |
| |
| std::unique_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTapTouchTarget* tap_target = |
| static_cast<MockSyntheticTapTouchTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(tap_target->GestureFinished()); |
| EXPECT_EQ(tap_target->position(), params.position); |
| EXPECT_EQ(tap_target->GetDuration().InMilliseconds(), params.duration_ms); |
| EXPECT_GE(GetTotalTime(), base::Milliseconds(params.duration_ms)); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TapGestureTouchFromDebugger) { |
| CreateControllerAndTarget<MockSyntheticTapTouchTarget>(); |
| |
| SyntheticTapGestureParams params; |
| params.from_devtools_debugger = true; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.duration_ms = 123; |
| params.position.SetPoint(87, -124); |
| |
| std::unique_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TapGestureMouse) { |
| CreateControllerAndTarget<MockSyntheticTapMouseTarget>(); |
| |
| SyntheticTapGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.duration_ms = 79; |
| params.position.SetPoint(98, 123); |
| |
| std::unique_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticTapMouseTarget* tap_target = |
| static_cast<MockSyntheticTapMouseTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(tap_target->GestureFinished()); |
| EXPECT_EQ(tap_target->position(), params.position); |
| EXPECT_EQ(tap_target->GetDuration().InMilliseconds(), params.duration_ms); |
| EXPECT_GE(GetTotalTime(), base::Milliseconds(params.duration_ms)); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, TapGestureMouseFromDebugger) { |
| CreateControllerAndTarget<MockSyntheticTapMouseTarget>(); |
| |
| SyntheticTapGestureParams params; |
| params.from_devtools_debugger = true; |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| params.duration_ms = 79; |
| params.position.SetPoint(98, 123); |
| |
| std::unique_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_TRUE(target_->all_from_debugger()); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, PointerTouchAction) { |
| CreateControllerAndTarget<MockSyntheticPointerTouchActionTarget>(); |
| |
| // First, send two touch presses for finger 0 and finger 1. |
| SyntheticPointerActionListParams::ParamList param_list; |
| SyntheticPointerActionParams param0 = SyntheticPointerActionParams( |
| SyntheticPointerActionParams::PointerActionType::PRESS); |
| SyntheticPointerActionParams param1 = SyntheticPointerActionParams( |
| SyntheticPointerActionParams::PointerActionType::PRESS); |
| param0.set_position(gfx::PointF(54, 89)); |
| param0.set_pointer_id(0); |
| param1.set_position(gfx::PointF(79, 132)); |
| param1.set_pointer_id(1); |
| param_list.push_back(param0); |
| param_list.push_back(param1); |
| SyntheticPointerActionListParams params(param_list); |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| std::unique_ptr<SyntheticPointerAction> gesture( |
| new SyntheticPointerAction(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticPointerTouchActionTarget* pointer_touch_target = |
| static_cast<MockSyntheticPointerTouchActionTarget*>(target_); |
| int index_array[2] = {0, 1}; |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_touch_target->num_dispatched_pointer_actions(), 2); |
| EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly( |
| param_list, 0, index_array)); |
| |
| // Second, send a touch release for finger 0, a touch move for finger 1. |
| param0.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::RELEASE); |
| param1.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::MOVE); |
| param1.set_position(gfx::PointF(183, 239)); |
| param_list.clear(); |
| param_list.push_back(param0); |
| param_list.push_back(param1); |
| params.PushPointerActionParamsList(param_list); |
| gesture = std::make_unique<SyntheticPointerAction>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| pointer_touch_target->reset_num_dispatched_pointer_actions(); |
| FlushInputUntilComplete(); |
| |
| index_array[1] = 0; |
| EXPECT_EQ(2, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_touch_target->num_dispatched_pointer_actions(), 4); |
| EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly( |
| param_list, 2, index_array)); |
| |
| // Third, send a touch release for finger 1. |
| param1.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::RELEASE); |
| param_list.clear(); |
| param_list.push_back(param1); |
| params.PushPointerActionParamsList(param_list); |
| gesture = std::make_unique<SyntheticPointerAction>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| pointer_touch_target->reset_num_dispatched_pointer_actions(); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(3, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_touch_target->num_dispatched_pointer_actions(), 5); |
| EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly( |
| param_list, 4, index_array)); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, PointerMouseAction) { |
| CreateControllerAndTarget<MockSyntheticPointerMouseActionTarget>(); |
| |
| // First, send a mouse move. |
| SyntheticPointerActionListParams::ParamList param_list; |
| SyntheticPointerActionParams param = SyntheticPointerActionParams( |
| SyntheticPointerActionParams::PointerActionType::MOVE); |
| |
| param.set_position(gfx::PointF(54, 89)); |
| SyntheticPointerActionListParams params; |
| params.PushPointerActionParams(param); |
| params.gesture_source_type = content::mojom::GestureSourceType::kMouseInput; |
| std::unique_ptr<SyntheticPointerAction> gesture( |
| new SyntheticPointerAction(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticPointerMouseActionTarget* pointer_mouse_target = |
| static_cast<MockSyntheticPointerMouseActionTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_mouse_target->num_dispatched_pointer_actions(), 1); |
| EXPECT_TRUE( |
| pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly(param, 0)); |
| |
| // Second, send a mouse press. |
| param.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::PRESS); |
| param.set_position(gfx::PointF(183, 239)); |
| param.set_button(SyntheticPointerActionParams::Button::LEFT); |
| params.PushPointerActionParams(param); |
| gesture = std::make_unique<SyntheticPointerAction>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| pointer_mouse_target->reset_num_dispatched_pointer_actions(); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(2, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_mouse_target->num_dispatched_pointer_actions(), 2); |
| EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( |
| param, 1, SyntheticPointerActionParams::Button::LEFT)); |
| |
| // Third, send a mouse move. |
| param.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::MOVE); |
| param.set_position(gfx::PointF(254, 279)); |
| params.PushPointerActionParams(param); |
| gesture = std::make_unique<SyntheticPointerAction>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| pointer_mouse_target->reset_num_dispatched_pointer_actions(); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(3, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_mouse_target->num_dispatched_pointer_actions(), 3); |
| EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( |
| param, 0, SyntheticPointerActionParams::Button::LEFT)); |
| |
| // Fourth, send a mouse release. |
| param.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::RELEASE); |
| params.PushPointerActionParams(param); |
| gesture = std::make_unique<SyntheticPointerAction>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| pointer_mouse_target->reset_num_dispatched_pointer_actions(); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(4, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_mouse_target->num_dispatched_pointer_actions(), 4); |
| EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( |
| param, 1, SyntheticPointerActionParams::Button::LEFT)); |
| } |
| |
| TEST_F(SyntheticGestureControllerTest, PointerPenAction) { |
| CreateControllerAndTarget<MockSyntheticPointerMouseActionTarget>(); |
| |
| // First, send a pen move. |
| SyntheticPointerActionListParams::ParamList param_list; |
| SyntheticPointerActionParams param = SyntheticPointerActionParams( |
| SyntheticPointerActionParams::PointerActionType::MOVE); |
| |
| param.set_position(gfx::PointF(54, 89)); |
| SyntheticPointerActionListParams params; |
| params.PushPointerActionParams(param); |
| params.gesture_source_type = content::mojom::GestureSourceType::kPenInput; |
| std::unique_ptr<SyntheticPointerAction> gesture( |
| new SyntheticPointerAction(params)); |
| QueueSyntheticGesture(std::move(gesture)); |
| FlushInputUntilComplete(); |
| |
| MockSyntheticPointerMouseActionTarget* pointer_pen_target = |
| static_cast<MockSyntheticPointerMouseActionTarget*>(target_); |
| EXPECT_EQ(1, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 1); |
| EXPECT_TRUE( |
| pointer_pen_target->SyntheticMouseActionDispatchedCorrectly(param, 0)); |
| |
| // Second, send a pen press. |
| param.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::PRESS); |
| param.set_button(SyntheticPointerActionParams::Button::LEFT); |
| param.set_position(gfx::PointF(183, 239)); |
| params.PushPointerActionParams(param); |
| gesture = std::make_unique<SyntheticPointerAction>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| pointer_pen_target->reset_num_dispatched_pointer_actions(); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(2, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 2); |
| EXPECT_TRUE(pointer_pen_target->SyntheticMouseActionDispatchedCorrectly( |
| param, 1, SyntheticPointerActionParams::Button::LEFT)); |
| |
| // Third, send a pen move. |
| param.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::MOVE); |
| param.set_position(gfx::PointF(254, 279)); |
| params.PushPointerActionParams(param); |
| gesture = std::make_unique<SyntheticPointerAction>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| pointer_pen_target->reset_num_dispatched_pointer_actions(); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(3, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 3); |
| EXPECT_TRUE(pointer_pen_target->SyntheticMouseActionDispatchedCorrectly( |
| param, 0, SyntheticPointerActionParams::Button::LEFT)); |
| |
| // Fourth, send a pen release. |
| param.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::RELEASE); |
| params.PushPointerActionParams(param); |
| gesture = std::make_unique<SyntheticPointerAction>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| pointer_pen_target->reset_num_dispatched_pointer_actions(); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(4, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 4); |
| EXPECT_TRUE(pointer_pen_target->SyntheticMouseActionDispatchedCorrectly( |
| param, 1, SyntheticPointerActionParams::Button::LEFT)); |
| |
| // Fifth, send a pen leave. |
| param.set_pointer_action_type( |
| SyntheticPointerActionParams::PointerActionType::LEAVE); |
| params.PushPointerActionParams(param); |
| gesture = std::make_unique<SyntheticPointerAction>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| pointer_pen_target->reset_num_dispatched_pointer_actions(); |
| FlushInputUntilComplete(); |
| |
| EXPECT_EQ(5, num_success_); |
| EXPECT_EQ(0, num_failure_); |
| EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 5); |
| EXPECT_TRUE( |
| pointer_pen_target->SyntheticMouseActionDispatchedCorrectly(param, 0)); |
| } |
| |
| class MockSyntheticGestureTargetManualAck : public MockSyntheticGestureTarget { |
| public: |
| void WaitForTargetAck(SyntheticGestureParams::GestureType type, |
| content::mojom::GestureSourceType source, |
| base::OnceClosure callback) const override { |
| if (manually_ack_) |
| target_ack_ = std::move(callback); |
| else |
| std::move(callback).Run(); |
| } |
| bool HasOutstandingAck() const { return !target_ack_.is_null(); } |
| void InvokeAck() { |
| DCHECK(HasOutstandingAck()); |
| std::move(target_ack_).Run(); |
| } |
| void SetManuallyAck(bool manually_ack) { manually_ack_ = manually_ack; } |
| |
| private: |
| mutable base::OnceClosure target_ack_; |
| bool manually_ack_ = true; |
| }; |
| |
| // Ensure the first time a gesture is queued, we wait for a renderer ACK before |
| // starting the gesture. Following gestures should start immediately. This test |
| // the renderer_known_to_be_initialized_ bit in the controller. |
| TEST_F(SyntheticGestureControllerTest, WaitForRendererInitialization) { |
| CreateControllerAndTarget<MockSyntheticGestureTargetManualAck>(); |
| |
| auto* target = static_cast<MockSyntheticGestureTargetManualAck*>(target_); |
| |
| EXPECT_FALSE(target->HasOutstandingAck()); |
| |
| SyntheticTapGestureParams params; |
| params.gesture_source_type = content::mojom::GestureSourceType::kTouchInput; |
| params.duration_ms = 123; |
| params.position.SetPoint(87, -124); |
| |
| // Queue the first gesture. |
| { |
| auto gesture = std::make_unique<SyntheticTapGesture>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| |
| // We should have received a WaitForTargetAck and the dispatch timer won't |
| // start until that's ACK'd. |
| EXPECT_TRUE(target->HasOutstandingAck()); |
| EXPECT_FALSE(DispatchTimerRunning()); |
| |
| target->InvokeAck(); |
| |
| // The timer should now be running. |
| EXPECT_FALSE(target->HasOutstandingAck()); |
| EXPECT_TRUE(DispatchTimerRunning()); |
| } |
| |
| // Finish the gesture. |
| { |
| target->SetManuallyAck(false); |
| FlushInputUntilComplete(); |
| target->SetManuallyAck(true); |
| EXPECT_FALSE(DispatchTimerRunning()); |
| } |
| |
| // Queue the second gesture. |
| { |
| auto gesture = std::make_unique<SyntheticTapGesture>(params); |
| QueueSyntheticGesture(std::move(gesture)); |
| |
| // This time, because we've already sent a gesuture to the renderer, |
| // there's no need to wait for an ACK before starting the dispatch timer. |
| EXPECT_FALSE(target->HasOutstandingAck()); |
| EXPECT_TRUE(DispatchTimerRunning()); |
| } |
| } |
| |
| } // namespace content |