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(
}
}
void RenderWidgetHostViewAura::DidStopFlinging() {
if (touch_editing_client_)
touch_editing_client_->DidStopFlinging();
}
#if defined(OS_WIN)
void RenderWidgetHostViewAura::SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) {
......
......@@ -116,6 +116,10 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// Notifies the client that a gesture event ack was received.
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
// perform any necessary clean-up.
virtual void OnViewDestroyed() = 0;
......@@ -228,6 +232,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
virtual void OnSwapCompositorFrame(
uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
virtual void DidStopFlinging() OVERRIDE;
#if defined(OS_WIN)
virtual void SetParentNativeViewAccessible(
......
......@@ -61,26 +61,11 @@ void TouchEditableImplAura::UpdateEditingController() {
}
void TouchEditableImplAura::OverscrollStarted() {
overscroll_in_progress_ = true;
scrolls_in_progress_++;
}
void TouchEditableImplAura::OverscrollCompleted() {
// We might receive multiple OverscrollStarted() and OverscrollCompleted()
// 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;
ScrollEnded();
}
////////////////////////////////////////////////////////////////////////////////
......@@ -116,12 +101,10 @@ void TouchEditableImplAura::OnSelectionOrCursorChanged(const gfx::Rect& anchor,
selection_anchor_rect_ = anchor;
selection_focus_rect_ = focus;
// If touch editing handles were not visible, we bring them up only if
// there is non-zero selection on the page. And the current event is a
// gesture event (we dont want to show handles if the user is selecting
// using mouse or keyboard).
if (selection_gesture_in_process_ && !scroll_in_progress_ &&
!overscroll_in_progress_ &&
// If touch editing handles were not visible, we bring them up only if the
// current event is a gesture event, no scroll/fling/overscoll is in progress,
// and there is non-zero selection on the page
if (selection_gesture_in_process_ && !scrolls_in_progress_ &&
selection_anchor_rect_ != selection_focus_rect_) {
StartTouchEditing();
selection_gesture_in_process_ = false;
......@@ -163,36 +146,29 @@ bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) {
}
// For single taps, not inside selected region, we want to show handles
// only when the tap is on an already focused textfield.
textfield_was_focused_on_tap_ = false;
if (gesture_event->details().tap_count() == 1 &&
text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)
textfield_was_focused_on_tap_ = true;
textfield_was_focused_on_tap_ =
gesture_event->details().tap_count() == 1 &&
text_input_type_ != ui::TEXT_INPUT_TYPE_NONE;
break;
case ui::ET_GESTURE_LONG_PRESS:
selection_gesture_in_process_ = true;
break;
case ui::ET_GESTURE_SCROLL_BEGIN:
// If selection handles are currently visible, we want to get them back up
// when scrolling ends. So we set |handles_hidden_due_to_scroll_| so that
// we can re-start touch editing on scroll end gesture.
scroll_in_progress_ = true;
handles_hidden_due_to_scroll_ = false;
if (touch_selection_controller_)
handles_hidden_due_to_scroll_ = true;
scrolls_in_progress_++;
// We need to hide selection handles during scroll (including fling and
// overscroll), but they should be re-activated after scrolling if:
// - an existing scroll decided that handles should be shown after
// scrolling; or
// - the gesture in progress is going to end in selection; or
// - 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);
break;
case ui::ET_GESTURE_SCROLL_END:
// Scroll has ended, but we might still be in overscroll animation.
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;
ScrollEnded();
break;
default:
break;
......@@ -210,6 +186,10 @@ void TouchEditableImplAura::GestureEventAck(int gesture_event_type) {
}
}
void TouchEditableImplAura::DidStopFlinging() {
ScrollEnded();
}
void TouchEditableImplAura::OnViewDestroyed() {
Cleanup();
}
......@@ -364,11 +344,23 @@ TouchEditableImplAura::TouchEditableImplAura()
rwhva_(NULL),
selection_gesture_in_process_(false),
handles_hidden_due_to_scroll_(false),
scroll_in_progress_(false),
overscroll_in_progress_(false),
scrolls_in_progress_(0),
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() {
if (rwhva_) {
rwhva_->set_touch_editing_client(NULL);
......@@ -378,8 +370,7 @@ void TouchEditableImplAura::Cleanup() {
EndTouchEditing(true);
selection_gesture_in_process_ = false;
handles_hidden_due_to_scroll_ = false;
scroll_in_progress_ = false;
overscroll_in_progress_ = false;
scrolls_in_progress_ = 0;
}
} // namespace content
......@@ -49,6 +49,7 @@ class CONTENT_EXPORT TouchEditableImplAura
virtual void OnTextInputTypeChanged(ui::TextInputType type) OVERRIDE;
virtual bool HandleInputEvent(const ui::Event* event) OVERRIDE;
virtual void GestureEventAck(int gesture_event_type) OVERRIDE;
virtual void DidStopFlinging() OVERRIDE;
virtual void OnViewDestroyed() OVERRIDE;
// Overridden from ui::TouchEditable:
......@@ -76,6 +77,10 @@ class CONTENT_EXPORT TouchEditableImplAura
private:
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();
// Rectangles for the selection anchor and focus.
......@@ -96,11 +101,8 @@ class CONTENT_EXPORT TouchEditableImplAura
// whether to re-show handles after a scrolling session.
bool handles_hidden_due_to_scroll_;
// Keeps track of when the user is scrolling.
bool scroll_in_progress_;
// Set to true when the page starts an overscroll.
bool overscroll_in_progress_;
// Keeps track of number of scrolls/flings/overscrolls in progress.
int scrolls_in_progress_;
// Used to track if a textfield was focused when the current tap gesture
// happened.
......
......@@ -36,13 +36,17 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
: selection_changed_callback_arrived_(false),
waiting_for_selection_changed_callback_(false),
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() {
selection_changed_callback_arrived_ = false;
waiting_for_selection_changed_callback_ = false;
waiting_for_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,
......@@ -61,6 +65,13 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
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() {
if (selection_changed_callback_arrived_)
return;
......@@ -77,6 +88,14 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
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:
virtual ~TestTouchEditableImplAura() {}
......@@ -85,8 +104,11 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
bool waiting_for_selection_changed_callback_;
WebInputEvent::Type waiting_for_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> gesture_ack_wait_run_loop_;
scoped_ptr<base::RunLoop> fling_stop_wait_run_loop_;
DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAura);
};
......@@ -242,6 +264,62 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
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,
TouchSelectionOnLongPressTest) {
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