1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/input/gesture_text_selector.h"
7 #include "ui/events/event_constants.h"
8 #include "ui/events/gesture_detection/gesture_detector.h"
9 #include "ui/events/gesture_detection/gesture_provider_config_helper.h"
10 #include "ui/events/gesture_detection/motion_event.h"
12 using ui::GestureDetector;
13 using ui::MotionEvent;
17 scoped_ptr<GestureDetector> CreateGestureDetector(
18 ui::GestureListener* listener) {
19 GestureDetector::Config config =
20 ui::DefaultGestureProviderConfig().gesture_detector_config;
22 ui::DoubleTapListener* null_double_tap_listener = nullptr;
24 // Doubletap, showpress and longpress detection are not required, and
25 // should be explicitly disabled for efficiency.
26 scoped_ptr<ui::GestureDetector> detector(
27 new ui::GestureDetector(config, listener, null_double_tap_listener));
28 detector->set_longpress_enabled(false);
29 detector->set_showpress_enabled(false);
31 return detector.Pass();
36 GestureTextSelector::GestureTextSelector(GestureTextSelectorClient* client)
38 text_selection_triggered_(false),
39 secondary_button_pressed_(false),
45 GestureTextSelector::~GestureTextSelector() {
48 bool GestureTextSelector::OnTouchEvent(const MotionEvent& event) {
49 if (event.GetAction() == MotionEvent::ACTION_DOWN) {
50 // Only trigger selection on ACTION_DOWN to prevent partial touch or gesture
51 // sequences from being forwarded.
52 text_selection_triggered_ = ShouldStartTextSelection(event);
53 secondary_button_pressed_ =
54 event.GetButtonState() == MotionEvent::BUTTON_SECONDARY;
55 anchor_x_ = event.GetX();
56 anchor_y_ = event.GetY();
59 if (!text_selection_triggered_)
62 if (event.GetAction() == MotionEvent::ACTION_MOVE) {
63 secondary_button_pressed_ =
64 event.GetButtonState() == MotionEvent::BUTTON_SECONDARY;
65 if (!secondary_button_pressed_) {
66 anchor_x_ = event.GetX();
67 anchor_y_ = event.GetY();
71 if (!gesture_detector_)
72 gesture_detector_ = CreateGestureDetector(this);
74 gesture_detector_->OnTouchEvent(event);
76 // Always return true, even if |gesture_detector_| technically doesn't
77 // consume the event, to prevent a partial touch stream from being forwarded.
81 bool GestureTextSelector::OnSingleTapUp(const MotionEvent& e) {
82 DCHECK(text_selection_triggered_);
83 client_->LongPress(e.GetEventTime(), e.GetX(), e.GetY());
87 bool GestureTextSelector::OnScroll(const MotionEvent& e1,
88 const MotionEvent& e2,
91 DCHECK(text_selection_triggered_);
93 // Return if Stylus button is not pressed.
94 if (!secondary_button_pressed_)
97 // TODO(changwan): check if we can show handles after the scroll finishes
98 // instead. Currently it is not possible as ShowSelectionHandles should
99 // be called before we change the selection.
100 client_->ShowSelectionHandlesAutomatically();
101 client_->SelectRange(anchor_x_, anchor_y_, e2.GetX(), e2.GetY());
106 bool GestureTextSelector::ShouldStartTextSelection(const MotionEvent& event) {
107 DCHECK_GT(event.GetPointerCount(), 0u);
108 // Currently we are supporting stylus-only cases.
109 const bool is_stylus = event.GetToolType(0) == MotionEvent::TOOL_TYPE_STYLUS;
110 const bool is_only_secondary_button_pressed =
111 event.GetButtonState() == MotionEvent::BUTTON_SECONDARY;
112 return is_stylus && is_only_secondary_button_pressed;
115 } // namespace content