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"
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"
13 using testing::ElementsAre
;
14 using testing::IsEmpty
;
15 using ui::test::MockMotionEvent
;
20 const int kDefaultTapTimeoutMs
= 200;
21 const float kDefaulTapSlop
= 10.f
;
22 const gfx::PointF
kIgnoredPoint(0, 0);
24 class MockTouchHandleDrawable
: public TouchHandleDrawable
{
26 explicit MockTouchHandleDrawable(bool* contains_point
)
27 : intersects_rect_(contains_point
) {}
28 ~MockTouchHandleDrawable() override
{}
29 void SetEnabled(bool enabled
) override
{}
30 void SetOrientation(TouchHandleOrientation orientation
) override
{}
31 void SetAlpha(float alpha
) override
{}
32 void SetFocus(const gfx::PointF
& position
) override
{}
33 gfx::RectF
GetVisibleBounds() const override
{
34 return *intersects_rect_
? gfx::RectF(-1000, -1000, 2000, 2000)
35 : gfx::RectF(-1000, -1000, 0, 0);
39 bool* intersects_rect_
;
41 DISALLOW_COPY_AND_ASSIGN(MockTouchHandleDrawable
);
46 class TouchSelectionControllerTestApi
{
48 explicit TouchSelectionControllerTestApi(TouchSelectionController
* controller
)
49 : controller_(controller
) {}
50 ~TouchSelectionControllerTestApi() {}
52 bool GetStartVisible() const { return controller_
->GetStartVisible(); }
53 bool GetEndVisible() const { return controller_
->GetEndVisible(); }
56 TouchSelectionController
* controller_
;
58 DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerTestApi
);
61 class TouchSelectionControllerTest
: public testing::Test
,
62 public TouchSelectionControllerClient
{
64 TouchSelectionControllerTest()
65 : caret_moved_(false),
66 selection_moved_(false),
67 selection_points_swapped_(false),
68 needs_animate_(false),
69 animation_enabled_(true),
70 dragging_enabled_(false) {}
72 ~TouchSelectionControllerTest() override
{}
74 // testing::Test implementation.
76 void SetUp() override
{
77 controller_
.reset(new TouchSelectionController(this, DefaultConfig()));
80 void TearDown() override
{ controller_
.reset(); }
82 // TouchSelectionControllerClient implementation.
84 bool SupportsAnimation() const override
{ return animation_enabled_
; }
86 void SetNeedsAnimate() override
{ needs_animate_
= true; }
88 void MoveCaret(const gfx::PointF
& position
) override
{
90 caret_position_
= position
;
93 void SelectBetweenCoordinates(const gfx::PointF
& base
,
94 const gfx::PointF
& extent
) override
{
95 if (base
== selection_end_
&& extent
== selection_start_
)
96 selection_points_swapped_
= true;
98 selection_start_
= base
;
99 selection_end_
= extent
;
102 void MoveRangeSelectionExtent(const gfx::PointF
& extent
) override
{
103 selection_moved_
= true;
104 selection_end_
= extent
;
107 void OnSelectionEvent(SelectionEventType event
) override
{
108 events_
.push_back(event
);
109 last_event_start_
= controller_
->GetStartPosition();
110 last_event_end_
= controller_
->GetEndPosition();
111 last_event_bounds_rect_
= controller_
->GetRectBetweenBounds();
114 scoped_ptr
<TouchHandleDrawable
> CreateDrawable() override
{
115 return make_scoped_ptr(new MockTouchHandleDrawable(&dragging_enabled_
));
118 void AllowShowingOnTapForEmptyEditable() {
119 TouchSelectionController::Config config
= DefaultConfig();
120 config
.show_on_tap_for_empty_editable
= true;
121 controller_
.reset(new TouchSelectionController(this, config
));
124 void EnableLongPressDragSelection() {
125 TouchSelectionController::Config config
= DefaultConfig();
126 config
.enable_longpress_drag_selection
= true;
127 controller_
.reset(new TouchSelectionController(this, config
));
130 void SetAnimationEnabled(bool enabled
) { animation_enabled_
= enabled
; }
131 void SetDraggingEnabled(bool enabled
) { dragging_enabled_
= enabled
; }
133 void ClearSelection() {
134 controller_
->OnSelectionBoundsChanged(SelectionBound(),
138 void ClearInsertion() { ClearSelection(); }
140 void ChangeInsertion(const gfx::RectF
& rect
, bool visible
) {
141 SelectionBound bound
;
142 bound
.set_type(SelectionBound::CENTER
);
143 bound
.SetEdge(rect
.origin(), rect
.bottom_left());
144 bound
.set_visible(visible
);
145 controller_
->OnSelectionBoundsChanged(bound
, bound
);
148 void ChangeSelection(const gfx::RectF
& start_rect
,
150 const gfx::RectF
& end_rect
,
152 SelectionBound start_bound
, end_bound
;
153 start_bound
.set_type(SelectionBound::LEFT
);
154 end_bound
.set_type(SelectionBound::RIGHT
);
155 start_bound
.SetEdge(start_rect
.origin(), start_rect
.bottom_left());
156 end_bound
.SetEdge(end_rect
.origin(), end_rect
.bottom_left());
157 start_bound
.set_visible(start_visible
);
158 end_bound
.set_visible(end_visible
);
159 controller_
->OnSelectionBoundsChanged(start_bound
, end_bound
);
162 void OnLongPressEvent() {
163 ASSERT_FALSE(controller().WillHandleLongPressEvent(base::TimeTicks(),
168 ASSERT_FALSE(controller().WillHandleTapEvent(kIgnoredPoint
));
172 base::TimeTicks now
= base::TimeTicks::Now();
173 while (needs_animate_
) {
174 needs_animate_
= controller_
->Animate(now
);
175 now
+= base::TimeDelta::FromMilliseconds(16);
179 bool GetAndResetNeedsAnimate() {
180 bool needs_animate
= needs_animate_
;
182 return needs_animate
;
185 bool GetAndResetCaretMoved() {
186 bool moved
= caret_moved_
;
187 caret_moved_
= false;
191 bool GetAndResetSelectionMoved() {
192 bool moved
= selection_moved_
;
193 selection_moved_
= false;
197 bool GetAndResetSelectionPointsSwapped() {
198 bool swapped
= selection_points_swapped_
;
199 selection_points_swapped_
= false;
203 const gfx::PointF
& GetLastCaretPosition() const { return caret_position_
; }
204 const gfx::PointF
& GetLastSelectionStart() const { return selection_start_
; }
205 const gfx::PointF
& GetLastSelectionEnd() const { return selection_end_
; }
206 const gfx::PointF
& GetLastEventStart() const { return last_event_start_
; }
207 const gfx::PointF
& GetLastEventEnd() const { return last_event_end_
; }
208 const gfx::RectF
& GetLastEventBoundsRect() const {
209 return last_event_bounds_rect_
;
212 std::vector
<SelectionEventType
> GetAndResetEvents() {
213 std::vector
<SelectionEventType
> events
;
214 events
.swap(events_
);
218 TouchSelectionController
& controller() { return *controller_
; }
221 TouchSelectionController::Config
DefaultConfig() {
222 // Both |show_on_tap_for_empty_editable| and
223 // |enable_longpress_drag_selection| are set to false by default, and should
224 // be overriden for explicit testing.
225 TouchSelectionController::Config config
;
227 base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs
);
228 config
.tap_slop
= kDefaulTapSlop
;
229 config
.show_on_tap_for_empty_editable
= false;
230 config
.enable_longpress_drag_selection
= false;
234 gfx::PointF last_event_start_
;
235 gfx::PointF last_event_end_
;
236 gfx::PointF caret_position_
;
237 gfx::PointF selection_start_
;
238 gfx::PointF selection_end_
;
239 gfx::RectF last_event_bounds_rect_
;
240 std::vector
<SelectionEventType
> events_
;
242 bool selection_moved_
;
243 bool selection_points_swapped_
;
245 bool animation_enabled_
;
246 bool dragging_enabled_
;
247 scoped_ptr
<TouchSelectionController
> controller_
;
249 DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerTest
);
252 TEST_F(TouchSelectionControllerTest
, InsertionBasic
) {
253 gfx::RectF
insertion_rect(5, 5, 0, 10);
256 // Insertion handles are not shown until automatic showing is enabled.
257 ChangeInsertion(insertion_rect
, visible
);
258 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED
));
259 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
262 // Insertion handles are not shown until the selection region is
264 ChangeInsertion(insertion_rect
, visible
);
265 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
266 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
269 controller().OnSelectionEditable(true);
270 ChangeInsertion(insertion_rect
, visible
);
271 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN
));
272 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
274 insertion_rect
.Offset(1, 0);
275 ChangeInsertion(insertion_rect
, visible
);
276 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_MOVED
));
277 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
279 insertion_rect
.Offset(0, 1);
280 ChangeInsertion(insertion_rect
, visible
);
281 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_MOVED
));
282 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
285 EXPECT_THAT(GetAndResetEvents(),
286 ElementsAre(SELECTION_DISSOLVED
, INSERTION_HANDLE_CLEARED
));
289 TEST_F(TouchSelectionControllerTest
, InsertionClearedWhenNoLongerEditable
) {
290 gfx::RectF
insertion_rect(5, 5, 0, 10);
293 controller().OnSelectionEditable(true);
295 ChangeInsertion(insertion_rect
, visible
);
296 EXPECT_THAT(GetAndResetEvents(),
297 ElementsAre(SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
298 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
300 controller().OnSelectionEditable(false);
301 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_CLEARED
));
304 TEST_F(TouchSelectionControllerTest
, InsertionWithNoShowOnTapForEmptyEditable
) {
305 gfx::RectF
insertion_rect(5, 5, 0, 10);
307 controller().OnSelectionEditable(true);
309 // Taps on an empty editable region should be ignored if the controller is
310 // created with |show_on_tap_for_empty_editable| set to false.
312 controller().OnSelectionEmpty(true);
313 ChangeInsertion(insertion_rect
, visible
);
314 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
316 // Once the region becomes non-empty, taps should show the insertion handle.
318 controller().OnSelectionEmpty(false);
319 ChangeInsertion(insertion_rect
, visible
);
320 EXPECT_THAT(GetAndResetEvents(),
321 ElementsAre(SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
322 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
324 // Reset the selection.
325 controller().HideAndDisallowShowingAutomatically();
326 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_CLEARED
));
328 // Long-pressing should show the handle even if the editable region is empty.
329 insertion_rect
.Offset(2, -2);
331 controller().OnSelectionEmpty(true);
332 ChangeInsertion(insertion_rect
, visible
);
333 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN
));
334 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
336 // Single Tap on an empty edit field should clear insertion handle.
338 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_CLEARED
));
341 TEST_F(TouchSelectionControllerTest
, InsertionWithShowOnTapForEmptyEditable
) {
342 AllowShowingOnTapForEmptyEditable();
344 gfx::RectF
insertion_rect(5, 5, 0, 10);
346 controller().OnSelectionEditable(true);
348 // Taps on an empty editable region should show the insertion handle if the
349 // controller is created with |show_on_tap_for_empty_editable| set to true.
351 controller().OnSelectionEmpty(true);
352 ChangeInsertion(insertion_rect
, visible
);
353 EXPECT_THAT(GetAndResetEvents(),
354 ElementsAre(SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
355 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
357 // Additional taps should not hide the insertion handle in this case.
359 ChangeInsertion(insertion_rect
, visible
);
360 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
363 TEST_F(TouchSelectionControllerTest
, InsertionAppearsAfterTapFollowingTyping
) {
364 gfx::RectF
insertion_rect(5, 5, 0, 10);
367 // Simulate the user tapping an empty text field.
369 controller().OnSelectionEditable(true);
370 controller().OnSelectionEmpty(true);
371 ChangeInsertion(insertion_rect
, visible
);
372 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
374 // Simulate the cursor moving while a user is typing.
375 insertion_rect
.Offset(10, 0);
376 controller().OnSelectionEmpty(false);
377 ChangeInsertion(insertion_rect
, visible
);
378 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
380 // If the user taps the *same* position as the cursor at the end of the text
381 // entry, the handle should appear.
383 ChangeInsertion(insertion_rect
, visible
);
384 EXPECT_THAT(GetAndResetEvents(),
385 ElementsAre(SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
386 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
389 TEST_F(TouchSelectionControllerTest
, InsertionToSelectionTransition
) {
391 controller().OnSelectionEditable(true);
393 gfx::RectF
start_rect(5, 5, 0, 10);
394 gfx::RectF
end_rect(50, 5, 0, 10);
397 ChangeInsertion(start_rect
, visible
);
398 EXPECT_THAT(GetAndResetEvents(),
399 ElementsAre(SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
400 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
402 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
403 EXPECT_THAT(GetAndResetEvents(),
404 ElementsAre(INSERTION_HANDLE_CLEARED
, SELECTION_HANDLES_SHOWN
));
405 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
407 ChangeInsertion(end_rect
, visible
);
408 EXPECT_THAT(GetAndResetEvents(),
409 ElementsAre(SELECTION_HANDLES_CLEARED
, INSERTION_HANDLE_SHOWN
));
410 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventStart());
412 controller().HideAndDisallowShowingAutomatically();
413 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_CLEARED
));
416 ChangeInsertion(end_rect
, visible
);
417 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN
));
418 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventStart());
421 TEST_F(TouchSelectionControllerTest
, InsertionDragged
) {
422 base::TimeTicks event_time
= base::TimeTicks::Now();
424 controller().OnSelectionEditable(true);
426 // The touch sequence should not be handled if insertion is not active.
427 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
428 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
430 float line_height
= 10.f
;
431 gfx::RectF
start_rect(10, 0, 0, line_height
);
433 ChangeInsertion(start_rect
, visible
);
434 EXPECT_THAT(GetAndResetEvents(),
435 ElementsAre(SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
436 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
438 // The touch sequence should be handled only if the drawable reports a hit.
439 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
440 SetDraggingEnabled(true);
441 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
442 EXPECT_FALSE(GetAndResetCaretMoved());
443 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED
));
445 // The MoveCaret() result should reflect the movement.
446 // The reported position is offset from the center of |start_rect|.
447 gfx::PointF start_offset
= start_rect
.CenterPoint();
448 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 0, 5);
449 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
450 EXPECT_TRUE(GetAndResetCaretMoved());
451 EXPECT_EQ(start_offset
+ gfx::Vector2dF(0, 5), GetLastCaretPosition());
453 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 5, 5);
454 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
455 EXPECT_TRUE(GetAndResetCaretMoved());
456 EXPECT_EQ(start_offset
+ gfx::Vector2dF(5, 5), GetLastCaretPosition());
458 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 10, 10);
459 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
460 EXPECT_TRUE(GetAndResetCaretMoved());
461 EXPECT_EQ(start_offset
+ gfx::Vector2dF(10, 10), GetLastCaretPosition());
463 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
464 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
465 EXPECT_FALSE(GetAndResetCaretMoved());
466 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STOPPED
));
468 // Once the drag is complete, no more touch events should be consumed until
469 // the next ACTION_DOWN.
470 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
473 TEST_F(TouchSelectionControllerTest
, InsertionTapped
) {
474 base::TimeTicks event_time
= base::TimeTicks::Now();
476 controller().OnSelectionEditable(true);
477 SetDraggingEnabled(true);
479 gfx::RectF
start_rect(10, 0, 0, 10);
481 ChangeInsertion(start_rect
, visible
);
482 EXPECT_THAT(GetAndResetEvents(),
483 ElementsAre(SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
485 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
486 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
487 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED
));
489 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 0, 0);
490 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
491 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_TAPPED
,
492 INSERTION_HANDLE_DRAG_STOPPED
));
494 // Reset the insertion.
497 ChangeInsertion(start_rect
, visible
);
498 EXPECT_THAT(GetAndResetEvents(),
499 ElementsAre(SELECTION_DISSOLVED
, INSERTION_HANDLE_CLEARED
,
500 SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
502 // No tap should be signalled if the time between DOWN and UP was too long.
503 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
504 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
505 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
,
506 event_time
+ base::TimeDelta::FromSeconds(1),
509 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
510 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED
,
511 INSERTION_HANDLE_DRAG_STOPPED
));
513 // Reset the insertion.
516 ChangeInsertion(start_rect
, visible
);
517 EXPECT_THAT(GetAndResetEvents(),
518 ElementsAre(SELECTION_DISSOLVED
, INSERTION_HANDLE_CLEARED
,
519 SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
521 // No tap should be signalled if the drag was too long.
522 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
523 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
524 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 100, 0);
525 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
526 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 100, 0);
527 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
528 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED
,
529 INSERTION_HANDLE_DRAG_STOPPED
));
531 // Reset the insertion.
534 ChangeInsertion(start_rect
, visible
);
535 EXPECT_THAT(GetAndResetEvents(),
536 ElementsAre(SELECTION_DISSOLVED
, INSERTION_HANDLE_CLEARED
,
537 SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
539 // No tap should be signalled if the touch sequence is cancelled.
540 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
541 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
542 event
= MockMotionEvent(MockMotionEvent::ACTION_CANCEL
, event_time
, 0, 0);
543 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
544 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED
,
545 INSERTION_HANDLE_DRAG_STOPPED
));
548 TEST_F(TouchSelectionControllerTest
, InsertionNotResetByRepeatedTapOrPress
) {
549 base::TimeTicks event_time
= base::TimeTicks::Now();
551 controller().OnSelectionEditable(true);
552 SetDraggingEnabled(true);
554 gfx::RectF
anchor_rect(10, 0, 0, 10);
556 ChangeInsertion(anchor_rect
, visible
);
557 EXPECT_THAT(GetAndResetEvents(),
558 ElementsAre(SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
559 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
561 // Tapping again shouldn't reset the active insertion point.
563 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
564 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
565 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED
));
566 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
568 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 0, 0);
569 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
570 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_TAPPED
,
571 INSERTION_HANDLE_DRAG_STOPPED
));
572 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
574 anchor_rect
.Offset(5, 15);
575 ChangeInsertion(anchor_rect
, visible
);
576 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_MOVED
));
577 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
579 // Pressing shouldn't reset the active insertion point.
581 controller().OnSelectionEmpty(true);
582 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
583 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
584 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED
));
585 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
587 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 0, 0);
588 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
589 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_TAPPED
,
590 INSERTION_HANDLE_DRAG_STOPPED
));
591 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
594 TEST_F(TouchSelectionControllerTest
, SelectionBasic
) {
595 gfx::RectF
start_rect(5, 5, 0, 10);
596 gfx::RectF
end_rect(50, 5, 0, 10);
599 // Selection events are ignored until automatic showing is enabled.
600 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
601 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
604 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
605 EXPECT_THAT(GetAndResetEvents(),
606 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
607 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
609 start_rect
.Offset(1, 0);
610 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
611 // Selection movement does not currently trigger a separate event.
612 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
613 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
614 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventEnd());
617 EXPECT_THAT(GetAndResetEvents(),
618 ElementsAre(SELECTION_DISSOLVED
, SELECTION_HANDLES_CLEARED
));
619 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
622 TEST_F(TouchSelectionControllerTest
, SelectionAllowsEmptyUpdateAfterLongPress
) {
623 gfx::RectF
start_rect(5, 5, 0, 10);
624 gfx::RectF
end_rect(50, 5, 0, 10);
628 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
630 // There may be several empty updates after a longpress due to the
631 // asynchronous response. These empty updates should not prevent the selection
632 // handles from (eventually) activating.
634 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
637 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
639 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
640 EXPECT_THAT(GetAndResetEvents(),
641 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
644 TEST_F(TouchSelectionControllerTest
, SelectionRepeatedLongPress
) {
645 gfx::RectF
start_rect(5, 5, 0, 10);
646 gfx::RectF
end_rect(50, 5, 0, 10);
650 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
651 EXPECT_THAT(GetAndResetEvents(),
652 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
653 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
654 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventEnd());
656 // A long press triggering a new selection should re-send the
657 // SELECTION_HANDLES_SHOWN
658 // event notification.
659 start_rect
.Offset(10, 10);
661 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
662 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN
));
663 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
664 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventEnd());
667 TEST_F(TouchSelectionControllerTest
, SelectionDragged
) {
668 base::TimeTicks event_time
= base::TimeTicks::Now();
671 // The touch sequence should not be handled if selection is not active.
672 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
673 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
675 float line_height
= 10.f
;
676 gfx::RectF
start_rect(0, 0, 0, line_height
);
677 gfx::RectF
end_rect(50, 0, 0, line_height
);
679 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
680 EXPECT_THAT(GetAndResetEvents(),
681 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
682 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
684 // The touch sequence should be handled only if the drawable reports a hit.
685 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
686 SetDraggingEnabled(true);
687 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
688 EXPECT_FALSE(GetAndResetSelectionMoved());
690 // The SelectBetweenCoordinates() result should reflect the movement. Note
691 // that the start coordinate will always reflect the "fixed" handle's
692 // position, in this case the position from |end_rect|.
693 // Note that the reported position is offset from the center of the
694 // input rects (i.e., the middle of the corresponding text line).
695 gfx::PointF fixed_offset
= end_rect
.CenterPoint();
696 gfx::PointF start_offset
= start_rect
.CenterPoint();
697 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 0, 5);
698 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
699 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED
));
700 EXPECT_TRUE(GetAndResetSelectionMoved());
701 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
702 EXPECT_EQ(start_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
704 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 5, 5);
705 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
706 EXPECT_TRUE(GetAndResetSelectionMoved());
707 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
708 EXPECT_EQ(start_offset
+ gfx::Vector2dF(5, 5), GetLastSelectionEnd());
710 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 10, 5);
711 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
712 EXPECT_TRUE(GetAndResetSelectionMoved());
713 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
714 EXPECT_EQ(start_offset
+ gfx::Vector2dF(10, 5), GetLastSelectionEnd());
716 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
717 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
718 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED
));
719 EXPECT_FALSE(GetAndResetSelectionMoved());
721 // Once the drag is complete, no more touch events should be consumed until
722 // the next ACTION_DOWN.
723 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
726 TEST_F(TouchSelectionControllerTest
, SelectionDraggedWithOverlap
) {
727 base::TimeTicks event_time
= base::TimeTicks::Now();
730 float line_height
= 10.f
;
731 gfx::RectF
start_rect(0, 0, 0, line_height
);
732 gfx::RectF
end_rect(50, 0, 0, line_height
);
734 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
735 EXPECT_THAT(GetAndResetEvents(),
736 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
737 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
739 // The ACTION_DOWN should lock to the closest handle.
740 gfx::PointF end_offset
= end_rect
.CenterPoint();
741 gfx::PointF fixed_offset
= start_rect
.CenterPoint();
742 float touch_down_x
= (end_offset
.x() + fixed_offset
.x()) / 2 + 1.f
;
743 MockMotionEvent
event(
744 MockMotionEvent::ACTION_DOWN
, event_time
, touch_down_x
, 0);
745 SetDraggingEnabled(true);
746 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
747 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED
));
748 EXPECT_FALSE(GetAndResetSelectionMoved());
750 // Even though the ACTION_MOVE is over the start handle, it should continue
751 // targetting the end handle that consumed the ACTION_DOWN.
752 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 0, 0);
753 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
754 EXPECT_TRUE(GetAndResetSelectionMoved());
755 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
756 EXPECT_EQ(end_offset
- gfx::Vector2dF(touch_down_x
, 0),
757 GetLastSelectionEnd());
759 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 0, 0);
760 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
761 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED
));
762 EXPECT_FALSE(GetAndResetSelectionMoved());
765 TEST_F(TouchSelectionControllerTest
, SelectionDraggedToSwitchBaseAndExtent
) {
766 base::TimeTicks event_time
= base::TimeTicks::Now();
769 float line_height
= 10.f
;
770 gfx::RectF
start_rect(50, line_height
, 0, line_height
);
771 gfx::RectF
end_rect(100, line_height
, 0, line_height
);
773 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
774 EXPECT_THAT(GetAndResetEvents(),
775 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
776 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
778 SetDraggingEnabled(true);
780 // Move the extent, not triggering a swap of points.
781 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
,
782 end_rect
.x(), end_rect
.bottom());
783 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
784 EXPECT_FALSE(GetAndResetSelectionMoved());
785 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
787 gfx::PointF base_offset
= start_rect
.CenterPoint();
788 gfx::PointF extent_offset
= end_rect
.CenterPoint();
789 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
790 end_rect
.x(), end_rect
.bottom() + 5);
791 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
792 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED
));
793 EXPECT_TRUE(GetAndResetSelectionMoved());
794 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
795 EXPECT_EQ(base_offset
, GetLastSelectionStart());
796 EXPECT_EQ(extent_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
798 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
799 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
800 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED
));
801 EXPECT_FALSE(GetAndResetSelectionMoved());
803 end_rect
+= gfx::Vector2dF(0, 5);
804 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
805 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
807 // Move the base, triggering a swap of points.
808 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
,
809 start_rect
.x(), start_rect
.bottom());
810 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
811 EXPECT_FALSE(GetAndResetSelectionMoved());
812 EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
814 base_offset
= end_rect
.CenterPoint();
815 extent_offset
= start_rect
.CenterPoint();
816 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
817 start_rect
.x(), start_rect
.bottom() + 5);
818 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
819 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED
));
820 EXPECT_TRUE(GetAndResetSelectionMoved());
821 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
822 EXPECT_EQ(base_offset
, GetLastSelectionStart());
823 EXPECT_EQ(extent_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
825 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
826 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
827 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED
));
828 EXPECT_FALSE(GetAndResetSelectionMoved());
830 start_rect
+= gfx::Vector2dF(0, 5);
831 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
832 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
834 // Move the same point again, not triggering a swap of points.
835 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
,
836 start_rect
.x(), start_rect
.bottom());
837 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
838 EXPECT_FALSE(GetAndResetSelectionMoved());
839 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
841 base_offset
= end_rect
.CenterPoint();
842 extent_offset
= start_rect
.CenterPoint();
843 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
844 start_rect
.x(), start_rect
.bottom() + 5);
845 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
846 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED
));
847 EXPECT_TRUE(GetAndResetSelectionMoved());
848 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
849 EXPECT_EQ(base_offset
, GetLastSelectionStart());
850 EXPECT_EQ(extent_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
852 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
853 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
854 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED
));
855 EXPECT_FALSE(GetAndResetSelectionMoved());
857 start_rect
+= gfx::Vector2dF(0, 5);
858 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
859 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
861 // Move the base, triggering a swap of points.
862 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
,
863 end_rect
.x(), end_rect
.bottom());
864 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
865 EXPECT_FALSE(GetAndResetSelectionMoved());
866 EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
868 base_offset
= start_rect
.CenterPoint();
869 extent_offset
= end_rect
.CenterPoint();
870 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
871 end_rect
.x(), end_rect
.bottom() + 5);
872 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
873 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED
));
874 EXPECT_TRUE(GetAndResetSelectionMoved());
875 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
876 EXPECT_EQ(base_offset
, GetLastSelectionStart());
877 EXPECT_EQ(extent_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
879 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
880 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
881 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED
));
882 EXPECT_FALSE(GetAndResetSelectionMoved());
885 TEST_F(TouchSelectionControllerTest
, SelectionDragExtremeLineSize
) {
886 base::TimeTicks event_time
= base::TimeTicks::Now();
889 float small_line_height
= 1.f
;
890 float large_line_height
= 50.f
;
891 gfx::RectF
small_line_rect(0, 0, 0, small_line_height
);
892 gfx::RectF
large_line_rect(50, 50, 0, large_line_height
);
894 ChangeSelection(small_line_rect
, visible
, large_line_rect
, visible
);
895 EXPECT_THAT(GetAndResetEvents(),
896 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
897 EXPECT_EQ(small_line_rect
.bottom_left(), GetLastEventStart());
899 // Start dragging the handle on the small line.
900 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
,
901 small_line_rect
.x(), small_line_rect
.y());
902 SetDraggingEnabled(true);
903 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
904 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED
));
905 // The drag coordinate for large lines should be capped to a reasonable
906 // offset, allowing seamless transition to neighboring lines with different
907 // sizes. The drag coordinate for small lines should have an offset
908 // commensurate with the small line size.
909 EXPECT_EQ(large_line_rect
.bottom_left() - gfx::Vector2dF(0, 8.f
),
910 GetLastSelectionStart());
911 EXPECT_EQ(small_line_rect
.CenterPoint(), GetLastSelectionEnd());
913 small_line_rect
+= gfx::Vector2dF(25.f
, 0);
914 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
915 small_line_rect
.x(), small_line_rect
.y());
916 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
917 EXPECT_TRUE(GetAndResetSelectionMoved());
918 EXPECT_EQ(small_line_rect
.CenterPoint(), GetLastSelectionEnd());
921 TEST_F(TouchSelectionControllerTest
, Animation
) {
923 controller().OnSelectionEditable(true);
925 gfx::RectF
insertion_rect(5, 5, 0, 10);
928 ChangeInsertion(insertion_rect
, visible
);
929 EXPECT_FALSE(GetAndResetNeedsAnimate());
932 ChangeInsertion(insertion_rect
, visible
);
933 EXPECT_TRUE(GetAndResetNeedsAnimate());
936 ChangeInsertion(insertion_rect
, visible
);
937 EXPECT_TRUE(GetAndResetNeedsAnimate());
939 // If the handles are explicity hidden, no animation should be triggered.
940 controller().HideAndDisallowShowingAutomatically();
941 EXPECT_FALSE(GetAndResetNeedsAnimate());
943 // If the client doesn't support animation, no animation should be triggered.
944 SetAnimationEnabled(false);
947 ChangeInsertion(insertion_rect
, visible
);
948 EXPECT_FALSE(GetAndResetNeedsAnimate());
951 TEST_F(TouchSelectionControllerTest
, TemporarilyHidden
) {
952 TouchSelectionControllerTestApi
test_controller(&controller());
955 controller().OnSelectionEditable(true);
957 gfx::RectF
insertion_rect(5, 5, 0, 10);
960 ChangeInsertion(insertion_rect
, visible
);
961 EXPECT_FALSE(GetAndResetNeedsAnimate());
962 EXPECT_TRUE(test_controller
.GetStartVisible());
963 EXPECT_TRUE(test_controller
.GetEndVisible());
965 controller().SetTemporarilyHidden(true);
966 EXPECT_TRUE(GetAndResetNeedsAnimate());
967 EXPECT_FALSE(test_controller
.GetStartVisible());
968 EXPECT_FALSE(test_controller
.GetEndVisible());
971 ChangeInsertion(insertion_rect
, visible
);
972 EXPECT_FALSE(GetAndResetNeedsAnimate());
973 EXPECT_FALSE(test_controller
.GetStartVisible());
976 ChangeInsertion(insertion_rect
, visible
);
977 EXPECT_FALSE(GetAndResetNeedsAnimate());
978 EXPECT_FALSE(test_controller
.GetStartVisible());
980 controller().SetTemporarilyHidden(false);
981 EXPECT_TRUE(GetAndResetNeedsAnimate());
982 EXPECT_TRUE(test_controller
.GetStartVisible());
985 TEST_F(TouchSelectionControllerTest
, SelectionClearOnTap
) {
986 gfx::RectF
start_rect(5, 5, 0, 10);
987 gfx::RectF
end_rect(50, 5, 0, 10);
991 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
992 EXPECT_THAT(GetAndResetEvents(),
993 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
995 // Selection should not be cleared if the selection bounds have not changed.
997 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
998 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1002 EXPECT_THAT(GetAndResetEvents(),
1003 ElementsAre(SELECTION_DISSOLVED
, SELECTION_HANDLES_CLEARED
));
1004 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
1007 TEST_F(TouchSelectionControllerTest
, NoSelectionAfterLongpressThenTap
) {
1008 gfx::RectF
start_rect(5, 5, 0, 10);
1009 gfx::RectF
end_rect(50, 5, 0, 10);
1010 bool visible
= true;
1012 // Tap-triggered selections should not be allowed.
1015 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1016 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED
));
1018 // Subsequent longpress selections will be allowed.
1020 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1021 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN
));
1023 // Tapping again shouldn't have any effect on subsequent selection events.
1025 end_rect
.Offset(10, 10);
1026 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1027 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
1029 EXPECT_THAT(GetAndResetEvents(),
1030 ElementsAre(SELECTION_DISSOLVED
, SELECTION_HANDLES_CLEARED
));
1033 TEST_F(TouchSelectionControllerTest
, AllowShowingFromCurrentSelection
) {
1034 gfx::RectF
start_rect(5, 5, 0, 10);
1035 gfx::RectF
end_rect(50, 5, 0, 10);
1036 bool visible
= true;
1038 // The selection should not be activated, as it wasn't yet allowed.
1039 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1040 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
1042 // A longpress should have no immediate effect.
1045 // Now explicitly allow showing from the previously supplied bounds.
1046 controller().AllowShowingFromCurrentSelection();
1047 EXPECT_THAT(GetAndResetEvents(),
1048 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
1049 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1051 // Repeated calls to show from the current selection should be ignored.
1052 controller().AllowShowingFromCurrentSelection();
1053 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1054 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1056 // Trying to show from an empty selection will have no result.
1058 EXPECT_THAT(GetAndResetEvents(),
1059 ElementsAre(SELECTION_DISSOLVED
, SELECTION_HANDLES_CLEARED
));
1060 controller().AllowShowingFromCurrentSelection();
1061 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1063 // Showing the insertion handle should also be supported.
1064 controller().OnSelectionEditable(true);
1065 controller().OnSelectionEmpty(false);
1066 controller().HideAndDisallowShowingAutomatically();
1067 gfx::RectF
insertion_rect(5, 5, 0, 10);
1068 ChangeInsertion(insertion_rect
, visible
);
1069 controller().AllowShowingFromCurrentSelection();
1070 EXPECT_THAT(GetAndResetEvents(),
1071 ElementsAre(SELECTION_ESTABLISHED
, INSERTION_HANDLE_SHOWN
));
1072 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
1075 TEST_F(TouchSelectionControllerTest
, HandlesShowOnTapInsideRect
) {
1076 bool visible
= false;
1077 gfx::RectF
start_rect(5, 5, 0, 10);
1078 gfx::RectF
end_rect(50, 5, 0, 10);
1079 gfx::PointF
inner_point(25, 10);
1080 gfx::PointF
outer_point(100, 100);
1082 // Establish a selection without handles from 5 to 50 with height 10.
1083 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1084 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED
));
1086 // A point outside the rect should not be handled.
1087 EXPECT_FALSE(controller().WillHandleTapEvent(outer_point
));
1088 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1090 // A point inside the rect should be handled.
1091 EXPECT_TRUE(controller().WillHandleTapEvent(inner_point
));
1092 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN
));
1095 TEST_F(TouchSelectionControllerTest
, HandlesShowOnLongPressInsideRect
) {
1096 bool visible
= false;
1097 gfx::RectF
start_rect(5, 5, 0, 10);
1098 gfx::RectF
end_rect(50, 5, 0, 10);
1099 gfx::PointF
inner_point(25, 10);
1100 gfx::PointF
outer_point(100, 100);
1102 // Establish a selection without handles from 5 to 50 with height 10.
1103 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1104 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED
));
1106 // A point outside the rect should not be handled.
1108 controller().WillHandleLongPressEvent(base::TimeTicks(), outer_point
));
1109 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1111 // A point inside the rect should be handled.
1113 controller().WillHandleLongPressEvent(base::TimeTicks(), inner_point
));
1114 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN
));
1117 TEST_F(TouchSelectionControllerTest
, LongPressDrag
) {
1118 EnableLongPressDragSelection();
1119 TouchSelectionControllerTestApi
test_controller(&controller());
1121 gfx::RectF
start_rect(-50, 0, 0, 10);
1122 gfx::RectF
end_rect(50, 0, 0, 10);
1123 bool visible
= true;
1125 // Start a touch sequence.
1126 MockMotionEvent event
;
1127 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.PressPoint(0, 0)));
1129 // Activate a longpress-triggered selection.
1131 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1132 EXPECT_THAT(GetAndResetEvents(),
1133 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
1134 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1136 // The handles should remain invisible while the touch release and longpress
1137 // drag gesture are pending.
1138 EXPECT_FALSE(test_controller
.GetStartVisible());
1139 EXPECT_FALSE(test_controller
.GetEndVisible());
1141 // The selection coordinates should reflect the drag movement.
1142 gfx::PointF fixed_offset
= start_rect
.CenterPoint();
1143 gfx::PointF end_offset
= end_rect
.CenterPoint();
1144 EXPECT_TRUE(controller().WillHandleTouchEvent(event
.MovePoint(0, 0, 0)));
1145 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1148 controller().WillHandleTouchEvent(event
.MovePoint(0, 0, kDefaulTapSlop
)));
1149 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED
));
1150 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
1151 EXPECT_EQ(end_offset
, GetLastSelectionEnd());
1153 // Movement after the start of drag will be relative to the moved endpoint.
1154 EXPECT_TRUE(controller().WillHandleTouchEvent(
1155 event
.MovePoint(0, 0, 2 * kDefaulTapSlop
)));
1156 EXPECT_TRUE(GetAndResetSelectionMoved());
1157 EXPECT_EQ(end_offset
+ gfx::Vector2dF(0, kDefaulTapSlop
),
1158 GetLastSelectionEnd());
1160 EXPECT_TRUE(controller().WillHandleTouchEvent(
1161 event
.MovePoint(0, kDefaulTapSlop
, 2 * kDefaulTapSlop
)));
1162 EXPECT_TRUE(GetAndResetSelectionMoved());
1163 EXPECT_EQ(end_offset
+ gfx::Vector2dF(kDefaulTapSlop
, kDefaulTapSlop
),
1164 GetLastSelectionEnd());
1166 EXPECT_TRUE(controller().WillHandleTouchEvent(
1167 event
.MovePoint(0, 2 * kDefaulTapSlop
, 2 * kDefaulTapSlop
)));
1168 EXPECT_TRUE(GetAndResetSelectionMoved());
1169 EXPECT_EQ(end_offset
+ gfx::Vector2dF(2 * kDefaulTapSlop
, kDefaulTapSlop
),
1170 GetLastSelectionEnd());
1172 // The handles should still be hidden.
1173 EXPECT_FALSE(test_controller
.GetStartVisible());
1174 EXPECT_FALSE(test_controller
.GetEndVisible());
1176 // Releasing the touch sequence should end the drag and show the handles.
1177 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.ReleasePoint()));
1178 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED
));
1179 EXPECT_TRUE(test_controller
.GetStartVisible());
1180 EXPECT_TRUE(test_controller
.GetEndVisible());
1183 TEST_F(TouchSelectionControllerTest
, LongPressNoDrag
) {
1184 EnableLongPressDragSelection();
1185 TouchSelectionControllerTestApi
test_controller(&controller());
1187 gfx::RectF
start_rect(-50, 0, 0, 10);
1188 gfx::RectF
end_rect(50, 0, 0, 10);
1189 bool visible
= true;
1191 // Start a touch sequence.
1192 MockMotionEvent event
;
1193 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.PressPoint(0, 0)));
1195 // Activate a longpress-triggered selection.
1197 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1198 EXPECT_THAT(GetAndResetEvents(),
1199 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
1200 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1202 // The handles should remain invisible while the touch release and longpress
1203 // drag gesture are pending.
1204 EXPECT_FALSE(test_controller
.GetStartVisible());
1205 EXPECT_FALSE(test_controller
.GetEndVisible());
1207 // If no drag movement occurs, the handles should reappear after the touch
1209 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.ReleasePoint()));
1210 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1211 EXPECT_TRUE(test_controller
.GetStartVisible());
1212 EXPECT_TRUE(test_controller
.GetEndVisible());
1215 TEST_F(TouchSelectionControllerTest
, NoLongPressDragIfDisabled
) {
1216 // The TouchSelectionController disables longpress drag selection by default.
1217 TouchSelectionControllerTestApi
test_controller(&controller());
1219 gfx::RectF
start_rect(-50, 0, 0, 10);
1220 gfx::RectF
end_rect(50, 0, 0, 10);
1221 bool visible
= true;
1223 // Start a touch sequence.
1224 MockMotionEvent event
;
1225 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.PressPoint(0, 0)));
1227 // Activate a longpress-triggered selection.
1229 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1230 EXPECT_THAT(GetAndResetEvents(),
1231 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
1232 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1233 EXPECT_TRUE(test_controller
.GetStartVisible());
1234 EXPECT_TRUE(test_controller
.GetEndVisible());
1236 // Subsequent motion of the same touch sequence after longpress shouldn't
1237 // trigger drag selection.
1238 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.MovePoint(0, 0, 0)));
1239 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1241 EXPECT_FALSE(controller().WillHandleTouchEvent(
1242 event
.MovePoint(0, 0, kDefaulTapSlop
* 10)));
1243 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1245 // Releasing the touch sequence should have no effect.
1246 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.ReleasePoint()));
1247 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1248 EXPECT_TRUE(test_controller
.GetStartVisible());
1249 EXPECT_TRUE(test_controller
.GetEndVisible());
1252 TEST_F(TouchSelectionControllerTest
, RectBetweenBounds
) {
1253 gfx::RectF
start_rect(5, 5, 0, 10);
1254 gfx::RectF
end_rect(50, 5, 0, 10);
1255 bool visible
= true;
1257 EXPECT_EQ(gfx::RectF(), controller().GetRectBetweenBounds());
1260 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1261 ASSERT_THAT(GetAndResetEvents(),
1262 ElementsAre(SELECTION_ESTABLISHED
, SELECTION_HANDLES_SHOWN
));
1263 EXPECT_EQ(gfx::RectF(5, 5, 45, 10), controller().GetRectBetweenBounds());
1265 // The result of |GetRectBetweenBounds| should be available within the
1266 // |OnSelectionEvent| callback, as stored by |GetLastEventBoundsRect()|.
1267 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1269 start_rect
.Offset(1, 0);
1270 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1271 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
1272 EXPECT_EQ(gfx::RectF(6, 5, 44, 10), controller().GetRectBetweenBounds());
1273 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1275 // If only one bound is visible, the selection bounding rect should reflect
1276 // only the visible bound.
1277 ChangeSelection(start_rect
, visible
, end_rect
, false);
1278 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
1279 EXPECT_EQ(start_rect
, controller().GetRectBetweenBounds());
1280 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1282 ChangeSelection(start_rect
, false, end_rect
, visible
);
1283 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
1284 EXPECT_EQ(end_rect
, controller().GetRectBetweenBounds());
1285 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1287 // If both bounds are visible, the full bounding rect should be returned.
1288 ChangeSelection(start_rect
, false, end_rect
, false);
1289 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
1290 EXPECT_EQ(gfx::RectF(6, 5, 44, 10), controller().GetRectBetweenBounds());
1291 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1294 ASSERT_THAT(GetAndResetEvents(),
1295 ElementsAre(SELECTION_DISSOLVED
, SELECTION_HANDLES_CLEARED
));
1296 EXPECT_EQ(gfx::RectF(), controller().GetRectBetweenBounds());