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"
12 #include "ui/touch_selection/touch_selection_controller_test_api.h"
14 using testing::ElementsAre
;
15 using testing::IsEmpty
;
16 using ui::test::MockMotionEvent
;
21 const int kDefaultTapTimeoutMs
= 200;
22 const float kDefaulTapSlop
= 10.f
;
23 const gfx::PointF
kIgnoredPoint(0, 0);
25 class MockTouchHandleDrawable
: public TouchHandleDrawable
{
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);
40 bool* intersects_rect_
;
42 DISALLOW_COPY_AND_ASSIGN(MockTouchHandleDrawable
);
47 class TouchSelectionControllerTest
: public testing::Test
,
48 public TouchSelectionControllerClient
{
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
{
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(),
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
,
136 const gfx::RectF
& end_rect
,
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(),
154 ASSERT_FALSE(controller().WillHandleTapEvent(kIgnoredPoint
));
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_
;
168 return needs_animate
;
171 bool GetAndResetCaretMoved() {
172 bool moved
= caret_moved_
;
173 caret_moved_
= false;
177 bool GetAndResetSelectionMoved() {
178 bool moved
= selection_moved_
;
179 selection_moved_
= false;
183 bool GetAndResetSelectionPointsSwapped() {
184 bool swapped
= selection_points_swapped_
;
185 selection_points_swapped_
= false;
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_
);
204 TouchSelectionController
& controller() { return *controller_
; }
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;
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_
;
228 bool selection_moved_
;
229 bool selection_points_swapped_
;
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);
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());
248 // Insertion handles are not shown until the selection region is
250 ChangeInsertion(insertion_rect
, visible
);
251 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
252 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
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());
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);
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);
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.
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.
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);
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.
324 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_CLEARED
));
327 TEST_F(TouchSelectionControllerTest
, InsertionWithShowOnTapForEmptyEditable
) {
328 AllowShowingOnTapForEmptyEditable();
330 gfx::RectF
insertion_rect(5, 5, 0, 10);
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.
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.
345 ChangeInsertion(insertion_rect
, visible
);
346 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
349 TEST_F(TouchSelectionControllerTest
, InsertionAppearsAfterTapFollowingTyping
) {
350 gfx::RectF
insertion_rect(5, 5, 0, 10);
353 // Simulate the user tapping an empty text field.
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.
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
) {
377 controller().OnSelectionEditable(true);
379 gfx::RectF
start_rect(5, 5, 0, 10);
380 gfx::RectF
end_rect(50, 5, 0, 10);
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
));
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();
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
);
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();
462 controller().OnSelectionEditable(true);
463 SetDraggingEnabled(true);
465 gfx::RectF
start_rect(10, 0, 0, 10);
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.
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.
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.
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();
537 controller().OnSelectionEditable(true);
538 SetDraggingEnabled(true);
540 gfx::RectF
anchor_rect(10, 0, 0, 10);
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.
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.
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);
585 // Selection events are ignored until automatic showing is enabled.
586 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
587 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
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());
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);
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.
620 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
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);
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);
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();
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
);
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();
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
);
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();
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
);
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();
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
);
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
) {
909 controller().OnSelectionEditable(true);
911 gfx::RectF
insertion_rect(5, 5, 0, 10);
914 ChangeInsertion(insertion_rect
, visible
);
915 EXPECT_FALSE(GetAndResetNeedsAnimate());
918 ChangeInsertion(insertion_rect
, visible
);
919 EXPECT_TRUE(GetAndResetNeedsAnimate());
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);
933 ChangeInsertion(insertion_rect
, visible
);
934 EXPECT_FALSE(GetAndResetNeedsAnimate());
937 TEST_F(TouchSelectionControllerTest
, TemporarilyHidden
) {
938 TouchSelectionControllerTestApi
test_controller(&controller());
941 controller().OnSelectionEditable(true);
943 gfx::RectF
insertion_rect(5, 5, 0, 10);
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());
957 ChangeInsertion(insertion_rect
, visible
);
958 EXPECT_FALSE(GetAndResetNeedsAnimate());
959 EXPECT_FALSE(test_controller
.GetStartVisible());
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);
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.
983 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
984 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
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);
998 // Tap-triggered selections should not be allowed.
1001 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1002 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED
));
1004 // Subsequent longpress selections will be allowed.
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.
1011 end_rect
.Offset(10, 10);
1012 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1013 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED
));
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.
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.
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.
1094 controller().WillHandleLongPressEvent(base::TimeTicks(), outer_point
));
1095 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1097 // A point inside the rect should be handled.
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.
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());
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.
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
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.
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());
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());
1280 ASSERT_THAT(GetAndResetEvents(),
1281 ElementsAre(SELECTION_DISSOLVED
, SELECTION_HANDLES_CLEARED
));
1282 EXPECT_EQ(gfx::RectF(), controller().GetRectBetweenBounds());