Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / ui / touch_selection / touch_selection_controller_unittest.cc
blobbe971b1034bd9a002e2bc60d044de4f67857a465
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 "ui/touch_selection/touch_selection_controller.h"
7 #include <vector>
9 #include "testing/gmock/include/gmock/gmock.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "ui/events/test/motion_event_test_utils.h"
12 #include "ui/touch_selection/touch_selection_controller_test_api.h"
14 using testing::ElementsAre;
15 using testing::IsEmpty;
16 using ui::test::MockMotionEvent;
18 namespace ui {
19 namespace {
21 const int kDefaultTapTimeoutMs = 200;
22 const float kDefaulTapSlop = 10.f;
23 const gfx::PointF kIgnoredPoint(0, 0);
25 class MockTouchHandleDrawable : public TouchHandleDrawable {
26 public:
27 explicit MockTouchHandleDrawable(bool* contains_point)
28 : intersects_rect_(contains_point) {}
29 ~MockTouchHandleDrawable() override {}
30 void SetEnabled(bool enabled) override {}
31 void SetOrientation(TouchHandleOrientation orientation) override {}
32 void SetAlpha(float alpha) override {}
33 void SetFocus(const gfx::PointF& position) override {}
34 gfx::RectF GetVisibleBounds() const override {
35 return *intersects_rect_ ? gfx::RectF(-1000, -1000, 2000, 2000)
36 : gfx::RectF(-1000, -1000, 0, 0);
39 private:
40 bool* intersects_rect_;
42 DISALLOW_COPY_AND_ASSIGN(MockTouchHandleDrawable);
45 } // namespace
47 class TouchSelectionControllerTest : public testing::Test,
48 public TouchSelectionControllerClient {
49 public:
50 TouchSelectionControllerTest()
51 : caret_moved_(false),
52 selection_moved_(false),
53 selection_points_swapped_(false),
54 needs_animate_(false),
55 animation_enabled_(true),
56 dragging_enabled_(false) {}
58 ~TouchSelectionControllerTest() override {}
60 // testing::Test implementation.
62 void SetUp() override {
63 controller_.reset(new TouchSelectionController(this, DefaultConfig()));
66 void TearDown() override { controller_.reset(); }
68 // TouchSelectionControllerClient implementation.
70 bool SupportsAnimation() const override { return animation_enabled_; }
72 void SetNeedsAnimate() override { needs_animate_ = true; }
74 void MoveCaret(const gfx::PointF& position) override {
75 caret_moved_ = true;
76 caret_position_ = position;
79 void SelectBetweenCoordinates(const gfx::PointF& base,
80 const gfx::PointF& extent) override {
81 if (base == selection_end_ && extent == selection_start_)
82 selection_points_swapped_ = true;
84 selection_start_ = base;
85 selection_end_ = extent;
88 void MoveRangeSelectionExtent(const gfx::PointF& extent) override {
89 selection_moved_ = true;
90 selection_end_ = extent;
93 void OnSelectionEvent(SelectionEventType event) override {
94 events_.push_back(event);
95 last_event_start_ = controller_->GetStartPosition();
96 last_event_end_ = controller_->GetEndPosition();
97 last_event_bounds_rect_ = controller_->GetRectBetweenBounds();
100 scoped_ptr<TouchHandleDrawable> CreateDrawable() override {
101 return make_scoped_ptr(new MockTouchHandleDrawable(&dragging_enabled_));
104 void AllowShowingOnTapForEmptyEditable() {
105 TouchSelectionController::Config config = DefaultConfig();
106 config.show_on_tap_for_empty_editable = true;
107 controller_.reset(new TouchSelectionController(this, config));
110 void EnableLongPressDragSelection() {
111 TouchSelectionController::Config config = DefaultConfig();
112 config.enable_longpress_drag_selection = true;
113 controller_.reset(new TouchSelectionController(this, config));
116 void SetAnimationEnabled(bool enabled) { animation_enabled_ = enabled; }
117 void SetDraggingEnabled(bool enabled) { dragging_enabled_ = enabled; }
119 void ClearSelection() {
120 controller_->OnSelectionBoundsChanged(SelectionBound(),
121 SelectionBound());
124 void ClearInsertion() { ClearSelection(); }
126 void ChangeInsertion(const gfx::RectF& rect, bool visible) {
127 SelectionBound bound;
128 bound.set_type(SelectionBound::CENTER);
129 bound.SetEdge(rect.origin(), rect.bottom_left());
130 bound.set_visible(visible);
131 controller_->OnSelectionBoundsChanged(bound, bound);
134 void ChangeSelection(const gfx::RectF& start_rect,
135 bool start_visible,
136 const gfx::RectF& end_rect,
137 bool end_visible) {
138 SelectionBound start_bound, end_bound;
139 start_bound.set_type(SelectionBound::LEFT);
140 end_bound.set_type(SelectionBound::RIGHT);
141 start_bound.SetEdge(start_rect.origin(), start_rect.bottom_left());
142 end_bound.SetEdge(end_rect.origin(), end_rect.bottom_left());
143 start_bound.set_visible(start_visible);
144 end_bound.set_visible(end_visible);
145 controller_->OnSelectionBoundsChanged(start_bound, end_bound);
148 void OnLongPressEvent() {
149 ASSERT_FALSE(controller().WillHandleLongPressEvent(base::TimeTicks(),
150 kIgnoredPoint));
153 void OnTapEvent() {
154 ASSERT_FALSE(controller().WillHandleTapEvent(kIgnoredPoint));
157 void Animate() {
158 base::TimeTicks now = base::TimeTicks::Now();
159 while (needs_animate_) {
160 needs_animate_ = controller_->Animate(now);
161 now += base::TimeDelta::FromMilliseconds(16);
165 bool GetAndResetNeedsAnimate() {
166 bool needs_animate = needs_animate_;
167 Animate();
168 return needs_animate;
171 bool GetAndResetCaretMoved() {
172 bool moved = caret_moved_;
173 caret_moved_ = false;
174 return moved;
177 bool GetAndResetSelectionMoved() {
178 bool moved = selection_moved_;
179 selection_moved_ = false;
180 return moved;
183 bool GetAndResetSelectionPointsSwapped() {
184 bool swapped = selection_points_swapped_;
185 selection_points_swapped_ = false;
186 return swapped;
189 const gfx::PointF& GetLastCaretPosition() const { return caret_position_; }
190 const gfx::PointF& GetLastSelectionStart() const { return selection_start_; }
191 const gfx::PointF& GetLastSelectionEnd() const { return selection_end_; }
192 const gfx::PointF& GetLastEventStart() const { return last_event_start_; }
193 const gfx::PointF& GetLastEventEnd() const { return last_event_end_; }
194 const gfx::RectF& GetLastEventBoundsRect() const {
195 return last_event_bounds_rect_;
198 std::vector<SelectionEventType> GetAndResetEvents() {
199 std::vector<SelectionEventType> events;
200 events.swap(events_);
201 return events;
204 TouchSelectionController& controller() { return *controller_; }
206 private:
207 TouchSelectionController::Config DefaultConfig() {
208 // Both |show_on_tap_for_empty_editable| and
209 // |enable_longpress_drag_selection| are set to false by default, and should
210 // be overriden for explicit testing.
211 TouchSelectionController::Config config;
212 config.max_tap_duration =
213 base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs);
214 config.tap_slop = kDefaulTapSlop;
215 config.show_on_tap_for_empty_editable = false;
216 config.enable_longpress_drag_selection = false;
217 return config;
220 gfx::PointF last_event_start_;
221 gfx::PointF last_event_end_;
222 gfx::PointF caret_position_;
223 gfx::PointF selection_start_;
224 gfx::PointF selection_end_;
225 gfx::RectF last_event_bounds_rect_;
226 std::vector<SelectionEventType> events_;
227 bool caret_moved_;
228 bool selection_moved_;
229 bool selection_points_swapped_;
230 bool needs_animate_;
231 bool animation_enabled_;
232 bool dragging_enabled_;
233 scoped_ptr<TouchSelectionController> controller_;
235 DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerTest);
238 TEST_F(TouchSelectionControllerTest, InsertionBasic) {
239 gfx::RectF insertion_rect(5, 5, 0, 10);
240 bool visible = true;
242 // Insertion handles are not shown until automatic showing is enabled.
243 ChangeInsertion(insertion_rect, visible);
244 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED));
245 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
246 OnTapEvent();
248 // Insertion handles are not shown until the selection region is
249 // marked editable.
250 ChangeInsertion(insertion_rect, visible);
251 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
252 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
254 OnTapEvent();
255 controller().OnSelectionEditable(true);
256 ChangeInsertion(insertion_rect, visible);
257 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN));
258 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventStart());
260 insertion_rect.Offset(1, 0);
261 ChangeInsertion(insertion_rect, visible);
262 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_MOVED));
263 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventStart());
265 insertion_rect.Offset(0, 1);
266 ChangeInsertion(insertion_rect, visible);
267 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_MOVED));
268 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventStart());
270 ClearInsertion();
271 EXPECT_THAT(GetAndResetEvents(),
272 ElementsAre(SELECTION_DISSOLVED, INSERTION_HANDLE_CLEARED));
275 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
276 gfx::RectF insertion_rect(5, 5, 0, 10);
277 bool visible = true;
278 OnTapEvent();
279 controller().OnSelectionEditable(true);
281 ChangeInsertion(insertion_rect, visible);
282 EXPECT_THAT(GetAndResetEvents(),
283 ElementsAre(SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
284 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventStart());
286 controller().OnSelectionEditable(false);
287 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_CLEARED));
290 TEST_F(TouchSelectionControllerTest, InsertionWithNoShowOnTapForEmptyEditable) {
291 gfx::RectF insertion_rect(5, 5, 0, 10);
292 bool visible = true;
293 controller().OnSelectionEditable(true);
295 // Taps on an empty editable region should be ignored if the controller is
296 // created with |show_on_tap_for_empty_editable| set to false.
297 OnTapEvent();
298 controller().OnSelectionEmpty(true);
299 ChangeInsertion(insertion_rect, visible);
300 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
302 // Once the region becomes non-empty, taps should show the insertion handle.
303 OnTapEvent();
304 controller().OnSelectionEmpty(false);
305 ChangeInsertion(insertion_rect, visible);
306 EXPECT_THAT(GetAndResetEvents(),
307 ElementsAre(SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
308 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventStart());
310 // Reset the selection.
311 controller().HideAndDisallowShowingAutomatically();
312 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_CLEARED));
314 // Long-pressing should show the handle even if the editable region is empty.
315 insertion_rect.Offset(2, -2);
316 OnLongPressEvent();
317 controller().OnSelectionEmpty(true);
318 ChangeInsertion(insertion_rect, visible);
319 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN));
320 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventStart());
322 // Single Tap on an empty edit field should clear insertion handle.
323 OnTapEvent();
324 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_CLEARED));
327 TEST_F(TouchSelectionControllerTest, InsertionWithShowOnTapForEmptyEditable) {
328 AllowShowingOnTapForEmptyEditable();
330 gfx::RectF insertion_rect(5, 5, 0, 10);
331 bool visible = true;
332 controller().OnSelectionEditable(true);
334 // Taps on an empty editable region should show the insertion handle if the
335 // controller is created with |show_on_tap_for_empty_editable| set to true.
336 OnTapEvent();
337 controller().OnSelectionEmpty(true);
338 ChangeInsertion(insertion_rect, visible);
339 EXPECT_THAT(GetAndResetEvents(),
340 ElementsAre(SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
341 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventStart());
343 // Additional taps should not hide the insertion handle in this case.
344 OnTapEvent();
345 ChangeInsertion(insertion_rect, visible);
346 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
349 TEST_F(TouchSelectionControllerTest, InsertionAppearsAfterTapFollowingTyping) {
350 gfx::RectF insertion_rect(5, 5, 0, 10);
351 bool visible = true;
353 // Simulate the user tapping an empty text field.
354 OnTapEvent();
355 controller().OnSelectionEditable(true);
356 controller().OnSelectionEmpty(true);
357 ChangeInsertion(insertion_rect, visible);
358 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
360 // Simulate the cursor moving while a user is typing.
361 insertion_rect.Offset(10, 0);
362 controller().OnSelectionEmpty(false);
363 ChangeInsertion(insertion_rect, visible);
364 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
366 // If the user taps the *same* position as the cursor at the end of the text
367 // entry, the handle should appear.
368 OnTapEvent();
369 ChangeInsertion(insertion_rect, visible);
370 EXPECT_THAT(GetAndResetEvents(),
371 ElementsAre(SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
372 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventStart());
375 TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
376 OnLongPressEvent();
377 controller().OnSelectionEditable(true);
379 gfx::RectF start_rect(5, 5, 0, 10);
380 gfx::RectF end_rect(50, 5, 0, 10);
381 bool visible = true;
383 ChangeInsertion(start_rect, visible);
384 EXPECT_THAT(GetAndResetEvents(),
385 ElementsAre(SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
386 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
388 ChangeSelection(start_rect, visible, end_rect, visible);
389 EXPECT_THAT(GetAndResetEvents(),
390 ElementsAre(INSERTION_HANDLE_CLEARED, SELECTION_HANDLES_SHOWN));
391 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
393 ChangeInsertion(end_rect, visible);
394 EXPECT_THAT(GetAndResetEvents(),
395 ElementsAre(SELECTION_HANDLES_CLEARED, INSERTION_HANDLE_SHOWN));
396 EXPECT_EQ(end_rect.bottom_left(), GetLastEventStart());
398 controller().HideAndDisallowShowingAutomatically();
399 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_CLEARED));
401 OnTapEvent();
402 ChangeInsertion(end_rect, visible);
403 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN));
404 EXPECT_EQ(end_rect.bottom_left(), GetLastEventStart());
407 TEST_F(TouchSelectionControllerTest, InsertionDragged) {
408 base::TimeTicks event_time = base::TimeTicks::Now();
409 OnTapEvent();
410 controller().OnSelectionEditable(true);
412 // The touch sequence should not be handled if insertion is not active.
413 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
414 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
416 float line_height = 10.f;
417 gfx::RectF start_rect(10, 0, 0, line_height);
418 bool visible = true;
419 ChangeInsertion(start_rect, visible);
420 EXPECT_THAT(GetAndResetEvents(),
421 ElementsAre(SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
422 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
424 // The touch sequence should be handled only if the drawable reports a hit.
425 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
426 SetDraggingEnabled(true);
427 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
428 EXPECT_FALSE(GetAndResetCaretMoved());
429 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED));
431 // The MoveCaret() result should reflect the movement.
432 // The reported position is offset from the center of |start_rect|.
433 gfx::PointF start_offset = start_rect.CenterPoint();
434 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
435 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
436 EXPECT_TRUE(GetAndResetCaretMoved());
437 EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition());
439 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
440 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
441 EXPECT_TRUE(GetAndResetCaretMoved());
442 EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastCaretPosition());
444 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 10);
445 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
446 EXPECT_TRUE(GetAndResetCaretMoved());
447 EXPECT_EQ(start_offset + gfx::Vector2dF(10, 10), GetLastCaretPosition());
449 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
450 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
451 EXPECT_FALSE(GetAndResetCaretMoved());
452 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STOPPED));
454 // Once the drag is complete, no more touch events should be consumed until
455 // the next ACTION_DOWN.
456 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
459 TEST_F(TouchSelectionControllerTest, InsertionTapped) {
460 base::TimeTicks event_time = base::TimeTicks::Now();
461 OnTapEvent();
462 controller().OnSelectionEditable(true);
463 SetDraggingEnabled(true);
465 gfx::RectF start_rect(10, 0, 0, 10);
466 bool visible = true;
467 ChangeInsertion(start_rect, visible);
468 EXPECT_THAT(GetAndResetEvents(),
469 ElementsAre(SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
471 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
472 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
473 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED));
475 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
476 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
477 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_TAPPED,
478 INSERTION_HANDLE_DRAG_STOPPED));
480 // Reset the insertion.
481 ClearInsertion();
482 OnTapEvent();
483 ChangeInsertion(start_rect, visible);
484 EXPECT_THAT(GetAndResetEvents(),
485 ElementsAre(SELECTION_DISSOLVED, INSERTION_HANDLE_CLEARED,
486 SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
488 // No tap should be signalled if the time between DOWN and UP was too long.
489 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
490 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
491 event = MockMotionEvent(MockMotionEvent::ACTION_UP,
492 event_time + base::TimeDelta::FromSeconds(1),
495 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
496 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED,
497 INSERTION_HANDLE_DRAG_STOPPED));
499 // Reset the insertion.
500 ClearInsertion();
501 OnTapEvent();
502 ChangeInsertion(start_rect, visible);
503 EXPECT_THAT(GetAndResetEvents(),
504 ElementsAre(SELECTION_DISSOLVED, INSERTION_HANDLE_CLEARED,
505 SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
507 // No tap should be signalled if the drag was too long.
508 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
509 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
510 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 100, 0);
511 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
512 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 100, 0);
513 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
514 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED,
515 INSERTION_HANDLE_DRAG_STOPPED));
517 // Reset the insertion.
518 ClearInsertion();
519 OnTapEvent();
520 ChangeInsertion(start_rect, visible);
521 EXPECT_THAT(GetAndResetEvents(),
522 ElementsAre(SELECTION_DISSOLVED, INSERTION_HANDLE_CLEARED,
523 SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
525 // No tap should be signalled if the touch sequence is cancelled.
526 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
527 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
528 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
529 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
530 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED,
531 INSERTION_HANDLE_DRAG_STOPPED));
534 TEST_F(TouchSelectionControllerTest, InsertionNotResetByRepeatedTapOrPress) {
535 base::TimeTicks event_time = base::TimeTicks::Now();
536 OnTapEvent();
537 controller().OnSelectionEditable(true);
538 SetDraggingEnabled(true);
540 gfx::RectF anchor_rect(10, 0, 0, 10);
541 bool visible = true;
542 ChangeInsertion(anchor_rect, visible);
543 EXPECT_THAT(GetAndResetEvents(),
544 ElementsAre(SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
545 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventStart());
547 // Tapping again shouldn't reset the active insertion point.
548 OnTapEvent();
549 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
550 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
551 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED));
552 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventStart());
554 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
555 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
556 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_TAPPED,
557 INSERTION_HANDLE_DRAG_STOPPED));
558 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventStart());
560 anchor_rect.Offset(5, 15);
561 ChangeInsertion(anchor_rect, visible);
562 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_MOVED));
563 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventStart());
565 // Pressing shouldn't reset the active insertion point.
566 OnLongPressEvent();
567 controller().OnSelectionEmpty(true);
568 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
569 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
570 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED));
571 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventStart());
573 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
574 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
575 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_TAPPED,
576 INSERTION_HANDLE_DRAG_STOPPED));
577 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventStart());
580 TEST_F(TouchSelectionControllerTest, SelectionBasic) {
581 gfx::RectF start_rect(5, 5, 0, 10);
582 gfx::RectF end_rect(50, 5, 0, 10);
583 bool visible = true;
585 // Selection events are ignored until automatic showing is enabled.
586 ChangeSelection(start_rect, visible, end_rect, visible);
587 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
589 OnLongPressEvent();
590 ChangeSelection(start_rect, visible, end_rect, visible);
591 EXPECT_THAT(GetAndResetEvents(),
592 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
593 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
595 start_rect.Offset(1, 0);
596 ChangeSelection(start_rect, visible, end_rect, visible);
597 // Selection movement does not currently trigger a separate event.
598 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED));
599 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
600 EXPECT_EQ(end_rect.bottom_left(), GetLastEventEnd());
602 ClearSelection();
603 EXPECT_THAT(GetAndResetEvents(),
604 ElementsAre(SELECTION_DISSOLVED, SELECTION_HANDLES_CLEARED));
605 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
608 TEST_F(TouchSelectionControllerTest, SelectionAllowsEmptyUpdateAfterLongPress) {
609 gfx::RectF start_rect(5, 5, 0, 10);
610 gfx::RectF end_rect(50, 5, 0, 10);
611 bool visible = true;
613 OnLongPressEvent();
614 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
616 // There may be several empty updates after a longpress due to the
617 // asynchronous response. These empty updates should not prevent the selection
618 // handles from (eventually) activating.
619 ClearSelection();
620 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
622 ClearSelection();
623 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
625 ChangeSelection(start_rect, visible, end_rect, visible);
626 EXPECT_THAT(GetAndResetEvents(),
627 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
630 TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) {
631 gfx::RectF start_rect(5, 5, 0, 10);
632 gfx::RectF end_rect(50, 5, 0, 10);
633 bool visible = true;
635 OnLongPressEvent();
636 ChangeSelection(start_rect, visible, end_rect, visible);
637 EXPECT_THAT(GetAndResetEvents(),
638 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
639 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
640 EXPECT_EQ(end_rect.bottom_left(), GetLastEventEnd());
642 // A long press triggering a new selection should re-send the
643 // SELECTION_HANDLES_SHOWN
644 // event notification.
645 start_rect.Offset(10, 10);
646 OnLongPressEvent();
647 ChangeSelection(start_rect, visible, end_rect, visible);
648 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN));
649 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
650 EXPECT_EQ(end_rect.bottom_left(), GetLastEventEnd());
653 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
654 base::TimeTicks event_time = base::TimeTicks::Now();
655 OnLongPressEvent();
657 // The touch sequence should not be handled if selection is not active.
658 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
659 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
661 float line_height = 10.f;
662 gfx::RectF start_rect(0, 0, 0, line_height);
663 gfx::RectF end_rect(50, 0, 0, line_height);
664 bool visible = true;
665 ChangeSelection(start_rect, visible, end_rect, visible);
666 EXPECT_THAT(GetAndResetEvents(),
667 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
668 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
670 // The touch sequence should be handled only if the drawable reports a hit.
671 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
672 SetDraggingEnabled(true);
673 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
674 EXPECT_FALSE(GetAndResetSelectionMoved());
676 // The SelectBetweenCoordinates() result should reflect the movement. Note
677 // that the start coordinate will always reflect the "fixed" handle's
678 // position, in this case the position from |end_rect|.
679 // Note that the reported position is offset from the center of the
680 // input rects (i.e., the middle of the corresponding text line).
681 gfx::PointF fixed_offset = end_rect.CenterPoint();
682 gfx::PointF start_offset = start_rect.CenterPoint();
683 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
684 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
685 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
686 EXPECT_TRUE(GetAndResetSelectionMoved());
687 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
688 EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
690 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
691 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
692 EXPECT_TRUE(GetAndResetSelectionMoved());
693 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
694 EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd());
696 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5);
697 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
698 EXPECT_TRUE(GetAndResetSelectionMoved());
699 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
700 EXPECT_EQ(start_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd());
702 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
703 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
704 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
705 EXPECT_FALSE(GetAndResetSelectionMoved());
707 // Once the drag is complete, no more touch events should be consumed until
708 // the next ACTION_DOWN.
709 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
712 TEST_F(TouchSelectionControllerTest, SelectionDraggedWithOverlap) {
713 base::TimeTicks event_time = base::TimeTicks::Now();
714 OnLongPressEvent();
716 float line_height = 10.f;
717 gfx::RectF start_rect(0, 0, 0, line_height);
718 gfx::RectF end_rect(50, 0, 0, line_height);
719 bool visible = true;
720 ChangeSelection(start_rect, visible, end_rect, visible);
721 EXPECT_THAT(GetAndResetEvents(),
722 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
723 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
725 // The ACTION_DOWN should lock to the closest handle.
726 gfx::PointF end_offset = end_rect.CenterPoint();
727 gfx::PointF fixed_offset = start_rect.CenterPoint();
728 float touch_down_x = (end_offset.x() + fixed_offset.x()) / 2 + 1.f;
729 MockMotionEvent event(
730 MockMotionEvent::ACTION_DOWN, event_time, touch_down_x, 0);
731 SetDraggingEnabled(true);
732 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
733 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
734 EXPECT_FALSE(GetAndResetSelectionMoved());
736 // Even though the ACTION_MOVE is over the start handle, it should continue
737 // targetting the end handle that consumed the ACTION_DOWN.
738 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 0);
739 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
740 EXPECT_TRUE(GetAndResetSelectionMoved());
741 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
742 EXPECT_EQ(end_offset - gfx::Vector2dF(touch_down_x, 0),
743 GetLastSelectionEnd());
745 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
746 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
747 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
748 EXPECT_FALSE(GetAndResetSelectionMoved());
751 TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) {
752 base::TimeTicks event_time = base::TimeTicks::Now();
753 OnLongPressEvent();
755 float line_height = 10.f;
756 gfx::RectF start_rect(50, line_height, 0, line_height);
757 gfx::RectF end_rect(100, line_height, 0, line_height);
758 bool visible = true;
759 ChangeSelection(start_rect, visible, end_rect, visible);
760 EXPECT_THAT(GetAndResetEvents(),
761 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
762 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
764 SetDraggingEnabled(true);
766 // Move the extent, not triggering a swap of points.
767 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time,
768 end_rect.x(), end_rect.bottom());
769 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
770 EXPECT_FALSE(GetAndResetSelectionMoved());
771 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
773 gfx::PointF base_offset = start_rect.CenterPoint();
774 gfx::PointF extent_offset = end_rect.CenterPoint();
775 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
776 end_rect.x(), end_rect.bottom() + 5);
777 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
778 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
779 EXPECT_TRUE(GetAndResetSelectionMoved());
780 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
781 EXPECT_EQ(base_offset, GetLastSelectionStart());
782 EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
784 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
785 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
786 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
787 EXPECT_FALSE(GetAndResetSelectionMoved());
789 end_rect += gfx::Vector2dF(0, 5);
790 ChangeSelection(start_rect, visible, end_rect, visible);
791 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED));
793 // Move the base, triggering a swap of points.
794 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time,
795 start_rect.x(), start_rect.bottom());
796 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
797 EXPECT_FALSE(GetAndResetSelectionMoved());
798 EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
800 base_offset = end_rect.CenterPoint();
801 extent_offset = start_rect.CenterPoint();
802 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
803 start_rect.x(), start_rect.bottom() + 5);
804 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
805 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
806 EXPECT_TRUE(GetAndResetSelectionMoved());
807 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
808 EXPECT_EQ(base_offset, GetLastSelectionStart());
809 EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
811 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
812 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
813 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
814 EXPECT_FALSE(GetAndResetSelectionMoved());
816 start_rect += gfx::Vector2dF(0, 5);
817 ChangeSelection(start_rect, visible, end_rect, visible);
818 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED));
820 // Move the same point again, not triggering a swap of points.
821 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time,
822 start_rect.x(), start_rect.bottom());
823 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
824 EXPECT_FALSE(GetAndResetSelectionMoved());
825 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
827 base_offset = end_rect.CenterPoint();
828 extent_offset = start_rect.CenterPoint();
829 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
830 start_rect.x(), start_rect.bottom() + 5);
831 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
832 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
833 EXPECT_TRUE(GetAndResetSelectionMoved());
834 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
835 EXPECT_EQ(base_offset, GetLastSelectionStart());
836 EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
838 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
839 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
840 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
841 EXPECT_FALSE(GetAndResetSelectionMoved());
843 start_rect += gfx::Vector2dF(0, 5);
844 ChangeSelection(start_rect, visible, end_rect, visible);
845 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED));
847 // Move the base, triggering a swap of points.
848 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time,
849 end_rect.x(), end_rect.bottom());
850 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
851 EXPECT_FALSE(GetAndResetSelectionMoved());
852 EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
854 base_offset = start_rect.CenterPoint();
855 extent_offset = end_rect.CenterPoint();
856 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
857 end_rect.x(), end_rect.bottom() + 5);
858 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
859 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
860 EXPECT_TRUE(GetAndResetSelectionMoved());
861 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
862 EXPECT_EQ(base_offset, GetLastSelectionStart());
863 EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
865 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
866 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
867 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
868 EXPECT_FALSE(GetAndResetSelectionMoved());
871 TEST_F(TouchSelectionControllerTest, SelectionDragExtremeLineSize) {
872 base::TimeTicks event_time = base::TimeTicks::Now();
873 OnLongPressEvent();
875 float small_line_height = 1.f;
876 float large_line_height = 50.f;
877 gfx::RectF small_line_rect(0, 0, 0, small_line_height);
878 gfx::RectF large_line_rect(50, 50, 0, large_line_height);
879 bool visible = true;
880 ChangeSelection(small_line_rect, visible, large_line_rect, visible);
881 EXPECT_THAT(GetAndResetEvents(),
882 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
883 EXPECT_EQ(small_line_rect.bottom_left(), GetLastEventStart());
885 // Start dragging the handle on the small line.
886 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time,
887 small_line_rect.x(), small_line_rect.y());
888 SetDraggingEnabled(true);
889 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
890 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
891 // The drag coordinate for large lines should be capped to a reasonable
892 // offset, allowing seamless transition to neighboring lines with different
893 // sizes. The drag coordinate for small lines should have an offset
894 // commensurate with the small line size.
895 EXPECT_EQ(large_line_rect.bottom_left() - gfx::Vector2dF(0, 8.f),
896 GetLastSelectionStart());
897 EXPECT_EQ(small_line_rect.CenterPoint(), GetLastSelectionEnd());
899 small_line_rect += gfx::Vector2dF(25.f, 0);
900 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
901 small_line_rect.x(), small_line_rect.y());
902 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
903 EXPECT_TRUE(GetAndResetSelectionMoved());
904 EXPECT_EQ(small_line_rect.CenterPoint(), GetLastSelectionEnd());
907 TEST_F(TouchSelectionControllerTest, Animation) {
908 OnTapEvent();
909 controller().OnSelectionEditable(true);
911 gfx::RectF insertion_rect(5, 5, 0, 10);
913 bool visible = true;
914 ChangeInsertion(insertion_rect, visible);
915 EXPECT_FALSE(GetAndResetNeedsAnimate());
917 visible = false;
918 ChangeInsertion(insertion_rect, visible);
919 EXPECT_TRUE(GetAndResetNeedsAnimate());
921 visible = true;
922 ChangeInsertion(insertion_rect, visible);
923 EXPECT_TRUE(GetAndResetNeedsAnimate());
925 // If the handles are explicity hidden, no animation should be triggered.
926 controller().HideAndDisallowShowingAutomatically();
927 EXPECT_FALSE(GetAndResetNeedsAnimate());
929 // If the client doesn't support animation, no animation should be triggered.
930 SetAnimationEnabled(false);
931 OnTapEvent();
932 visible = true;
933 ChangeInsertion(insertion_rect, visible);
934 EXPECT_FALSE(GetAndResetNeedsAnimate());
937 TEST_F(TouchSelectionControllerTest, TemporarilyHidden) {
938 TouchSelectionControllerTestApi test_controller(&controller());
940 OnTapEvent();
941 controller().OnSelectionEditable(true);
943 gfx::RectF insertion_rect(5, 5, 0, 10);
945 bool visible = true;
946 ChangeInsertion(insertion_rect, visible);
947 EXPECT_FALSE(GetAndResetNeedsAnimate());
948 EXPECT_TRUE(test_controller.GetStartVisible());
949 EXPECT_TRUE(test_controller.GetEndVisible());
951 controller().SetTemporarilyHidden(true);
952 EXPECT_TRUE(GetAndResetNeedsAnimate());
953 EXPECT_FALSE(test_controller.GetStartVisible());
954 EXPECT_FALSE(test_controller.GetEndVisible());
956 visible = false;
957 ChangeInsertion(insertion_rect, visible);
958 EXPECT_FALSE(GetAndResetNeedsAnimate());
959 EXPECT_FALSE(test_controller.GetStartVisible());
961 visible = true;
962 ChangeInsertion(insertion_rect, visible);
963 EXPECT_FALSE(GetAndResetNeedsAnimate());
964 EXPECT_FALSE(test_controller.GetStartVisible());
966 controller().SetTemporarilyHidden(false);
967 EXPECT_TRUE(GetAndResetNeedsAnimate());
968 EXPECT_TRUE(test_controller.GetStartVisible());
971 TEST_F(TouchSelectionControllerTest, SelectionClearOnTap) {
972 gfx::RectF start_rect(5, 5, 0, 10);
973 gfx::RectF end_rect(50, 5, 0, 10);
974 bool visible = true;
976 OnLongPressEvent();
977 ChangeSelection(start_rect, visible, end_rect, visible);
978 EXPECT_THAT(GetAndResetEvents(),
979 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
981 // Selection should not be cleared if the selection bounds have not changed.
982 OnTapEvent();
983 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
984 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
986 OnTapEvent();
987 ClearSelection();
988 EXPECT_THAT(GetAndResetEvents(),
989 ElementsAre(SELECTION_DISSOLVED, SELECTION_HANDLES_CLEARED));
990 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
993 TEST_F(TouchSelectionControllerTest, NoSelectionAfterLongpressThenTap) {
994 gfx::RectF start_rect(5, 5, 0, 10);
995 gfx::RectF end_rect(50, 5, 0, 10);
996 bool visible = true;
998 // Tap-triggered selections should not be allowed.
999 OnLongPressEvent();
1000 OnTapEvent();
1001 ChangeSelection(start_rect, visible, end_rect, visible);
1002 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED));
1004 // Subsequent longpress selections will be allowed.
1005 OnLongPressEvent();
1006 ChangeSelection(start_rect, visible, end_rect, visible);
1007 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN));
1009 // Tapping again shouldn't have any effect on subsequent selection events.
1010 OnTapEvent();
1011 end_rect.Offset(10, 10);
1012 ChangeSelection(start_rect, visible, end_rect, visible);
1013 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED));
1014 ClearSelection();
1015 EXPECT_THAT(GetAndResetEvents(),
1016 ElementsAre(SELECTION_DISSOLVED, SELECTION_HANDLES_CLEARED));
1019 TEST_F(TouchSelectionControllerTest, AllowShowingFromCurrentSelection) {
1020 gfx::RectF start_rect(5, 5, 0, 10);
1021 gfx::RectF end_rect(50, 5, 0, 10);
1022 bool visible = true;
1024 // The selection should not be activated, as it wasn't yet allowed.
1025 ChangeSelection(start_rect, visible, end_rect, visible);
1026 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
1028 // A longpress should have no immediate effect.
1029 OnLongPressEvent();
1031 // Now explicitly allow showing from the previously supplied bounds.
1032 controller().AllowShowingFromCurrentSelection();
1033 EXPECT_THAT(GetAndResetEvents(),
1034 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
1035 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
1037 // Repeated calls to show from the current selection should be ignored.
1038 controller().AllowShowingFromCurrentSelection();
1039 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1040 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
1042 // Trying to show from an empty selection will have no result.
1043 ClearSelection();
1044 EXPECT_THAT(GetAndResetEvents(),
1045 ElementsAre(SELECTION_DISSOLVED, SELECTION_HANDLES_CLEARED));
1046 controller().AllowShowingFromCurrentSelection();
1047 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1049 // Showing the insertion handle should also be supported.
1050 controller().OnSelectionEditable(true);
1051 controller().OnSelectionEmpty(false);
1052 controller().HideAndDisallowShowingAutomatically();
1053 gfx::RectF insertion_rect(5, 5, 0, 10);
1054 ChangeInsertion(insertion_rect, visible);
1055 controller().AllowShowingFromCurrentSelection();
1056 EXPECT_THAT(GetAndResetEvents(),
1057 ElementsAre(SELECTION_ESTABLISHED, INSERTION_HANDLE_SHOWN));
1058 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventStart());
1061 TEST_F(TouchSelectionControllerTest, HandlesShowOnTapInsideRect) {
1062 bool visible = false;
1063 gfx::RectF start_rect(5, 5, 0, 10);
1064 gfx::RectF end_rect(50, 5, 0, 10);
1065 gfx::PointF inner_point(25, 10);
1066 gfx::PointF outer_point(100, 100);
1068 // Establish a selection without handles from 5 to 50 with height 10.
1069 ChangeSelection(start_rect, visible, end_rect, visible);
1070 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED));
1072 // A point outside the rect should not be handled.
1073 EXPECT_FALSE(controller().WillHandleTapEvent(outer_point));
1074 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1076 // A point inside the rect should be handled.
1077 EXPECT_TRUE(controller().WillHandleTapEvent(inner_point));
1078 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN));
1081 TEST_F(TouchSelectionControllerTest, HandlesShowOnLongPressInsideRect) {
1082 bool visible = false;
1083 gfx::RectF start_rect(5, 5, 0, 10);
1084 gfx::RectF end_rect(50, 5, 0, 10);
1085 gfx::PointF inner_point(25, 10);
1086 gfx::PointF outer_point(100, 100);
1088 // Establish a selection without handles from 5 to 50 with height 10.
1089 ChangeSelection(start_rect, visible, end_rect, visible);
1090 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED));
1092 // A point outside the rect should not be handled.
1093 EXPECT_FALSE(
1094 controller().WillHandleLongPressEvent(base::TimeTicks(), outer_point));
1095 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1097 // A point inside the rect should be handled.
1098 EXPECT_TRUE(
1099 controller().WillHandleLongPressEvent(base::TimeTicks(), inner_point));
1100 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN));
1103 TEST_F(TouchSelectionControllerTest, LongPressDrag) {
1104 EnableLongPressDragSelection();
1105 TouchSelectionControllerTestApi test_controller(&controller());
1107 gfx::RectF start_rect(-50, 0, 0, 10);
1108 gfx::RectF end_rect(50, 0, 0, 10);
1109 bool visible = true;
1111 // Start a touch sequence.
1112 MockMotionEvent event;
1113 EXPECT_FALSE(controller().WillHandleTouchEvent(event.PressPoint(0, 0)));
1115 // Activate a longpress-triggered selection.
1116 OnLongPressEvent();
1117 ChangeSelection(start_rect, visible, end_rect, visible);
1118 EXPECT_THAT(GetAndResetEvents(),
1119 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
1120 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
1122 // The handles should remain invisible while the touch release and longpress
1123 // drag gesture are pending.
1124 EXPECT_FALSE(test_controller.GetStartVisible());
1125 EXPECT_FALSE(test_controller.GetEndVisible());
1127 // The selection coordinates should reflect the drag movement.
1128 gfx::PointF fixed_offset = start_rect.CenterPoint();
1129 gfx::PointF end_offset = end_rect.CenterPoint();
1130 EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 0, 0)));
1131 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1133 EXPECT_TRUE(
1134 controller().WillHandleTouchEvent(event.MovePoint(0, 0, kDefaulTapSlop)));
1135 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
1136 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
1137 EXPECT_EQ(end_offset, GetLastSelectionEnd());
1139 // Movement after the start of drag will be relative to the moved endpoint.
1140 EXPECT_TRUE(controller().WillHandleTouchEvent(
1141 event.MovePoint(0, 0, 2 * kDefaulTapSlop)));
1142 EXPECT_TRUE(GetAndResetSelectionMoved());
1143 EXPECT_EQ(end_offset + gfx::Vector2dF(0, kDefaulTapSlop),
1144 GetLastSelectionEnd());
1146 EXPECT_TRUE(controller().WillHandleTouchEvent(
1147 event.MovePoint(0, kDefaulTapSlop, 2 * kDefaulTapSlop)));
1148 EXPECT_TRUE(GetAndResetSelectionMoved());
1149 EXPECT_EQ(end_offset + gfx::Vector2dF(kDefaulTapSlop, kDefaulTapSlop),
1150 GetLastSelectionEnd());
1152 EXPECT_TRUE(controller().WillHandleTouchEvent(
1153 event.MovePoint(0, 2 * kDefaulTapSlop, 2 * kDefaulTapSlop)));
1154 EXPECT_TRUE(GetAndResetSelectionMoved());
1155 EXPECT_EQ(end_offset + gfx::Vector2dF(2 * kDefaulTapSlop, kDefaulTapSlop),
1156 GetLastSelectionEnd());
1158 // The handles should still be hidden.
1159 EXPECT_FALSE(test_controller.GetStartVisible());
1160 EXPECT_FALSE(test_controller.GetEndVisible());
1162 // Releasing the touch sequence should end the drag and show the handles.
1163 EXPECT_FALSE(controller().WillHandleTouchEvent(event.ReleasePoint()));
1164 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
1165 EXPECT_TRUE(test_controller.GetStartVisible());
1166 EXPECT_TRUE(test_controller.GetEndVisible());
1169 TEST_F(TouchSelectionControllerTest, LongPressNoDrag) {
1170 EnableLongPressDragSelection();
1171 TouchSelectionControllerTestApi test_controller(&controller());
1173 gfx::RectF start_rect(-50, 0, 0, 10);
1174 gfx::RectF end_rect(50, 0, 0, 10);
1175 bool visible = true;
1177 // Start a touch sequence.
1178 MockMotionEvent event;
1179 EXPECT_FALSE(controller().WillHandleTouchEvent(event.PressPoint(0, 0)));
1181 // Activate a longpress-triggered selection.
1182 OnLongPressEvent();
1183 ChangeSelection(start_rect, visible, end_rect, visible);
1184 EXPECT_THAT(GetAndResetEvents(),
1185 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
1186 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
1188 // The handles should remain invisible while the touch release and longpress
1189 // drag gesture are pending.
1190 EXPECT_FALSE(test_controller.GetStartVisible());
1191 EXPECT_FALSE(test_controller.GetEndVisible());
1193 // If no drag movement occurs, the handles should reappear after the touch
1194 // is released.
1195 EXPECT_FALSE(controller().WillHandleTouchEvent(event.ReleasePoint()));
1196 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1197 EXPECT_TRUE(test_controller.GetStartVisible());
1198 EXPECT_TRUE(test_controller.GetEndVisible());
1201 TEST_F(TouchSelectionControllerTest, NoLongPressDragIfDisabled) {
1202 // The TouchSelectionController disables longpress drag selection by default.
1203 TouchSelectionControllerTestApi test_controller(&controller());
1205 gfx::RectF start_rect(-50, 0, 0, 10);
1206 gfx::RectF end_rect(50, 0, 0, 10);
1207 bool visible = true;
1209 // Start a touch sequence.
1210 MockMotionEvent event;
1211 EXPECT_FALSE(controller().WillHandleTouchEvent(event.PressPoint(0, 0)));
1213 // Activate a longpress-triggered selection.
1214 OnLongPressEvent();
1215 ChangeSelection(start_rect, visible, end_rect, visible);
1216 EXPECT_THAT(GetAndResetEvents(),
1217 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
1218 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
1219 EXPECT_TRUE(test_controller.GetStartVisible());
1220 EXPECT_TRUE(test_controller.GetEndVisible());
1222 // Subsequent motion of the same touch sequence after longpress shouldn't
1223 // trigger drag selection.
1224 EXPECT_FALSE(controller().WillHandleTouchEvent(event.MovePoint(0, 0, 0)));
1225 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1227 EXPECT_FALSE(controller().WillHandleTouchEvent(
1228 event.MovePoint(0, 0, kDefaulTapSlop * 10)));
1229 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1231 // Releasing the touch sequence should have no effect.
1232 EXPECT_FALSE(controller().WillHandleTouchEvent(event.ReleasePoint()));
1233 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1234 EXPECT_TRUE(test_controller.GetStartVisible());
1235 EXPECT_TRUE(test_controller.GetEndVisible());
1238 TEST_F(TouchSelectionControllerTest, RectBetweenBounds) {
1239 gfx::RectF start_rect(5, 5, 0, 10);
1240 gfx::RectF end_rect(50, 5, 0, 10);
1241 bool visible = true;
1243 EXPECT_EQ(gfx::RectF(), controller().GetRectBetweenBounds());
1245 OnLongPressEvent();
1246 ChangeSelection(start_rect, visible, end_rect, visible);
1247 ASSERT_THAT(GetAndResetEvents(),
1248 ElementsAre(SELECTION_ESTABLISHED, SELECTION_HANDLES_SHOWN));
1249 EXPECT_EQ(gfx::RectF(5, 5, 45, 10), controller().GetRectBetweenBounds());
1251 // The result of |GetRectBetweenBounds| should be available within the
1252 // |OnSelectionEvent| callback, as stored by |GetLastEventBoundsRect()|.
1253 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1255 start_rect.Offset(1, 0);
1256 ChangeSelection(start_rect, visible, end_rect, visible);
1257 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED));
1258 EXPECT_EQ(gfx::RectF(6, 5, 44, 10), controller().GetRectBetweenBounds());
1259 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1261 // If only one bound is visible, the selection bounding rect should reflect
1262 // only the visible bound.
1263 ChangeSelection(start_rect, visible, end_rect, false);
1264 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED));
1265 EXPECT_EQ(start_rect, controller().GetRectBetweenBounds());
1266 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1268 ChangeSelection(start_rect, false, end_rect, visible);
1269 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED));
1270 EXPECT_EQ(end_rect, controller().GetRectBetweenBounds());
1271 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1273 // If both bounds are visible, the full bounding rect should be returned.
1274 ChangeSelection(start_rect, false, end_rect, false);
1275 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED));
1276 EXPECT_EQ(gfx::RectF(6, 5, 44, 10), controller().GetRectBetweenBounds());
1277 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1279 ClearSelection();
1280 ASSERT_THAT(GetAndResetEvents(),
1281 ElementsAre(SELECTION_DISSOLVED, SELECTION_HANDLES_CLEARED));
1282 EXPECT_EQ(gfx::RectF(), controller().GetRectBetweenBounds());
1285 } // namespace ui