diff options
author | christiank <christiank@opera.com> | 2014-11-05 02:49:14 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-05 10:49:31 +0000 |
commit | aeed9866ec8ef2172404784edeebc85aaafbf330 (patch) | |
tree | 5118b0b317a4d0f4fb1524a7794d32106fc1fcd8 | |
parent | 61cb84971f5f21eb83b7e3b3ac43364aafb9b2d4 (diff) | |
download | chromium_src-aeed9866ec8ef2172404784edeebc85aaafbf330.zip chromium_src-aeed9866ec8ef2172404784edeebc85aaafbf330.tar.gz chromium_src-aeed9866ec8ef2172404784edeebc85aaafbf330.tar.bz2 |
Update touch selection to only modify one selection point at a time.
This is made in preparation for enabling selection auto scroll using touch
handles.
BUG=340658
Review URL: https://codereview.chromium.org/657803002
Cr-Commit-Position: refs/heads/master@{#302776}
18 files changed, 468 insertions, 67 deletions
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index 18528b6..9aa69cd 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc @@ -770,17 +770,24 @@ void ContentViewCoreImpl::RemoveLayer(scoped_refptr<cc::Layer> layer) { root_layer_->SetIsDrawable(true); } -void ContentViewCoreImpl::SelectBetweenCoordinates(const gfx::PointF& start, - const gfx::PointF& end) { +void ContentViewCoreImpl::MoveRangeSelectionExtent(const gfx::PointF& extent) { if (!web_contents_) return; - gfx::Point start_point = gfx::Point(start.x(), start.y()); - gfx::Point end_point = gfx::Point(end.x(), end.y()); - if (start_point == end_point) + web_contents_->MoveRangeSelectionExtent(gfx::Point(extent.x(), extent.y())); +} + +void ContentViewCoreImpl::SelectBetweenCoordinates(const gfx::PointF& base, + const gfx::PointF& extent) { + if (!web_contents_) + return; + + gfx::Point base_point = gfx::Point(base.x(), base.y()); + gfx::Point extent_point = gfx::Point(extent.x(), extent.y()); + if (base_point == extent_point) return; - web_contents_->SelectRange(start_point, end_point); + web_contents_->SelectRange(base_point, extent_point); } ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const { diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index b9ff454..6e90696 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h @@ -270,8 +270,10 @@ class ContentViewCoreImpl : public ContentViewCore, void AttachLayer(scoped_refptr<cc::Layer> layer); void RemoveLayer(scoped_refptr<cc::Layer> layer); - void SelectBetweenCoordinates(const gfx::PointF& start, - const gfx::PointF& end); + void MoveRangeSelectionExtent(const gfx::PointF& extent); + + void SelectBetweenCoordinates(const gfx::PointF& base, + const gfx::PointF& extent); private: class ContentViewUserData; diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc index 364f7ca..4848f6d 100644 --- a/content/browser/renderer_host/input/input_router_impl.cc +++ b/content/browser/renderer_host/input/input_router_impl.cc @@ -68,7 +68,7 @@ InputRouterImpl::InputRouterImpl(IPC::Sender* sender, client_(client), ack_handler_(ack_handler), routing_id_(routing_id), - select_range_pending_(false), + select_message_pending_(false), move_caret_pending_(false), mouse_move_pending_(false), mouse_wheel_pending_(false), @@ -83,7 +83,9 @@ InputRouterImpl::InputRouterImpl(IPC::Sender* sender, UpdateTouchAckTimeoutEnabled(); } -InputRouterImpl::~InputRouterImpl() {} +InputRouterImpl::~InputRouterImpl() { + STLDeleteElements(&pending_select_messages_); +} void InputRouterImpl::Flush() { flush_requested_ = true; @@ -95,7 +97,8 @@ bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) { switch (message->type()) { // Check for types that require an ACK. case InputMsg_SelectRange::ID: - return SendSelectRange(message.Pass()); + case InputMsg_MoveRangeSelectionExtent::ID: + return SendSelectMessage(message.Pass()); case InputMsg_MoveCaret::ID: return SendMoveCaret(message.Pass()); case InputMsg_HandleInputEvent::ID: @@ -267,8 +270,10 @@ bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(InputRouterImpl, message) IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck) IPC_MESSAGE_HANDLER(InputHostMsg_DidOverscroll, OnDidOverscroll) - IPC_MESSAGE_HANDLER(ViewHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck) - IPC_MESSAGE_HANDLER(ViewHostMsg_SelectRange_ACK, OnSelectRangeAck) + IPC_MESSAGE_HANDLER(InputHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck) + IPC_MESSAGE_HANDLER(InputHostMsg_SelectRange_ACK, OnSelectMessageAck) + IPC_MESSAGE_HANDLER(InputHostMsg_MoveRangeSelectionExtent_ACK, + OnSelectMessageAck) IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers, OnHasTouchEventHandlers) IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction, @@ -298,14 +303,25 @@ void InputRouterImpl::OnGestureEventAck( ack_handler_->OnGestureEventAck(event, ack_result); } -bool InputRouterImpl::SendSelectRange(scoped_ptr<IPC::Message> message) { - DCHECK(message->type() == InputMsg_SelectRange::ID); - if (select_range_pending_) { - next_selection_range_ = message.Pass(); +bool InputRouterImpl::SendSelectMessage( + scoped_ptr<IPC::Message> message) { + DCHECK(message->type() == InputMsg_SelectRange::ID || + message->type() == InputMsg_MoveRangeSelectionExtent::ID); + + // TODO(jdduke): Factor out common logic between selection and caret-related + // IPC messages. + if (select_message_pending_) { + if (!pending_select_messages_.empty() && + pending_select_messages_.back()->type() == message->type()) { + delete pending_select_messages_.back(); + pending_select_messages_.pop_back(); + } + + pending_select_messages_.push_back(message.release()); return true; } - select_range_pending_ = true; + select_message_pending_ = true; return Send(message.release()); } @@ -487,10 +503,15 @@ void InputRouterImpl::OnMsgMoveCaretAck() { SendMoveCaret(next_move_caret_.Pass()); } -void InputRouterImpl::OnSelectRangeAck() { - select_range_pending_ = false; - if (next_selection_range_) - SendSelectRange(next_selection_range_.Pass()); +void InputRouterImpl::OnSelectMessageAck() { + select_message_pending_ = false; + if (!pending_select_messages_.empty()) { + scoped_ptr<IPC::Message> next_message = + make_scoped_ptr(pending_select_messages_.front()); + pending_select_messages_.pop_front(); + + SendSelectMessage(next_message.Pass()); + } } void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers) { @@ -679,7 +700,7 @@ bool InputRouterImpl::HasPendingEvents() const { !key_queue_.empty() || mouse_move_pending_ || mouse_wheel_pending_ || - select_range_pending_ || + select_message_pending_ || move_caret_pending_; } diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h index b08c1e3..2b00c12 100644 --- a/content/browser/renderer_host/input/input_router_impl.h +++ b/content/browser/renderer_host/input/input_router_impl.h @@ -95,7 +95,7 @@ private: InputEventAckState ack_result) override; bool SendMoveCaret(scoped_ptr<IPC::Message> message); - bool SendSelectRange(scoped_ptr<IPC::Message> message); + bool SendSelectMessage(scoped_ptr<IPC::Message> message); bool Send(IPC::Message* message); // Filters and forwards |input_event| to the appropriate handler. @@ -148,7 +148,7 @@ private: void OnInputEventAck(const InputHostMsg_HandleInputEvent_ACK_Params& ack); void OnDidOverscroll(const DidOverscrollParams& params); void OnMsgMoveCaretAck(); - void OnSelectRangeAck(); + void OnSelectMessageAck(); void OnHasTouchEventHandlers(bool has_handlers); void OnSetTouchAction(TouchAction touch_action); @@ -212,11 +212,13 @@ private: InputAckHandler* ack_handler_; int routing_id_; - // (Similar to |mouse_move_pending_|.) True while waiting for SelectRange_ACK. - bool select_range_pending_; + // (Similar to |mouse_move_pending_|.) True while waiting for SelectRange_ACK + // or MoveRangeSelectionExtent_ACK. + bool select_message_pending_; - // (Similar to |next_mouse_move_|.) The next SelectRange to send, if any. - scoped_ptr<IPC::Message> next_selection_range_; + // Queue of pending select messages to send after receving the next select + // message ack. + std::deque<IPC::Message*> pending_select_messages_; // (Similar to |mouse_move_pending_|.) True while waiting for MoveCaret_ACK. bool move_caret_pending_; diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc index 5b3d7d7..ed922c9d 100644 --- a/content/browser/renderer_host/input/input_router_impl_unittest.cc +++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc @@ -354,7 +354,7 @@ TEST_F(InputRouterImplTest, CoalescesRangeSelection) { // Now ack the first message. { - scoped_ptr<IPC::Message> response(new ViewHostMsg_SelectRange_ACK(0)); + scoped_ptr<IPC::Message> response(new InputHostMsg_SelectRange_ACK(0)); input_router_->OnMessageReceived(*response); } @@ -367,7 +367,197 @@ TEST_F(InputRouterImplTest, CoalescesRangeSelection) { // Acking the coalesced msg should not send any more msg. { - scoped_ptr<IPC::Message> response(new ViewHostMsg_SelectRange_ACK(0)); + scoped_ptr<IPC::Message> response(new InputHostMsg_SelectRange_ACK(0)); + input_router_->OnMessageReceived(*response); + } + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); +} + +TEST_F(InputRouterImplTest, CoalescesMoveRangeSelectionExtent) { + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(1, 2)))); + ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>( + process_->sink().GetMessageAt(0), + gfx::Point(1, 2)); + EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + + // Send two more messages without acking. + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(3, 4)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(5, 6)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + // Now ack the first message. + { + scoped_ptr<IPC::Message> response( + new InputHostMsg_MoveRangeSelectionExtent_ACK(0)); + input_router_->OnMessageReceived(*response); + } + + // Verify that the two messages are coalesced into one message. + ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>( + process_->sink().GetMessageAt(0), + gfx::Point(5, 6)); + EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + + // Acking the coalesced msg should not send any more msg. + { + scoped_ptr<IPC::Message> response( + new InputHostMsg_MoveRangeSelectionExtent_ACK(0)); + input_router_->OnMessageReceived(*response); + } + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); +} + +TEST_F(InputRouterImplTest, InterleaveSelectRangeAndMoveRangeSelectionExtent) { + // Send first message: SelectRange. + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_SelectRange(0, gfx::Point(1, 2), gfx::Point(3, 4)))); + ExpectIPCMessageWithArg2<InputMsg_SelectRange>( + process_->sink().GetMessageAt(0), + gfx::Point(1, 2), + gfx::Point(3, 4)); + EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + + // Send second message: MoveRangeSelectionExtent. + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(5, 6)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + // Send third message: SelectRange. + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_SelectRange(0, gfx::Point(7, 8), gfx::Point(9, 10)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + // Ack the messages and verify that they're not coalesced and that they're in + // correct order. + + // Ack the first message. + { + scoped_ptr<IPC::Message> response( + new InputHostMsg_SelectRange_ACK(0)); + input_router_->OnMessageReceived(*response); + } + + ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>( + process_->sink().GetMessageAt(0), + gfx::Point(5, 6)); + EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + + // Ack the second message. + { + scoped_ptr<IPC::Message> response( + new InputHostMsg_MoveRangeSelectionExtent_ACK(0)); + input_router_->OnMessageReceived(*response); + } + + ExpectIPCMessageWithArg2<InputMsg_SelectRange>( + process_->sink().GetMessageAt(0), + gfx::Point(7, 8), + gfx::Point(9, 10)); + EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + + // Ack the third message. + { + scoped_ptr<IPC::Message> response( + new InputHostMsg_SelectRange_ACK(0)); + input_router_->OnMessageReceived(*response); + } + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); +} + +TEST_F(InputRouterImplTest, + CoalescesInterleavedSelectRangeAndMoveRangeSelectionExtent) { + // Send interleaved SelectRange and MoveRangeSelectionExtent messages. They + // should be coalesced as shown by the arrows. + // > SelectRange + // MoveRangeSelectionExtent + // MoveRangeSelectionExtent + // > MoveRangeSelectionExtent + // SelectRange + // > SelectRange + // > MoveRangeSelectionExtent + + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_SelectRange(0, gfx::Point(1, 2), gfx::Point(3, 4)))); + ExpectIPCMessageWithArg2<InputMsg_SelectRange>( + process_->sink().GetMessageAt(0), + gfx::Point(1, 2), + gfx::Point(3, 4)); + EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(5, 6)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(7, 8)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(9, 10)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_SelectRange(0, gfx::Point(11, 12), gfx::Point(13, 14)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_SelectRange(0, gfx::Point(15, 16), gfx::Point(17, 18)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + input_router_->SendInput(scoped_ptr<IPC::Message>( + new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(19, 20)))); + EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + + // Ack the first message. + { + scoped_ptr<IPC::Message> response( + new InputHostMsg_SelectRange_ACK(0)); + input_router_->OnMessageReceived(*response); + } + + // Verify that the three MoveRangeSelectionExtent messages are coalesced into + // one message. + ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>( + process_->sink().GetMessageAt(0), + gfx::Point(9, 10)); + EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + + // Ack the second message. + { + scoped_ptr<IPC::Message> response( + new InputHostMsg_MoveRangeSelectionExtent_ACK(0)); + input_router_->OnMessageReceived(*response); + } + + // Verify that the two SelectRange messages are coalesced into one message. + ExpectIPCMessageWithArg2<InputMsg_SelectRange>( + process_->sink().GetMessageAt(0), + gfx::Point(15, 16), + gfx::Point(17, 18)); + EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + + // Ack the third message. + { + scoped_ptr<IPC::Message> response( + new InputHostMsg_SelectRange_ACK(0)); + input_router_->OnMessageReceived(*response); + } + + // Verify the fourth message. + ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>( + process_->sink().GetMessageAt(0), + gfx::Point(19, 20)); + EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + + // Ack the fourth message. + { + scoped_ptr<IPC::Message> response( + new InputHostMsg_MoveRangeSelectionExtent_ACK(0)); input_router_->OnMessageReceived(*response); } EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); @@ -391,7 +581,7 @@ TEST_F(InputRouterImplTest, CoalescesCaretMove) { // Now ack the first message. { - scoped_ptr<IPC::Message> response(new ViewHostMsg_MoveCaret_ACK(0)); + scoped_ptr<IPC::Message> response(new InputHostMsg_MoveCaret_ACK(0)); input_router_->OnMessageReceived(*response); } @@ -402,7 +592,7 @@ TEST_F(InputRouterImplTest, CoalescesCaretMove) { // Acking the coalesced msg should not send any more msg. { - scoped_ptr<IPC::Message> response(new ViewHostMsg_MoveCaret_ACK(0)); + scoped_ptr<IPC::Message> response(new InputHostMsg_MoveCaret_ACK(0)); input_router_->OnMessageReceived(*response); } EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); diff --git a/content/browser/renderer_host/input/touch_selection_controller.cc b/content/browser/renderer_host/input/touch_selection_controller.cc index e904e28..4c8807d 100644 --- a/content/browser/renderer_host/input/touch_selection_controller.cc +++ b/content/browser/renderer_host/input/touch_selection_controller.cc @@ -209,13 +209,19 @@ void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) { return; } + gfx::PointF base, extent; if (&handle == start_selection_handle_.get()) { - fixed_handle_position_ = - end_selection_handle_->position() + GetEndLineOffset(); + base = end_selection_handle_->position() + GetEndLineOffset(); + extent = start_selection_handle_->position() + GetStartLineOffset(); } else { - fixed_handle_position_ = - start_selection_handle_->position() + GetStartLineOffset(); + base = start_selection_handle_->position() + GetStartLineOffset(); + extent = end_selection_handle_->position() + GetEndLineOffset(); } + + // When moving the handle we want to move only the extent point. Before doing + // so we must make sure that the base point is set correctly. + client_->SelectBetweenCoordinates(base, extent); + client_->OnSelectionEvent(SELECTION_DRAG_STARTED, handle.position()); } @@ -230,7 +236,7 @@ void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle, if (&handle == insertion_handle_.get()) { client_->MoveCaret(line_position); } else { - client_->SelectBetweenCoordinates(fixed_handle_position_, line_position); + client_->MoveRangeSelectionExtent(line_position); } } diff --git a/content/browser/renderer_host/input/touch_selection_controller.h b/content/browser/renderer_host/input/touch_selection_controller.h index 1ded1a97..abe4ed4 100644 --- a/content/browser/renderer_host/input/touch_selection_controller.h +++ b/content/browser/renderer_host/input/touch_selection_controller.h @@ -31,8 +31,9 @@ class CONTENT_EXPORT TouchSelectionControllerClient { virtual bool SupportsAnimation() const = 0; virtual void SetNeedsAnimate() = 0; virtual void MoveCaret(const gfx::PointF& position) = 0; - virtual void SelectBetweenCoordinates(const gfx::PointF& start, - const gfx::PointF& end) = 0; + virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) = 0; + virtual void SelectBetweenCoordinates(const gfx::PointF& base, + const gfx::PointF& extent) = 0; virtual void OnSelectionEvent(SelectionEventType event, const gfx::PointF& position) = 0; virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() = 0; @@ -133,7 +134,6 @@ class CONTENT_EXPORT TouchSelectionController : public TouchHandleClient { scoped_ptr<TouchHandle> start_selection_handle_; scoped_ptr<TouchHandle> end_selection_handle_; - gfx::PointF fixed_handle_position_; bool is_selection_active_; bool activate_selection_automatically_; diff --git a/content/browser/renderer_host/input/touch_selection_controller_unittest.cc b/content/browser/renderer_host/input/touch_selection_controller_unittest.cc index ca4af34..de7d620 100644 --- a/content/browser/renderer_host/input/touch_selection_controller_unittest.cc +++ b/content/browser/renderer_host/input/touch_selection_controller_unittest.cc @@ -42,6 +42,7 @@ class TouchSelectionControllerTest : public testing::Test, : last_event_(SELECTION_CLEARED), caret_moved_(false), selection_moved_(false), + selection_points_swapped_(false), needs_animate_(false), animation_enabled_(true), dragging_enabled_(false) {} @@ -69,11 +70,18 @@ class TouchSelectionControllerTest : public testing::Test, caret_position_ = position; } - void SelectBetweenCoordinates(const gfx::PointF& start, - const gfx::PointF& end) override { + void SelectBetweenCoordinates(const gfx::PointF& base, + const gfx::PointF& extent) override { + if (base == selection_end_ && extent == selection_start_) + selection_points_swapped_ = true; + + selection_start_ = base; + selection_end_ = extent; + } + + virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) override { selection_moved_ = true; - selection_start_ = start; - selection_end_ = end; + selection_end_ = extent; } void OnSelectionEvent(SelectionEventType event, @@ -148,6 +156,12 @@ class TouchSelectionControllerTest : public testing::Test, return moved; } + bool GetAndResetSelectionPointsSwapped() { + bool swapped = selection_points_swapped_; + selection_points_swapped_ = false; + return swapped; + } + const gfx::PointF& GetLastCaretPosition() const { return caret_position_; } const gfx::PointF& GetLastSelectionStart() const { return selection_start_; } const gfx::PointF& GetLastSelectionEnd() const { return selection_end_; } @@ -164,6 +178,7 @@ class TouchSelectionControllerTest : public testing::Test, SelectionEventType last_event_; bool caret_moved_; bool selection_moved_; + bool selection_points_swapped_; bool needs_animate_; bool animation_enabled_; bool dragging_enabled_; @@ -602,6 +617,122 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedWithOverlap) { EXPECT_FALSE(GetAndResetSelectionMoved()); } +TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { + base::TimeTicks event_time = base::TimeTicks::Now(); + controller().OnLongPressEvent(); + + float line_height = 10.f; + gfx::RectF start_rect(50, line_height, 0, line_height); + gfx::RectF end_rect(100, line_height, 0, line_height); + bool visible = true; + ChangeSelection(start_rect, visible, end_rect, visible); + EXPECT_EQ(SELECTION_SHOWN, GetLastEventType()); + EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor()); + + SetDraggingEnabled(true); + + // Move the extent, not triggering a swap of points. + MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, + end_rect.x(), end_rect.bottom()); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_FALSE(GetAndResetSelectionMoved()); + EXPECT_FALSE(GetAndResetSelectionPointsSwapped()); + + gfx::PointF base_offset = start_rect.CenterPoint(); + gfx::PointF extent_offset = end_rect.CenterPoint(); + event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, + end_rect.x(), end_rect.bottom() + 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType()); + EXPECT_TRUE(GetAndResetSelectionMoved()); + EXPECT_FALSE(GetAndResetSelectionPointsSwapped()); + EXPECT_EQ(base_offset, GetLastSelectionStart()); + EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd()); + + event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType()); + EXPECT_FALSE(GetAndResetSelectionMoved()); + + end_rect += gfx::Vector2dF(0, 5); + ChangeSelection(start_rect, visible, end_rect, visible); + + // Move the base, triggering a swap of points. + event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + start_rect.x(), start_rect.bottom()); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_FALSE(GetAndResetSelectionMoved()); + EXPECT_TRUE(GetAndResetSelectionPointsSwapped()); + + base_offset = end_rect.CenterPoint(); + extent_offset = start_rect.CenterPoint(); + event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, + start_rect.x(), start_rect.bottom() + 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType()); + EXPECT_TRUE(GetAndResetSelectionMoved()); + EXPECT_FALSE(GetAndResetSelectionPointsSwapped()); + EXPECT_EQ(base_offset, GetLastSelectionStart()); + EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd()); + + event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType()); + EXPECT_FALSE(GetAndResetSelectionMoved()); + + start_rect += gfx::Vector2dF(0, 5); + ChangeSelection(start_rect, visible, end_rect, visible); + + // Move the same point again, not triggering a swap of points. + event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + start_rect.x(), start_rect.bottom()); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_FALSE(GetAndResetSelectionMoved()); + EXPECT_FALSE(GetAndResetSelectionPointsSwapped()); + + base_offset = end_rect.CenterPoint(); + extent_offset = start_rect.CenterPoint(); + event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, + start_rect.x(), start_rect.bottom() + 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType()); + EXPECT_TRUE(GetAndResetSelectionMoved()); + EXPECT_FALSE(GetAndResetSelectionPointsSwapped()); + EXPECT_EQ(base_offset, GetLastSelectionStart()); + EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd()); + + event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType()); + EXPECT_FALSE(GetAndResetSelectionMoved()); + + start_rect += gfx::Vector2dF(0, 5); + ChangeSelection(start_rect, visible, end_rect, visible); + + // Move the base, triggering a swap of points. + event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + end_rect.x(), end_rect.bottom()); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_FALSE(GetAndResetSelectionMoved()); + EXPECT_TRUE(GetAndResetSelectionPointsSwapped()); + + base_offset = start_rect.CenterPoint(); + extent_offset = end_rect.CenterPoint(); + event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, + end_rect.x(), end_rect.bottom() + 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType()); + EXPECT_TRUE(GetAndResetSelectionMoved()); + EXPECT_FALSE(GetAndResetSelectionPointsSwapped()); + EXPECT_EQ(base_offset, GetLastSelectionStart()); + EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd()); + + event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType()); + EXPECT_FALSE(GetAndResetSelectionMoved()); +} + TEST_F(TouchSelectionControllerTest, Animation) { controller().OnTapEvent(); controller().OnSelectionEditable(true); diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 67af1bb..830ab01 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc @@ -1301,7 +1301,7 @@ TEST_F(RenderWidgetHostTest, InputRouterReceivesHandleInputEvent_ACK) { TEST_F(RenderWidgetHostTest, InputRouterReceivesMoveCaret_ACK) { host_->SetupForInputRouterTest(); - host_->OnMessageReceived(ViewHostMsg_MoveCaret_ACK(0)); + host_->OnMessageReceived(InputHostMsg_MoveCaret_ACK(0)); EXPECT_TRUE(host_->mock_input_router()->message_received_); } @@ -1309,7 +1309,7 @@ TEST_F(RenderWidgetHostTest, InputRouterReceivesMoveCaret_ACK) { TEST_F(RenderWidgetHostTest, InputRouterReceivesSelectRange_ACK) { host_->SetupForInputRouterTest(); - host_->OnMessageReceived(ViewHostMsg_SelectRange_ACK(0)); + host_->OnMessageReceived(InputHostMsg_SelectRange_ACK(0)); EXPECT_TRUE(host_->mock_input_router()->message_received_); } diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index dac44e1..3a2dc88 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -1160,11 +1160,17 @@ void RenderWidgetHostViewAndroid::MoveCaret(const gfx::PointF& position) { MoveCaret(gfx::Point(position.x(), position.y())); } +void RenderWidgetHostViewAndroid::MoveRangeSelectionExtent( + const gfx::PointF& extent) { + DCHECK(content_view_core_); + content_view_core_->MoveRangeSelectionExtent(extent); +} + void RenderWidgetHostViewAndroid::SelectBetweenCoordinates( - const gfx::PointF& start, - const gfx::PointF& end) { + const gfx::PointF& base, + const gfx::PointF& extent) { DCHECK(content_view_core_); - content_view_core_->SelectBetweenCoordinates(start, end); + content_view_core_->SelectBetweenCoordinates(base, extent); } void RenderWidgetHostViewAndroid::OnSelectionEvent( diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 48d6536..063a515 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h @@ -269,8 +269,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid virtual bool SupportsAnimation() const override; virtual void SetNeedsAnimate() override; virtual void MoveCaret(const gfx::PointF& position) override; - virtual void SelectBetweenCoordinates(const gfx::PointF& start, - const gfx::PointF& end) override; + virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) override; + virtual void SelectBetweenCoordinates(const gfx::PointF& base, + const gfx::PointF& extent) override; virtual void OnSelectionEvent(SelectionEventType event, const gfx::PointF& anchor_position) override; virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() override; diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index c17dcf3..d3e8b13 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -3174,14 +3174,23 @@ void WebContentsImpl::SetIsLoading(RenderViewHost* render_view_host, type, Source<NavigationController>(&controller_), det); } -void WebContentsImpl::SelectRange(const gfx::Point& start, - const gfx::Point& end) { +void WebContentsImpl::MoveRangeSelectionExtent(const gfx::Point& extent) { + RenderFrameHost* focused_frame = GetFocusedFrame(); + if (!focused_frame) + return; + + focused_frame->Send(new InputMsg_MoveRangeSelectionExtent( + focused_frame->GetRoutingID(), extent)); +} + +void WebContentsImpl::SelectRange(const gfx::Point& base, + const gfx::Point& extent) { RenderFrameHost* focused_frame = GetFocusedFrame(); if (!focused_frame) return; focused_frame->Send( - new InputMsg_SelectRange(focused_frame->GetRoutingID(), start, end)); + new InputMsg_SelectRange(focused_frame->GetRoutingID(), base, extent)); } void WebContentsImpl::UpdateMaxPageIDIfNecessary(RenderViewHost* rvh) { diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index e502796..7869292 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h @@ -638,9 +638,12 @@ class CONTENT_EXPORT WebContentsImpl typedef base::Callback<void(WebContents*)> CreatedCallback; + // Requests the renderer to move the selection extent to a new position. + void MoveRangeSelectionExtent(const gfx::Point& extent); + // Requests the renderer to select the region between two points in the // currently focused frame. - void SelectRange(const gfx::Point& start, const gfx::Point& end); + void SelectRange(const gfx::Point& base, const gfx::Point& extent); // Notifies the main frame that it can continue navigation (if it was deferred // immediately at first response). diff --git a/content/common/input_messages.h b/content/common/input_messages.h index 9953035..95663f7 100644 --- a/content/common/input_messages.h +++ b/content/common/input_messages.h @@ -199,8 +199,13 @@ IPC_MESSAGE_ROUTED0(InputMsg_Unselect) // Requests the renderer to select the region between two points. // Expects a SelectRange_ACK message when finished. IPC_MESSAGE_ROUTED2(InputMsg_SelectRange, - gfx::Point /* start */, - gfx::Point /* end */) + gfx::Point /* base */, + gfx::Point /* extent */) + +// Requests the renderer to move the selection extent point to a new position. +// Expects a MoveRangeSelectionExtent_ACK message when finished. +IPC_MESSAGE_ROUTED1(InputMsg_MoveRangeSelectionExtent, + gfx::Point /* extent */) // Requests the renderer to move the caret selection toward the point. // Expects a MoveCaret_ACK message when finished. @@ -237,6 +242,15 @@ IPC_MESSAGE_ROUTED1(InputHostMsg_SetTouchAction, IPC_MESSAGE_ROUTED1(InputHostMsg_DidOverscroll, content::DidOverscrollParams /* params */) +// Acknowledges receipt of a InputMsg_MoveCaret message. +IPC_MESSAGE_ROUTED0(InputHostMsg_MoveCaret_ACK) + +// Acknowledges receipt of a InputMsg_MoveRangeSelectionExtent message. +IPC_MESSAGE_ROUTED0(InputHostMsg_MoveRangeSelectionExtent_ACK) + +// Acknowledges receipt of a InputMsg_SelectRange message. +IPC_MESSAGE_ROUTED0(InputHostMsg_SelectRange_ACK) + // Required for cancelling an ongoing input method composition. IPC_MESSAGE_ROUTED0(InputHostMsg_ImeCancelComposition) diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 3f55ab5..426ac1f 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -1330,9 +1330,6 @@ IPC_MESSAGE_ROUTED2(ViewHostMsg_SetTooltipText, base::string16 /* tooltip text string */, blink::WebTextDirection /* text direction hint */) -IPC_MESSAGE_ROUTED0(ViewHostMsg_SelectRange_ACK) -IPC_MESSAGE_ROUTED0(ViewHostMsg_MoveCaret_ACK) - // Notification that the text selection has changed. // Note: The secound parameter is the character based offset of the // base::string16 diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 3d8a05f..5319024 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -920,6 +920,8 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(InputMsg_SelectAll, OnSelectAll) IPC_MESSAGE_HANDLER(InputMsg_SelectRange, OnSelectRange) IPC_MESSAGE_HANDLER(InputMsg_Unselect, OnUnselect) + IPC_MESSAGE_HANDLER(InputMsg_MoveRangeSelectionExtent, + OnMoveRangeSelectionExtent) IPC_MESSAGE_HANDLER(InputMsg_Replace, OnReplace) IPC_MESSAGE_HANDLER(InputMsg_ReplaceMisspelling, OnReplaceMisspelling) IPC_MESSAGE_HANDLER(InputMsg_ExtendSelectionAndDelete, @@ -1282,13 +1284,13 @@ void RenderFrameImpl::OnSelectAll() { frame_->executeCommand(WebString::fromUTF8("SelectAll"), GetFocusedElement()); } -void RenderFrameImpl::OnSelectRange(const gfx::Point& start, - const gfx::Point& end) { +void RenderFrameImpl::OnSelectRange(const gfx::Point& base, + const gfx::Point& extent) { // This IPC is dispatched by RenderWidgetHost, so use its routing id. - Send(new ViewHostMsg_SelectRange_ACK(GetRenderWidget()->routing_id())); + Send(new InputHostMsg_SelectRange_ACK(GetRenderWidget()->routing_id())); base::AutoReset<bool> handling_select_range(&handling_select_range_, true); - frame_->selectRange(start, end); + frame_->selectRange(base, extent); } void RenderFrameImpl::OnUnselect() { @@ -1296,6 +1298,15 @@ void RenderFrameImpl::OnUnselect() { frame_->executeCommand(WebString::fromUTF8("Unselect"), GetFocusedElement()); } +void RenderFrameImpl::OnMoveRangeSelectionExtent(const gfx::Point& point) { + // This IPC is dispatched by RenderWidgetHost, so use its routing id. + Send(new InputHostMsg_MoveRangeSelectionExtent_ACK( + GetRenderWidget()->routing_id())); + + base::AutoReset<bool> handling_select_range(&handling_select_range_, true); + frame_->moveRangeSelectionExtent(point); +} + void RenderFrameImpl::OnReplace(const base::string16& text) { if (!frame_->hasSelection()) frame_->selectWordAroundCaret(); diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index f0d15ec..ccb30b4 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h @@ -541,8 +541,9 @@ class CONTENT_EXPORT RenderFrameImpl void OnPasteAndMatchStyle(); void OnDelete(); void OnSelectAll(); - void OnSelectRange(const gfx::Point& start, const gfx::Point& end); + void OnSelectRange(const gfx::Point& base, const gfx::Point& extent); void OnUnselect(); + void OnMoveRangeSelectionExtent(const gfx::Point& point); void OnReplace(const base::string16& text); void OnReplaceMisspelling(const base::string16& text); void OnCSSInsertRequest(const std::string& css); diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 49f1732..15985fc 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -1465,7 +1465,7 @@ void RenderViewImpl::OnMoveCaret(const gfx::Point& point) { if (!webview()) return; - Send(new ViewHostMsg_MoveCaret_ACK(routing_id_)); + Send(new InputHostMsg_MoveCaret_ACK(routing_id_)); webview()->focusedFrame()->moveCaretSelection(point); } |