Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(360)

Side by Side Diff: ui/touch_selection/touch_selection_controller.cc

Issue 903143003: wip: Touch Text Selection Prototypes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@selection_granularity_on_unified
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/touch_selection/touch_selection_controller.h" 5 #include "ui/touch_selection/touch_selection_controller.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 9
10 namespace ui { 10 namespace ui {
(...skipping 21 matching lines...) Expand all
32 return TOUCH_HANDLE_CENTER; 32 return TOUCH_HANDLE_CENTER;
33 case SelectionBound::EMPTY: 33 case SelectionBound::EMPTY:
34 return TOUCH_HANDLE_ORIENTATION_UNDEFINED; 34 return TOUCH_HANDLE_ORIENTATION_UNDEFINED;
35 } 35 }
36 NOTREACHED() << "Invalid selection bound type: " << type; 36 NOTREACHED() << "Invalid selection bound type: " << type;
37 return TOUCH_HANDLE_ORIENTATION_UNDEFINED; 37 return TOUCH_HANDLE_ORIENTATION_UNDEFINED;
38 } 38 }
39 39
40 } // namespace 40 } // namespace
41 41
42 class GranularityStrategy {
43 public:
44 virtual ~GranularityStrategy() {};
45 virtual void OnSelectionBoundsUpdated(const SelectionBound& start,
46 const SelectionBound& end) {};
47 virtual void OnHandleDragBegin(const gfx::PointF& position,
48 base::TimeTicks event_time,
49 TouchSelectionController* controller) {};
50 virtual TextSelectionGranularity OnHandleDragUpdate(
51 const gfx::PointF& position,
52 const gfx::PointF& line_position,
53 base::TimeTicks event_time,
54 bool end_handle_dragged) { return ui::CHARACTER_GRANULARITY; };
55 protected:
56 GranularityStrategy() {};
57 };
58
59 class DefaultGranularityStrategy : public GranularityStrategy {
60 public:
61 DefaultGranularityStrategy() {};
62 ~DefaultGranularityStrategy() override {};
63 };
64
65 class DirectionGranularityStrategy : public GranularityStrategy {
66 public:
67 DirectionGranularityStrategy() : granularity_(ui::CHARACTER_GRANULARITY) {};
68
69 ~DirectionGranularityStrategy() override {};
70
71 void OnSelectionBoundsUpdated(const SelectionBound& start,
72 const SelectionBound& end) override {
73 // LOG(ERROR) << "Bounds updated: "
74 // << "start.y/2=" << (start.edge_bottom_rounded().y() + start.edge_top_r ounded().y()) /2
75 // << ", start.x=" << start.edge_bottom_rounded().x()
76 // << ", end.y/2=" << (end.edge_bottom_rounded().y() + end.edge_top_round ed().y()) / 2
77 // << ", end.x=" << end.edge_bottom_rounded().x();
78
79 if (granularity_ == ui::WORD_GRANULARITY) {
80 granularity_threshold_start_ = start;
81 granularity_threshold_end_ = end;
82 }
83 };
84
85 void OnHandleDragBegin(const gfx::PointF& position,
86 base::TimeTicks event_time,
87 TouchSelectionController* controller) override {
88 // TODO(mfomitchev):
89 // Ideally we want word boundaries communicated in CompositorFrameMetadata
90 // (see RenderWidgetHostViewAura::OnSwapCompositorFrame)
91 granularity_threshold_start_ = controller->start();
92 granularity_threshold_end_ = controller->end();
93 farthest_dragging_handle_position_ = position;
94 granularity_ = ui::WORD_GRANULARITY;
95 };
96
97 // TODO(mfomitchev): perhaps this should depend on character size?
98 // tap_slop_ is too big, uses max_touch_move_in_pixels_for_click. Perhaps
99 // we should use span_slop? See GestureConfiguration
100 const int kHandleDragSlop = 7;
101 TextSelectionGranularity OnHandleDragUpdate(
102 const gfx::PointF& position,
103 const gfx::PointF& line_position,
104 base::TimeTicks event_time,
105 bool end_handle_dragged) override {
106 if (end_handle_dragged) {
107 if (line_position.y() > granularity_threshold_end_.edge_bottom().y()) {
108 LOG(ERROR) << "Moved down a line - adjusting max_dragging_handle_positio n_";
109 farthest_dragging_handle_position_ = position;
110 if (granularity_ == ui::CHARACTER_GRANULARITY) {
111 LOG(ERROR) << "Moved down a line, switching to WORD_GRANULARITY";
112 granularity_ = ui::WORD_GRANULARITY;
113 }
114 } else if (line_position.y() < granularity_threshold_end_.edge_top().y()) {
115 LOG(ERROR) << "Moved up a line - adjusting max_dragging_handle_position_ ";
116 farthest_dragging_handle_position_ = position;
117 if (granularity_ == ui::CHARACTER_GRANULARITY) {
118 granularity_ = ui::WORD_GRANULARITY;
119 LOG(ERROR) << "Moved up a line - switching to WORD_GRANULARITY";
120 }
121 } else if (position.x() > farthest_dragging_handle_position_.x()) {
122 LOG(ERROR) << "Incrementing max_dragging_handle_position_";
123 farthest_dragging_handle_position_ = position;
124 if (granularity_ == ui::CHARACTER_GRANULARITY &&
125 position.x() > granularity_threshold_end_.edge_bottom().x()) {
126 granularity_ = ui::WORD_GRANULARITY;
127 LOG(ERROR) << "Moved right of granularity_threshold_end_,"
128 << " switching to WORD_GRANULARITY";
129 }
130 } else if (position.x() + kHandleDragSlop <
131 farthest_dragging_handle_position_.x()) {
132 if (granularity_ == ui::WORD_GRANULARITY) {
133 granularity_ = ui::CHARACTER_GRANULARITY;
134 LOG(ERROR) << "Moved left of max_dragging_handle_position_,"
135 << " switching to CHARACTER_GRANULARITY";
136 }
137 }
138 } else { //!end_handle_dragged
139 if (line_position.y() < granularity_threshold_start_.edge_top().y() ||
140 line_position.y() > granularity_threshold_start_.edge_bottom().y()) {
141 // Line change
142 farthest_dragging_handle_position_ = position;
143 granularity_ = ui::WORD_GRANULARITY;
144 } else if (position.x() < farthest_dragging_handle_position_.x()) {
145 farthest_dragging_handle_position_ = position;
146 if (position.x() < granularity_threshold_start_.edge_bottom().x())
147 granularity_ = ui::WORD_GRANULARITY;
148 } else if (position.x() - kHandleDragSlop >
149 farthest_dragging_handle_position_.x()) {
150 granularity_ = ui::CHARACTER_GRANULARITY;
151 }
152 }
153 return granularity_;
154 }
155
156 private:
157 TextSelectionGranularity granularity_;
158 SelectionBound granularity_threshold_start_;
159 SelectionBound granularity_threshold_end_;
160 // If we go left of this by more than slop - switch to CHAR granularity
161 // For right handle - farthest down/right
162 // For left handle - farthest up/left
163 gfx::PointF farthest_dragging_handle_position_;
164
165 DISALLOW_COPY_AND_ASSIGN(DirectionGranularityStrategy);
166 };
167
168 class VelocityGranularityStrategy : public GranularityStrategy {
169 public:
170 VelocityGranularityStrategy() :
171 granularity_(ui::CHARACTER_GRANULARITY),
172 avg_velocity_(0.f),
173 filterTimeConstant_(kFilterTimeConstant),
174 velocityGranularityThreshold_(kVelocityGranularityThreshold) {};
175
176 ~VelocityGranularityStrategy() override {};
177
178 const float kFilterTimeConstant = 0.3f; // half decay @ 300ms
179 const float kVelocityGranularityThreshold = 80.f;
180
181 void SetStrategyParameters(int halfDecayMs, int threshold) {
182 filterTimeConstant_ = halfDecayMs / 1000.f;
183 velocityGranularityThreshold_ = threshold;
184 }
185
186 void OnHandleDragBegin(const gfx::PointF& position,
187 base::TimeTicks event_time,
188 TouchSelectionController* controller) override {
189 last_dragging_handle_position_ = position;
190 avg_velocity_ = 0;
191 last_event_time_ = event_time;
192 granularity_ = ui::WORD_GRANULARITY;
193 };
194
195 TextSelectionGranularity OnHandleDragUpdate(
196 const gfx::PointF& position,
197 const gfx::PointF& line_position,
198 base::TimeTicks event_time,
199 bool end_handle_dragged) override {
200 float dist = (position - last_dragging_handle_position_).Length();
201 float dt = static_cast<float>((event_time - last_event_time_).InSecondsF());
202 float current_velocity = dist / dt;
203
204 if (avg_velocity_ == 0) {
205 avg_velocity_ = current_velocity;
206 } else {
207 float alpha = dt / (filterTimeConstant_ + dt);
208 avg_velocity_ += (current_velocity - avg_velocity_) * alpha;
209 }
210
211 if (avg_velocity_ > velocityGranularityThreshold_)
212 granularity_ = ui::WORD_GRANULARITY;
213 else
214 granularity_ = ui::CHARACTER_GRANULARITY;
215
216 LOG(ERROR) << "avg_velocity=" << avg_velocity_
217 << ", current_velocity=" << current_velocity;
218
219 last_dragging_handle_position_ = position;
220 last_event_time_ = event_time;
221
222 return granularity_;
223 };
224
225 private:
226 TextSelectionGranularity granularity_;
227 gfx::PointF last_dragging_handle_position_;
228 base::TimeTicks last_event_time_;
229 float avg_velocity_;
230
231 float filterTimeConstant_;
232 float velocityGranularityThreshold_;
233
234
235 DISALLOW_COPY_AND_ASSIGN(VelocityGranularityStrategy);
236 };
237
42 TouchSelectionController::TouchSelectionController( 238 TouchSelectionController::TouchSelectionController(
43 TouchSelectionControllerClient* client, 239 TouchSelectionControllerClient* client,
44 base::TimeDelta tap_timeout, 240 base::TimeDelta tap_timeout,
45 float tap_slop, 241 float tap_slop,
46 bool show_on_tap_for_empty_editable) 242 bool show_on_tap_for_empty_editable,
243 TextSelectionGranularityStrategy selection_granularity_strategy)
47 : client_(client), 244 : client_(client),
48 tap_timeout_(tap_timeout), 245 tap_timeout_(tap_timeout),
49 tap_slop_(tap_slop), 246 tap_slop_(tap_slop),
50 show_on_tap_for_empty_editable_(show_on_tap_for_empty_editable), 247 show_on_tap_for_empty_editable_(show_on_tap_for_empty_editable),
51 response_pending_input_event_(INPUT_EVENT_TYPE_NONE), 248 response_pending_input_event_(INPUT_EVENT_TYPE_NONE),
52 start_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), 249 start_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
53 end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), 250 end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
54 is_insertion_active_(false), 251 is_insertion_active_(false),
55 activate_insertion_automatically_(false), 252 activate_insertion_automatically_(false),
56 is_selection_active_(false), 253 is_selection_active_(false),
57 activate_selection_automatically_(false), 254 activate_selection_automatically_(false),
58 selection_empty_(false), 255 selection_empty_(false),
59 selection_editable_(false), 256 selection_editable_(false),
60 temporarily_hidden_(false) { 257 temporarily_hidden_(false),
258 selection_granularity_strategy_(selection_granularity_strategy) {
61 DCHECK(client_); 259 DCHECK(client_);
260 switch (selection_granularity_strategy) {
261 case GRANULARITY_STRATEGY_DEFAULT:
262 granularity_strategy_.reset(new DefaultGranularityStrategy());
263 break;
264 case GRANULARITY_STRATEGY_DIRECTION:
265 granularity_strategy_.reset(new DirectionGranularityStrategy());
266 break;
267 case GRANULARITY_STRATEGY_VELOCITY:
268 granularity_strategy_.reset(new VelocityGranularityStrategy());
269 break;
270 }
62 } 271 }
63 272
64 TouchSelectionController::~TouchSelectionController() { 273 TouchSelectionController::~TouchSelectionController() {
65 } 274 }
66 275
276 void TouchSelectionController::SetVelocityStrategyParameters(int halfDecayMs,
277 int threshold) {
278 if (selection_granularity_strategy_ != GRANULARITY_STRATEGY_VELOCITY)
279 return;
280
281 VelocityGranularityStrategy* velocityStrategy =
282 static_cast<VelocityGranularityStrategy*>(granularity_strategy_.get());
283 velocityStrategy->SetStrategyParameters(halfDecayMs, threshold);
284 }
285
67 void TouchSelectionController::OnSelectionBoundsUpdated( 286 void TouchSelectionController::OnSelectionBoundsUpdated(
68 const SelectionBound& start, 287 const SelectionBound& start,
69 const SelectionBound& end) { 288 const SelectionBound& end) {
70 if (start == start_ && end_ == end) 289 if (start == start_ && end_ == end)
71 return; 290 return;
72 291
292 granularity_strategy_->OnSelectionBoundsUpdated(start, end);
293
73 start_ = start; 294 start_ = start;
74 end_ = end; 295 end_ = end;
75 start_orientation_ = ToTouchHandleOrientation(start_.type()); 296 start_orientation_ = ToTouchHandleOrientation(start_.type());
76 end_orientation_ = ToTouchHandleOrientation(end_.type()); 297 end_orientation_ = ToTouchHandleOrientation(end_.type());
77 298
78 if (!activate_selection_automatically_ && 299 if (!activate_selection_automatically_ &&
79 !activate_insertion_automatically_) { 300 !activate_insertion_automatically_) {
80 DCHECK_EQ(INPUT_EVENT_TYPE_NONE, response_pending_input_event_); 301 DCHECK_EQ(INPUT_EVENT_TYPE_NONE, response_pending_input_event_);
81 return; 302 return;
82 } 303 }
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 449
229 void TouchSelectionController::TryActivateSelection() { 450 void TouchSelectionController::TryActivateSelection() {
230 if (GetStartPosition() != GetEndPosition()) { 451 if (GetStartPosition() != GetEndPosition()) {
231 SelectionBound start = start_; 452 SelectionBound start = start_;
232 SelectionBound end = end_; 453 SelectionBound end = end_;
233 ShowSelectionHandlesAutomatically(); 454 ShowSelectionHandlesAutomatically();
234 OnSelectionBoundsUpdated(start, end); 455 OnSelectionBoundsUpdated(start, end);
235 } 456 }
236 } 457 }
237 458
238 void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) { 459 void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle,
460 base::TimeTicks event_time) {
239 if (&handle == insertion_handle_.get()) { 461 if (&handle == insertion_handle_.get()) {
240 client_->OnSelectionEvent(INSERTION_DRAG_STARTED, handle.position()); 462 client_->OnSelectionEvent(INSERTION_DRAG_STARTED, handle.position());
241 return; 463 return;
242 } 464 }
243 465
244 gfx::PointF base, extent; 466 gfx::PointF base, extent;
245 if (&handle == start_selection_handle_.get()) { 467 if (&handle == start_selection_handle_.get()) {
246 base = end_selection_handle_->position() + GetEndLineOffset(); 468 base = end_selection_handle_->position() + GetEndLineOffset();
247 extent = start_selection_handle_->position() + GetStartLineOffset(); 469 extent = start_selection_handle_->position() + GetStartLineOffset();
470 // TODO: HACK
471 client_->SelectBetweenCoordinates(base, start_.edge_bottom_rounded() + GetSt artLineOffset());
248 } else { 472 } else {
249 base = start_selection_handle_->position() + GetStartLineOffset(); 473 base = start_selection_handle_->position() + GetStartLineOffset();
250 extent = end_selection_handle_->position() + GetEndLineOffset(); 474 extent = end_selection_handle_->position() + GetEndLineOffset();
475 // TODO: HACK
476 client_->SelectBetweenCoordinates(base, end_.edge_bottom_rounded() + GetEndL ineOffset());
251 } 477 }
252 478
479 granularity_strategy_->OnHandleDragBegin(handle.position(), event_time, this);
480
253 // When moving the handle we want to move only the extent point. Before doing 481 // When moving the handle we want to move only the extent point. Before doing
254 // so we must make sure that the base point is set correctly. 482 // so we must make sure that the base point is set correctly.
255 client_->SelectBetweenCoordinates(base, extent); 483 // TODO: HACK - swallow the update
484 //client_->SelectBetweenCoordinates(base, extent);
485 //OnHandleDragUpdate(handle, handle.position());
256 486
257 client_->OnSelectionEvent(SELECTION_DRAG_STARTED, handle.position()); 487 client_->OnSelectionEvent(SELECTION_DRAG_STARTED, handle.position());
258 } 488 }
259 489
260 void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle, 490 void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle,
261 const gfx::PointF& position) { 491 const gfx::PointF& position,
492 base::TimeTicks event_time) {
493 // TODO: figure out RTL
494 // TODO: start/end can switch! Handle!
495 bool end_handle_dragged = &handle == end_selection_handle_.get();
262 // As the position corresponds to the bottom left point of the selection 496 // As the position corresponds to the bottom left point of the selection
263 // bound, offset it by half the corresponding line height. 497 // bound, offset it by half the corresponding line height.
264 gfx::Vector2dF line_offset = &handle == start_selection_handle_.get() 498 gfx::Vector2dF line_offset = end_handle_dragged
265 ? GetStartLineOffset() 499 ? GetEndLineOffset()
266 : GetEndLineOffset(); 500 : GetStartLineOffset();
501
267 gfx::PointF line_position = position + line_offset; 502 gfx::PointF line_position = position + line_offset;
503
268 if (&handle == insertion_handle_.get()) { 504 if (&handle == insertion_handle_.get()) {
269 client_->MoveCaret(line_position); 505 client_->MoveCaret(line_position);
270 } else { 506 } else {
271 client_->MoveRangeSelectionExtent(line_position, ui::CHARACTER_GRANULARITY); 507 TextSelectionGranularity granularity =
508 granularity_strategy_->OnHandleDragUpdate(position,
509 line_position,
510 event_time,
511 end_handle_dragged);
512 client_->MoveRangeSelectionExtent(line_position, granularity);
272 } 513 }
273 } 514 }
274 515
275 void TouchSelectionController::OnHandleDragEnd(const TouchHandle& handle) { 516 void TouchSelectionController::OnHandleDragEnd(const TouchHandle& handle) {
276 if (&handle == insertion_handle_.get()) 517 if (&handle == insertion_handle_.get())
277 client_->OnSelectionEvent(INSERTION_DRAG_STOPPED, handle.position()); 518 client_->OnSelectionEvent(INSERTION_DRAG_STOPPED, handle.position());
278 else 519 else
279 client_->OnSelectionEvent(SELECTION_DRAG_STOPPED, handle.position()); 520 client_->OnSelectionEvent(SELECTION_DRAG_STOPPED, handle.position());
280 } 521 }
281 522
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 } 690 }
450 691
451 TouchHandle::AnimationStyle TouchSelectionController::GetAnimationStyle( 692 TouchHandle::AnimationStyle TouchSelectionController::GetAnimationStyle(
452 bool was_active) const { 693 bool was_active) const {
453 return was_active && client_->SupportsAnimation() 694 return was_active && client_->SupportsAnimation()
454 ? TouchHandle::ANIMATION_SMOOTH 695 ? TouchHandle::ANIMATION_SMOOTH
455 : TouchHandle::ANIMATION_NONE; 696 : TouchHandle::ANIMATION_NONE;
456 } 697 }
457 698
458 } // namespace ui 699 } // namespace ui
OLDNEW
« no previous file with comments | « ui/touch_selection/touch_selection_controller.h ('k') | ui/touch_selection/touch_selection_controller_aura.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698