Commit a8248c9e authored by mohsen's avatar mohsen Committed by Commit bot

Re-activate touch selection after fling

Currently, when a scroll starts touch selection handles are hidden and
then re-shown after scroll ends. But, if scroll ends in a fling, handles
are not re-shown, because there hadn't been a way to determine end of
the fling. Now that there is an IPC message notifying end of flings, we
can re-show handles after a fling.

BUG=413927

Review URL: https://codereview.chromium.org/569863003

Cr-Commit-Position: refs/heads/master@{#294927}
parent 774231cb
...@@ -1046,6 +1046,11 @@ void RenderWidgetHostViewAura::OnSwapCompositorFrame( ...@@ -1046,6 +1046,11 @@ void RenderWidgetHostViewAura::OnSwapCompositorFrame(
} }
} }
void RenderWidgetHostViewAura::DidStopFlinging() {
if (touch_editing_client_)
touch_editing_client_->DidStopFlinging();
}
#if defined(OS_WIN) #if defined(OS_WIN)
void RenderWidgetHostViewAura::SetParentNativeViewAccessible( void RenderWidgetHostViewAura::SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) { gfx::NativeViewAccessible accessible_parent) {
......
...@@ -116,6 +116,10 @@ class CONTENT_EXPORT RenderWidgetHostViewAura ...@@ -116,6 +116,10 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// Notifies the client that a gesture event ack was received. // Notifies the client that a gesture event ack was received.
virtual void GestureEventAck(int gesture_event_type) = 0; virtual void GestureEventAck(int gesture_event_type) = 0;
// Notifies the client that the fling has ended, so it can activate touch
// editing if needed.
virtual void DidStopFlinging() = 0;
// This is called when the view is destroyed, so that the client can // This is called when the view is destroyed, so that the client can
// perform any necessary clean-up. // perform any necessary clean-up.
virtual void OnViewDestroyed() = 0; virtual void OnViewDestroyed() = 0;
...@@ -228,6 +232,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura ...@@ -228,6 +232,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
virtual void OnSwapCompositorFrame( virtual void OnSwapCompositorFrame(
uint32 output_surface_id, uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) OVERRIDE; scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
virtual void DidStopFlinging() OVERRIDE;
#if defined(OS_WIN) #if defined(OS_WIN)
virtual void SetParentNativeViewAccessible( virtual void SetParentNativeViewAccessible(
......
...@@ -61,26 +61,11 @@ void TouchEditableImplAura::UpdateEditingController() { ...@@ -61,26 +61,11 @@ void TouchEditableImplAura::UpdateEditingController() {
} }
void TouchEditableImplAura::OverscrollStarted() { void TouchEditableImplAura::OverscrollStarted() {
overscroll_in_progress_ = true; scrolls_in_progress_++;
} }
void TouchEditableImplAura::OverscrollCompleted() { void TouchEditableImplAura::OverscrollCompleted() {
// We might receive multiple OverscrollStarted() and OverscrollCompleted() ScrollEnded();
// during the same scroll session (for example, when the scroll direction
// changes). We want to show the handles only when:
// 1. Overscroll has completed
// 2. Scrolling session is over, i.e. we have received ET_GESTURE_SCROLL_END.
// 3. If we had hidden the handles when scrolling started
// 4. If there is still a need to show handles (there is a non-empty selection
// or non-NONE |text_input_type_|)
if (overscroll_in_progress_ && !scroll_in_progress_ &&
handles_hidden_due_to_scroll_ &&
(selection_anchor_rect_ != selection_focus_rect_ ||
text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
StartTouchEditing();
UpdateEditingController();
}
overscroll_in_progress_ = false;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
...@@ -116,12 +101,10 @@ void TouchEditableImplAura::OnSelectionOrCursorChanged(const gfx::Rect& anchor, ...@@ -116,12 +101,10 @@ void TouchEditableImplAura::OnSelectionOrCursorChanged(const gfx::Rect& anchor,
selection_anchor_rect_ = anchor; selection_anchor_rect_ = anchor;
selection_focus_rect_ = focus; selection_focus_rect_ = focus;
// If touch editing handles were not visible, we bring them up only if // If touch editing handles were not visible, we bring them up only if the
// there is non-zero selection on the page. And the current event is a // current event is a gesture event, no scroll/fling/overscoll is in progress,
// gesture event (we dont want to show handles if the user is selecting // and there is non-zero selection on the page
// using mouse or keyboard). if (selection_gesture_in_process_ && !scrolls_in_progress_ &&
if (selection_gesture_in_process_ && !scroll_in_progress_ &&
!overscroll_in_progress_ &&
selection_anchor_rect_ != selection_focus_rect_) { selection_anchor_rect_ != selection_focus_rect_) {
StartTouchEditing(); StartTouchEditing();
selection_gesture_in_process_ = false; selection_gesture_in_process_ = false;
...@@ -163,36 +146,29 @@ bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) { ...@@ -163,36 +146,29 @@ bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) {
} }
// For single taps, not inside selected region, we want to show handles // For single taps, not inside selected region, we want to show handles
// only when the tap is on an already focused textfield. // only when the tap is on an already focused textfield.
textfield_was_focused_on_tap_ = false; textfield_was_focused_on_tap_ =
if (gesture_event->details().tap_count() == 1 && gesture_event->details().tap_count() == 1 &&
text_input_type_ != ui::TEXT_INPUT_TYPE_NONE) text_input_type_ != ui::TEXT_INPUT_TYPE_NONE;
textfield_was_focused_on_tap_ = true;
break; break;
case ui::ET_GESTURE_LONG_PRESS: case ui::ET_GESTURE_LONG_PRESS:
selection_gesture_in_process_ = true; selection_gesture_in_process_ = true;
break; break;
case ui::ET_GESTURE_SCROLL_BEGIN: case ui::ET_GESTURE_SCROLL_BEGIN:
// If selection handles are currently visible, we want to get them back up scrolls_in_progress_++;
// when scrolling ends. So we set |handles_hidden_due_to_scroll_| so that // We need to hide selection handles during scroll (including fling and
// we can re-start touch editing on scroll end gesture. // overscroll), but they should be re-activated after scrolling if:
scroll_in_progress_ = true; // - an existing scroll decided that handles should be shown after
handles_hidden_due_to_scroll_ = false; // scrolling; or
if (touch_selection_controller_) // - the gesture in progress is going to end in selection; or
handles_hidden_due_to_scroll_ = true; // - selection handles are currently active.
handles_hidden_due_to_scroll_ = handles_hidden_due_to_scroll_ ||
selection_gesture_in_process_ ||
touch_selection_controller_ != NULL;
selection_gesture_in_process_ = false;
EndTouchEditing(true); EndTouchEditing(true);
break; break;
case ui::ET_GESTURE_SCROLL_END: case ui::ET_GESTURE_SCROLL_END:
// Scroll has ended, but we might still be in overscroll animation. ScrollEnded();
if (handles_hidden_due_to_scroll_ && !overscroll_in_progress_ &&
(selection_anchor_rect_ != selection_focus_rect_ ||
text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
StartTouchEditing();
UpdateEditingController();
}
// fall through to reset |scroll_in_progress_|.
case ui::ET_SCROLL_FLING_START:
selection_gesture_in_process_ = false;
scroll_in_progress_ = false;
break; break;
default: default:
break; break;
...@@ -210,6 +186,10 @@ void TouchEditableImplAura::GestureEventAck(int gesture_event_type) { ...@@ -210,6 +186,10 @@ void TouchEditableImplAura::GestureEventAck(int gesture_event_type) {
} }
} }
void TouchEditableImplAura::DidStopFlinging() {
ScrollEnded();
}
void TouchEditableImplAura::OnViewDestroyed() { void TouchEditableImplAura::OnViewDestroyed() {
Cleanup(); Cleanup();
} }
...@@ -364,11 +344,23 @@ TouchEditableImplAura::TouchEditableImplAura() ...@@ -364,11 +344,23 @@ TouchEditableImplAura::TouchEditableImplAura()
rwhva_(NULL), rwhva_(NULL),
selection_gesture_in_process_(false), selection_gesture_in_process_(false),
handles_hidden_due_to_scroll_(false), handles_hidden_due_to_scroll_(false),
scroll_in_progress_(false), scrolls_in_progress_(0),
overscroll_in_progress_(false),
textfield_was_focused_on_tap_(false) { textfield_was_focused_on_tap_(false) {
} }
void TouchEditableImplAura::ScrollEnded() {
scrolls_in_progress_--;
// If there is no scrolling left in progress, show selection handles if they
// were hidden due to scroll and there is a selection.
if (!scrolls_in_progress_ && handles_hidden_due_to_scroll_ &&
(selection_anchor_rect_ != selection_focus_rect_ ||
text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
StartTouchEditing();
UpdateEditingController();
handles_hidden_due_to_scroll_ = false;
}
}
void TouchEditableImplAura::Cleanup() { void TouchEditableImplAura::Cleanup() {
if (rwhva_) { if (rwhva_) {
rwhva_->set_touch_editing_client(NULL); rwhva_->set_touch_editing_client(NULL);
...@@ -378,8 +370,7 @@ void TouchEditableImplAura::Cleanup() { ...@@ -378,8 +370,7 @@ void TouchEditableImplAura::Cleanup() {
EndTouchEditing(true); EndTouchEditing(true);
selection_gesture_in_process_ = false; selection_gesture_in_process_ = false;
handles_hidden_due_to_scroll_ = false; handles_hidden_due_to_scroll_ = false;
scroll_in_progress_ = false; scrolls_in_progress_ = 0;
overscroll_in_progress_ = false;
} }
} // namespace content } // namespace content
...@@ -49,6 +49,7 @@ class CONTENT_EXPORT TouchEditableImplAura ...@@ -49,6 +49,7 @@ class CONTENT_EXPORT TouchEditableImplAura
virtual void OnTextInputTypeChanged(ui::TextInputType type) OVERRIDE; virtual void OnTextInputTypeChanged(ui::TextInputType type) OVERRIDE;
virtual bool HandleInputEvent(const ui::Event* event) OVERRIDE; virtual bool HandleInputEvent(const ui::Event* event) OVERRIDE;
virtual void GestureEventAck(int gesture_event_type) OVERRIDE; virtual void GestureEventAck(int gesture_event_type) OVERRIDE;
virtual void DidStopFlinging() OVERRIDE;
virtual void OnViewDestroyed() OVERRIDE; virtual void OnViewDestroyed() OVERRIDE;
// Overridden from ui::TouchEditable: // Overridden from ui::TouchEditable:
...@@ -76,6 +77,10 @@ class CONTENT_EXPORT TouchEditableImplAura ...@@ -76,6 +77,10 @@ class CONTENT_EXPORT TouchEditableImplAura
private: private:
friend class TouchEditableImplAuraTest; friend class TouchEditableImplAuraTest;
// A convenience function that is called after scroll/fling/overscroll ends to
// re-activate touch selection if necessary.
void ScrollEnded();
void Cleanup(); void Cleanup();
// Rectangles for the selection anchor and focus. // Rectangles for the selection anchor and focus.
...@@ -96,11 +101,8 @@ class CONTENT_EXPORT TouchEditableImplAura ...@@ -96,11 +101,8 @@ class CONTENT_EXPORT TouchEditableImplAura
// whether to re-show handles after a scrolling session. // whether to re-show handles after a scrolling session.
bool handles_hidden_due_to_scroll_; bool handles_hidden_due_to_scroll_;
// Keeps track of when the user is scrolling. // Keeps track of number of scrolls/flings/overscrolls in progress.
bool scroll_in_progress_; int scrolls_in_progress_;
// Set to true when the page starts an overscroll.
bool overscroll_in_progress_;
// Used to track if a textfield was focused when the current tap gesture // Used to track if a textfield was focused when the current tap gesture
// happened. // happened.
......
...@@ -36,13 +36,17 @@ class TestTouchEditableImplAura : public TouchEditableImplAura { ...@@ -36,13 +36,17 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
: selection_changed_callback_arrived_(false), : selection_changed_callback_arrived_(false),
waiting_for_selection_changed_callback_(false), waiting_for_selection_changed_callback_(false),
waiting_for_gesture_ack_type_(WebInputEvent::Undefined), waiting_for_gesture_ack_type_(WebInputEvent::Undefined),
last_gesture_ack_type_(WebInputEvent::Undefined) {} last_gesture_ack_type_(WebInputEvent::Undefined),
fling_stop_callback_arrived_(false),
waiting_for_fling_stop_callback_(false) {}
virtual void Reset() { virtual void Reset() {
selection_changed_callback_arrived_ = false; selection_changed_callback_arrived_ = false;
waiting_for_selection_changed_callback_ = false; waiting_for_selection_changed_callback_ = false;
waiting_for_gesture_ack_type_ = WebInputEvent::Undefined; waiting_for_gesture_ack_type_ = WebInputEvent::Undefined;
last_gesture_ack_type_ = WebInputEvent::Undefined; last_gesture_ack_type_ = WebInputEvent::Undefined;
fling_stop_callback_arrived_ = false;
waiting_for_fling_stop_callback_ = false;
} }
virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor, virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
...@@ -61,6 +65,13 @@ class TestTouchEditableImplAura : public TouchEditableImplAura { ...@@ -61,6 +65,13 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
gesture_ack_wait_run_loop_->Quit(); gesture_ack_wait_run_loop_->Quit();
} }
virtual void DidStopFlinging() OVERRIDE {
fling_stop_callback_arrived_ = true;
TouchEditableImplAura::DidStopFlinging();
if (waiting_for_fling_stop_callback_)
fling_stop_wait_run_loop_->Quit();
}
virtual void WaitForSelectionChangeCallback() { virtual void WaitForSelectionChangeCallback() {
if (selection_changed_callback_arrived_) if (selection_changed_callback_arrived_)
return; return;
...@@ -77,6 +88,14 @@ class TestTouchEditableImplAura : public TouchEditableImplAura { ...@@ -77,6 +88,14 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
gesture_ack_wait_run_loop_->Run(); gesture_ack_wait_run_loop_->Run();
} }
virtual void WaitForFlingStopCallback() {
if (fling_stop_callback_arrived_)
return;
waiting_for_fling_stop_callback_ = true;
fling_stop_wait_run_loop_.reset(new base::RunLoop());
fling_stop_wait_run_loop_->Run();
}
protected: protected:
virtual ~TestTouchEditableImplAura() {} virtual ~TestTouchEditableImplAura() {}
...@@ -85,8 +104,11 @@ class TestTouchEditableImplAura : public TouchEditableImplAura { ...@@ -85,8 +104,11 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
bool waiting_for_selection_changed_callback_; bool waiting_for_selection_changed_callback_;
WebInputEvent::Type waiting_for_gesture_ack_type_; WebInputEvent::Type waiting_for_gesture_ack_type_;
WebInputEvent::Type last_gesture_ack_type_; WebInputEvent::Type last_gesture_ack_type_;
bool fling_stop_callback_arrived_;
bool waiting_for_fling_stop_callback_;
scoped_ptr<base::RunLoop> selection_changed_wait_run_loop_; scoped_ptr<base::RunLoop> selection_changed_wait_run_loop_;
scoped_ptr<base::RunLoop> gesture_ack_wait_run_loop_; scoped_ptr<base::RunLoop> gesture_ack_wait_run_loop_;
scoped_ptr<base::RunLoop> fling_stop_wait_run_loop_;
DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAura); DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAura);
}; };
...@@ -242,6 +264,62 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, ...@@ -242,6 +264,62 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
EXPECT_TRUE(GetTouchSelectionController(touch_editable)); EXPECT_TRUE(GetTouchSelectionController(touch_editable));
} }
IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
TestTouchSelectionReshownAfterFling) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
RenderFrameHost* main_frame = web_contents->GetMainFrame();
WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
web_contents->GetView());
TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
view_aura->SetTouchEditableForTest(touch_editable);
RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
web_contents->GetRenderWidgetHostView());
EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
// Long press to select word.
ui::GestureEvent long_press(
10,
10,
0,
ui::EventTimeForNow(),
ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS, 0, 0));
touch_editable->Reset();
rwhva->OnGestureEvent(&long_press);
touch_editable->WaitForSelectionChangeCallback();
// Check if selection handles are showing.
EXPECT_TRUE(GetTouchSelectionController(touch_editable));
scoped_ptr<base::Value> value =
content::ExecuteScriptAndGetValue(main_frame, "get_selection()");
std::string selection;
value->GetAsString(&selection);
EXPECT_STREQ("Some", selection.c_str());
// Start scrolling. Handles should get hidden.
ui::GestureEvent scroll_begin(
10,
10,
0,
ui::EventTimeForNow(),
ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0));
rwhva->OnGestureEvent(&scroll_begin);
EXPECT_FALSE(GetTouchSelectionController(touch_editable));
// Start a fling. Handles should come back after fling stops.
ui::GestureEvent fling_start(
10,
10,
0,
ui::EventTimeForNow(),
ui::GestureEventDetails(ui::ET_SCROLL_FLING_START, 1, 0));
rwhva->OnGestureEvent(&fling_start);
touch_editable->WaitForFlingStopCallback();
EXPECT_TRUE(GetTouchSelectionController(touch_editable));
}
IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
TouchSelectionOnLongPressTest) { TouchSelectionOnLongPressTest) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment