File: touch_selection_controller.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (299 lines) | stat: -rw-r--r-- 11,491 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_H_
#define UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_H_

#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/selection_bound.h"
#include "ui/touch_selection/longpress_drag_selector.h"
#include "ui/touch_selection/selection_event_type.h"
#include "ui/touch_selection/touch_handle.h"
#include "ui/touch_selection/touch_handle_orientation.h"
#include "ui/touch_selection/ui_touch_selection_export.h"

#if BUILDFLAG(IS_ANDROID)
namespace cc::slim {
class Layer;
}
#endif

namespace ui {
class MotionEvent;

// Interface through which |TouchSelectionController| issues selection-related
// commands, notifications and requests.
class UI_TOUCH_SELECTION_EXPORT TouchSelectionControllerClient {
 public:
  virtual ~TouchSelectionControllerClient() {}

  virtual bool SupportsAnimation() const = 0;
  virtual void SetNeedsAnimate() = 0;
  virtual void MoveCaret(const gfx::PointF& position) = 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) = 0;
  virtual void OnDragUpdate(const TouchSelectionDraggable::Type type,
                            const gfx::PointF& position) = 0;
  virtual std::unique_ptr<TouchHandleDrawable> CreateDrawable() = 0;
  virtual void DidScroll() = 0;
  virtual void ShowTouchSelectionContextMenu(const gfx::Point& location) {}
};

// Controller for manipulating text selection via touch input.
class UI_TOUCH_SELECTION_EXPORT TouchSelectionController
    : public TouchHandleClient,
      public LongPressDragSelectorClient {
 public:
  enum ActiveStatus {
    INACTIVE,
    INSERTION_ACTIVE,
    SELECTION_ACTIVE,
  };

  struct UI_TOUCH_SELECTION_EXPORT Config {
    // Maximum allowed time for handle tap detection. Defaults to 300 ms.
    base::TimeDelta max_tap_duration = base::Milliseconds(300);

    // Defaults to 8 DIPs.
    float tap_slop = 8;

    // Controls whether adaptive orientation for selection handles is enabled.
    // Defaults to false.
    bool enable_adaptive_handle_orientation = false;

    // Controls whether drag selection after a longpress is enabled.
    // Defaults to false.
    bool enable_longpress_drag_selection = false;

    // Should we hide the active handle.
    bool hide_active_handle = false;
  };

  TouchSelectionController(TouchSelectionControllerClient* client,
                           const Config& config);

  TouchSelectionController(const TouchSelectionController&) = delete;
  TouchSelectionController& operator=(const TouchSelectionController&) = delete;

  ~TouchSelectionController() override;

  // To be called when the selection bounds have changed.
  // Note that such updates will trigger handle updates only if preceded
  // by an appropriate call to allow automatic showing.
  void OnSelectionBoundsChanged(const gfx::SelectionBound& start,
                                const gfx::SelectionBound& end);

  // To be called when the viewport rect has been changed. This is used for
  // setting the state of the handles.
  void OnViewportChanged(const gfx::RectF viewport_rect);

  // Allows touch-dragging of the handle.
  // Returns true iff the event was consumed, in which case the caller should
  // cease further handling of the event.
  bool WillHandleTouchEvent(const MotionEvent& event);

  // To be called before forwarding a tap event.
  // |tap_count| is tap index in a repeated sequence, i.e., 1 for the first
  // tap, 2 for the second tap, etc...
  void HandleTapEvent(const gfx::PointF& location, int tap_count);

  // To be called before forwarding a longpress event.
  void HandleLongPressEvent(base::TimeTicks event_time,
                                const gfx::PointF& location);

  // To be called before forwarding a double press event.
  void HandleDoublePressEvent(base::TimeTicks event_time,
                              const gfx::PointF& location);

  // To be called before forwarding a gesture scroll begin event to prevent
  // long-press drag.
  void OnScrollBeginEvent();

#if BUILDFLAG(IS_ANDROID)
  void OnUpdateNativeViewTree(gfx::NativeView parent_native_view,
                              cc::slim::Layer* parent_layer);
#endif

// TODO(crbug.com/375388841): Remove once Aura also uses
// TouchSelectionControllerInputObserver for receiving inputs.
#if BUILDFLAG(IS_ANDROID)
  // Called when a scroll event ack is received.
  void HandleSwipeToMoveCursorGestureAck(
      ui::EventType type,
      const gfx::PointF& point,
      const std::optional<bool>& cursor_control,
      bool is_in_root_view);
#endif  // BUILDFLAG(IS_ANDROID)

  // Hide the handles and suppress bounds updates until the next explicit
  // showing allowance.
  void HideAndDisallowShowingAutomatically();

  // Override the handle visibility according to |hidden|.
  void SetTemporarilyHidden(bool hidden);

  // Ticks an active animation, as requested to the client by |SetNeedsAnimate|.
  // Returns true if an animation is active and requires further ticking.
  bool Animate(base::TimeTicks animate_time);

  // Returns the current focus bound. For an active selection, this is the
  // selection bound that has most recently been dragged or updated (defaulting
  // to the end if neither endpoint has moved). For an active insertion it is
  // the caret bound. Should only be called when touch selection is active.
  const gfx::SelectionBound& GetFocusBound() const;

  // Returns the rect between the two active selection bounds. If just one of
  // the bounds is visible, or both bounds are visible and on the same line,
  // the rect is simply a one-dimensional rect of that bound. If no selection
  // is active, an empty rect will be returned.
  gfx::RectF GetRectBetweenBounds() const;
  // Returns the rect between the selection bounds (as above) but clipped by
  // occluding layers.
  gfx::RectF GetVisibleRectBetweenBounds() const;

  // Returns the visible rect of specified touch handle. For an active insertion
  // these values will be identical.
  gfx::RectF GetStartHandleRect() const;
  gfx::RectF GetEndHandleRect() const;

  // Return the handle height of visible touch handle. This value will be zero
  // when no handle is visible.
  float GetTouchHandleHeight() const;

  // Returns the focal point of the start and end bounds, as defined by
  // their bottom coordinate.
  const gfx::PointF& GetStartPosition() const;
  const gfx::PointF& GetEndPosition() const;

  // To be called when swipe-to-move-cursor motion begins.
  void OnSwipeToMoveCursorBegin();
  // To be called when swipe-to-move-cursor motion ends.
  void OnSwipeToMoveCursorEnd();

  const gfx::SelectionBound& start() const { return start_; }
  const gfx::SelectionBound& end() const { return end_; }

  ActiveStatus active_status() const { return active_status_; }

 private:
  friend class TouchSelectionControllerTestApi;

  enum InputEventType { TAP, REPEATED_TAP, LONG_PRESS, INPUT_EVENT_TYPE_NONE };

  enum class DragSelectorInitiatingGesture { kNone, kLongPress, kDoublePress };

  bool WillHandleTouchEventImpl(const MotionEvent& event);

  // TouchHandleClient implementation.
  void OnDragBegin(const TouchSelectionDraggable& draggable,
                   const gfx::PointF& drag_position) override;
  void OnDragUpdate(const TouchSelectionDraggable& draggable,
                    const gfx::PointF& drag_position) override;
  void OnDragEnd(const TouchSelectionDraggable& draggable) override;
  bool IsWithinTapSlop(const gfx::Vector2dF& delta) const override;
  void OnHandleTapped(const TouchHandle& handle) override;
  void SetNeedsAnimate() override;
  std::unique_ptr<TouchHandleDrawable> CreateDrawable() override;
  base::TimeDelta GetMaxTapDuration() const override;
  bool IsAdaptiveHandleOrientationEnabled() const override;

  // LongPressDragSelectorClient implementation.
  void OnLongPressDragActiveStateChanged() override;
  gfx::PointF GetSelectionStart() const override;
  gfx::PointF GetSelectionEnd() const override;

  void OnInsertionChanged();
  void OnSelectionChanged();

  // Returns true if insertion mode was newly (re)activated.
  bool ActivateInsertionIfNecessary();
  void DeactivateInsertion();
  // Returns true if selection mode was newly (re)activated.
  bool ActivateSelectionIfNecessary();
  void DeactivateSelection();
  void UpdateHandleLayoutIfNecessary();

  bool WillHandleTouchEventForLongPressDrag(const MotionEvent& event);
  void SetTemporarilyHiddenForLongPressDrag(bool hidden);
  void RefreshHandleVisibility();

  // Returns the y-coordinate of middle point of selection bound corresponding
  // to the active selection or insertion handle. If there is no active handle,
  // returns 0.0.
  float GetActiveHandleMiddleY() const;

  void HideHandles();

  gfx::Vector2dF GetStartLineOffset() const;
  gfx::Vector2dF GetEndLineOffset() const;
  bool GetStartVisible() const;
  bool GetEndVisible() const;
  TouchHandle::AnimationStyle GetAnimationStyle(bool was_active) const;

  void LogDragType(const TouchSelectionDraggable& draggable);

  const raw_ptr<TouchSelectionControllerClient, DanglingUntriaged> client_;
  const Config config_;

  InputEventType response_pending_input_event_;

  // The bounds at the begin and end of the selection, which might be vertical
  // or horizontal line and represents the position of the touch handles or
  // caret.
  gfx::SelectionBound start_;
  gfx::SelectionBound end_;
  TouchHandleOrientation start_orientation_;
  TouchHandleOrientation end_orientation_;

  ActiveStatus active_status_;

  std::unique_ptr<TouchHandle> insertion_handle_;

  std::unique_ptr<TouchHandle> start_selection_handle_;
  std::unique_ptr<TouchHandle> end_selection_handle_;

  bool temporarily_hidden_;

  // Whether to use the start bound (if false, the end bound) for computing the
  // appropriate text line offset when performing a selection drag. This helps
  // ensure that the initial selection induced by the drag doesn't "jump"
  // between lines.
  bool anchor_drag_to_selection_start_;

  // Allows the text selection to be adjusted by touch dragging after a long
  // press or double press initiated selection.
  LongPressDragSelector longpress_drag_selector_;

  // Used to track whether a selection drag gesture was initiated by a long
  // press or double press.
  DragSelectorInitiatingGesture drag_selector_initiating_gesture_ =
      DragSelectorInitiatingGesture::kNone;

  gfx::RectF viewport_rect_;

  // Whether a selection handle was dragged during the current 'selection
  // session' - i.e. since the current selection has been activated.
  bool selection_handle_dragged_;

  // Determines whether the entire touch sequence should be consumed or not.
  bool consume_touch_sequence_;

  bool show_touch_handles_;

  // Whether a swipe-to-move-cursor gesture is activated.
  bool swipe_to_move_cursor_activated_ = false;
};

}  // namespace ui

#endif  // UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_H_