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 events are ignored until automatic showing is enabled.
257 ChangeInsertion(insertion_rect
, visible
);
258 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
259 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
262 // Insertion events are ignored until the selection region is marked editable.
263 ChangeInsertion(insertion_rect
, visible
);
264 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
265 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
268 controller().OnSelectionEditable(true);
269 ChangeInsertion(insertion_rect
, visible
);
270 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
271 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
273 insertion_rect
.Offset(1, 0);
274 ChangeInsertion(insertion_rect
, visible
);
275 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_MOVED
));
276 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
278 insertion_rect
.Offset(0, 1);
279 ChangeInsertion(insertion_rect
, visible
);
280 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_MOVED
));
281 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
284 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED
));
287 TEST_F(TouchSelectionControllerTest
, InsertionClearedWhenNoLongerEditable
) {
288 gfx::RectF
insertion_rect(5, 5, 0, 10);
291 controller().OnSelectionEditable(true);
293 ChangeInsertion(insertion_rect
, visible
);
294 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
295 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
297 controller().OnSelectionEditable(false);
298 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED
));
301 TEST_F(TouchSelectionControllerTest
, InsertionWithNoShowOnTapForEmptyEditable
) {
302 gfx::RectF
insertion_rect(5, 5, 0, 10);
304 controller().OnSelectionEditable(true);
306 // Taps on an empty editable region should be ignored if the controller is
307 // created with |show_on_tap_for_empty_editable| set to false.
309 controller().OnSelectionEmpty(true);
310 ChangeInsertion(insertion_rect
, visible
);
311 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
313 // Once the region becomes non-empty, taps should show the insertion handle.
315 controller().OnSelectionEmpty(false);
316 ChangeInsertion(insertion_rect
, visible
);
317 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
318 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
320 // Reset the selection.
321 controller().HideAndDisallowShowingAutomatically();
322 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED
));
324 // Long-pressing should show the handle even if the editable region is empty.
325 insertion_rect
.Offset(2, -2);
327 controller().OnSelectionEmpty(true);
328 ChangeInsertion(insertion_rect
, visible
);
329 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
330 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
332 // Single Tap on an empty edit field should clear insertion handle.
334 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED
));
337 TEST_F(TouchSelectionControllerTest
, InsertionWithShowOnTapForEmptyEditable
) {
338 AllowShowingOnTapForEmptyEditable();
340 gfx::RectF
insertion_rect(5, 5, 0, 10);
342 controller().OnSelectionEditable(true);
344 // Taps on an empty editable region should show the insertion handle if the
345 // controller is created with |show_on_tap_for_empty_editable| set to true.
347 controller().OnSelectionEmpty(true);
348 ChangeInsertion(insertion_rect
, visible
);
349 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
350 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
352 // Additional taps should not hide the insertion handle in this case.
354 ChangeInsertion(insertion_rect
, visible
);
355 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
358 TEST_F(TouchSelectionControllerTest
, InsertionAppearsAfterTapFollowingTyping
) {
359 gfx::RectF
insertion_rect(5, 5, 0, 10);
362 // Simulate the user tapping an empty text field.
364 controller().OnSelectionEditable(true);
365 controller().OnSelectionEmpty(true);
366 ChangeInsertion(insertion_rect
, visible
);
367 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
369 // Simulate the cursor moving while a user is typing.
370 insertion_rect
.Offset(10, 0);
371 controller().OnSelectionEmpty(false);
372 ChangeInsertion(insertion_rect
, visible
);
373 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
375 // If the user taps the *same* position as the cursor at the end of the text
376 // entry, the handle should appear.
378 ChangeInsertion(insertion_rect
, visible
);
379 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
380 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
383 TEST_F(TouchSelectionControllerTest
, InsertionToSelectionTransition
) {
385 controller().OnSelectionEditable(true);
387 gfx::RectF
start_rect(5, 5, 0, 10);
388 gfx::RectF
end_rect(50, 5, 0, 10);
391 ChangeInsertion(start_rect
, visible
);
392 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
393 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
395 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
396 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED
,
398 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
400 ChangeInsertion(end_rect
, visible
);
401 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED
,
403 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventStart());
405 controller().HideAndDisallowShowingAutomatically();
406 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED
));
409 ChangeInsertion(end_rect
, visible
);
410 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
411 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventStart());
414 TEST_F(TouchSelectionControllerTest
, InsertionDragged
) {
415 base::TimeTicks event_time
= base::TimeTicks::Now();
417 controller().OnSelectionEditable(true);
419 // The touch sequence should not be handled if insertion is not active.
420 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
421 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
423 float line_height
= 10.f
;
424 gfx::RectF
start_rect(10, 0, 0, line_height
);
426 ChangeInsertion(start_rect
, visible
);
427 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
428 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
430 // The touch sequence should be handled only if the drawable reports a hit.
431 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
432 SetDraggingEnabled(true);
433 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
434 EXPECT_FALSE(GetAndResetCaretMoved());
435 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED
));
437 // The MoveCaret() result should reflect the movement.
438 // The reported position is offset from the center of |start_rect|.
439 gfx::PointF start_offset
= start_rect
.CenterPoint();
440 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 0, 5);
441 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
442 EXPECT_TRUE(GetAndResetCaretMoved());
443 EXPECT_EQ(start_offset
+ gfx::Vector2dF(0, 5), GetLastCaretPosition());
445 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 5, 5);
446 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
447 EXPECT_TRUE(GetAndResetCaretMoved());
448 EXPECT_EQ(start_offset
+ gfx::Vector2dF(5, 5), GetLastCaretPosition());
450 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 10, 10);
451 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
452 EXPECT_TRUE(GetAndResetCaretMoved());
453 EXPECT_EQ(start_offset
+ gfx::Vector2dF(10, 10), GetLastCaretPosition());
455 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
456 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
457 EXPECT_FALSE(GetAndResetCaretMoved());
458 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STOPPED
));
460 // Once the drag is complete, no more touch events should be consumed until
461 // the next ACTION_DOWN.
462 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
465 TEST_F(TouchSelectionControllerTest
, InsertionTapped
) {
466 base::TimeTicks event_time
= base::TimeTicks::Now();
468 controller().OnSelectionEditable(true);
469 SetDraggingEnabled(true);
471 gfx::RectF
start_rect(10, 0, 0, 10);
473 ChangeInsertion(start_rect
, visible
);
474 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
476 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
477 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
478 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED
));
480 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 0, 0);
481 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
482 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_TAPPED
,
483 INSERTION_DRAG_STOPPED
));
485 // Reset the insertion.
488 ChangeInsertion(start_rect
, visible
);
489 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED
,
492 // No tap should be signalled if the time between DOWN and UP was too long.
493 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
494 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
495 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
,
496 event_time
+ base::TimeDelta::FromSeconds(1),
499 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
500 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED
,
501 INSERTION_DRAG_STOPPED
));
503 // Reset the insertion.
506 ChangeInsertion(start_rect
, visible
);
507 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED
,
510 // No tap should be signalled if the drag was too long.
511 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
512 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
513 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 100, 0);
514 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
515 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 100, 0);
516 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
517 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED
,
518 INSERTION_DRAG_STOPPED
));
520 // Reset the insertion.
523 ChangeInsertion(start_rect
, visible
);
524 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED
,
527 // No tap should be signalled if the touch sequence is cancelled.
528 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
529 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
530 event
= MockMotionEvent(MockMotionEvent::ACTION_CANCEL
, event_time
, 0, 0);
531 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
532 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED
,
533 INSERTION_DRAG_STOPPED
));
536 TEST_F(TouchSelectionControllerTest
, InsertionNotResetByRepeatedTapOrPress
) {
537 base::TimeTicks event_time
= base::TimeTicks::Now();
539 controller().OnSelectionEditable(true);
540 SetDraggingEnabled(true);
542 gfx::RectF
anchor_rect(10, 0, 0, 10);
544 ChangeInsertion(anchor_rect
, visible
);
545 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
546 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
548 // Tapping again shouldn't reset the active insertion point.
550 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
551 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
552 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED
));
553 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
555 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 0, 0);
556 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
557 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_TAPPED
,
558 INSERTION_DRAG_STOPPED
));
559 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
561 anchor_rect
.Offset(5, 15);
562 ChangeInsertion(anchor_rect
, visible
);
563 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_MOVED
));
564 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
566 // Pressing shouldn't reset the active insertion point.
568 controller().OnSelectionEmpty(true);
569 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
570 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
571 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED
));
572 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
574 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 0, 0);
575 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
576 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_TAPPED
,
577 INSERTION_DRAG_STOPPED
));
578 EXPECT_EQ(anchor_rect
.bottom_left(), GetLastEventStart());
581 TEST_F(TouchSelectionControllerTest
, SelectionBasic
) {
582 gfx::RectF
start_rect(5, 5, 0, 10);
583 gfx::RectF
end_rect(50, 5, 0, 10);
586 // Selection events are ignored until automatic showing is enabled.
587 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
588 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
591 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
592 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_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_MOVED
));
599 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
600 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventEnd());
603 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED
));
604 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
607 TEST_F(TouchSelectionControllerTest
, SelectionAllowsEmptyUpdateAfterLongPress
) {
608 gfx::RectF
start_rect(5, 5, 0, 10);
609 gfx::RectF
end_rect(50, 5, 0, 10);
613 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
615 // There may be several empty updates after a longpress due to the
616 // asynchronous response. These empty updates should not prevent the selection
617 // handles from (eventually) activating.
619 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
622 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
624 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
625 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
628 TEST_F(TouchSelectionControllerTest
, SelectionRepeatedLongPress
) {
629 gfx::RectF
start_rect(5, 5, 0, 10);
630 gfx::RectF
end_rect(50, 5, 0, 10);
634 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
635 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
636 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
637 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventEnd());
639 // A long press triggering a new selection should re-send the SELECTION_SHOWN
640 // event notification.
641 start_rect
.Offset(10, 10);
643 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
644 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
645 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
646 EXPECT_EQ(end_rect
.bottom_left(), GetLastEventEnd());
649 TEST_F(TouchSelectionControllerTest
, SelectionDragged
) {
650 base::TimeTicks event_time
= base::TimeTicks::Now();
653 // The touch sequence should not be handled if selection is not active.
654 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
, 0, 0);
655 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
657 float line_height
= 10.f
;
658 gfx::RectF
start_rect(0, 0, 0, line_height
);
659 gfx::RectF
end_rect(50, 0, 0, line_height
);
661 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
662 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
663 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
665 // The touch sequence should be handled only if the drawable reports a hit.
666 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
667 SetDraggingEnabled(true);
668 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
669 EXPECT_FALSE(GetAndResetSelectionMoved());
671 // The SelectBetweenCoordinates() result should reflect the movement. Note
672 // that the start coordinate will always reflect the "fixed" handle's
673 // position, in this case the position from |end_rect|.
674 // Note that the reported position is offset from the center of the
675 // input rects (i.e., the middle of the corresponding text line).
676 gfx::PointF fixed_offset
= end_rect
.CenterPoint();
677 gfx::PointF start_offset
= start_rect
.CenterPoint();
678 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 0, 5);
679 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
680 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED
));
681 EXPECT_TRUE(GetAndResetSelectionMoved());
682 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
683 EXPECT_EQ(start_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
685 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 5, 5);
686 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
687 EXPECT_TRUE(GetAndResetSelectionMoved());
688 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
689 EXPECT_EQ(start_offset
+ gfx::Vector2dF(5, 5), GetLastSelectionEnd());
691 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 10, 5);
692 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
693 EXPECT_TRUE(GetAndResetSelectionMoved());
694 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
695 EXPECT_EQ(start_offset
+ gfx::Vector2dF(10, 5), GetLastSelectionEnd());
697 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
698 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
699 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED
));
700 EXPECT_FALSE(GetAndResetSelectionMoved());
702 // Once the drag is complete, no more touch events should be consumed until
703 // the next ACTION_DOWN.
704 EXPECT_FALSE(controller().WillHandleTouchEvent(event
));
707 TEST_F(TouchSelectionControllerTest
, SelectionDraggedWithOverlap
) {
708 base::TimeTicks event_time
= base::TimeTicks::Now();
711 float line_height
= 10.f
;
712 gfx::RectF
start_rect(0, 0, 0, line_height
);
713 gfx::RectF
end_rect(50, 0, 0, line_height
);
715 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
716 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
717 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
719 // The ACTION_DOWN should lock to the closest handle.
720 gfx::PointF end_offset
= end_rect
.CenterPoint();
721 gfx::PointF fixed_offset
= start_rect
.CenterPoint();
722 float touch_down_x
= (end_offset
.x() + fixed_offset
.x()) / 2 + 1.f
;
723 MockMotionEvent
event(
724 MockMotionEvent::ACTION_DOWN
, event_time
, touch_down_x
, 0);
725 SetDraggingEnabled(true);
726 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
727 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED
));
728 EXPECT_FALSE(GetAndResetSelectionMoved());
730 // Even though the ACTION_MOVE is over the start handle, it should continue
731 // targetting the end handle that consumed the ACTION_DOWN.
732 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
, 0, 0);
733 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
734 EXPECT_TRUE(GetAndResetSelectionMoved());
735 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
736 EXPECT_EQ(end_offset
- gfx::Vector2dF(touch_down_x
, 0),
737 GetLastSelectionEnd());
739 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 0, 0);
740 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
741 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED
));
742 EXPECT_FALSE(GetAndResetSelectionMoved());
745 TEST_F(TouchSelectionControllerTest
, SelectionDraggedToSwitchBaseAndExtent
) {
746 base::TimeTicks event_time
= base::TimeTicks::Now();
749 float line_height
= 10.f
;
750 gfx::RectF
start_rect(50, line_height
, 0, line_height
);
751 gfx::RectF
end_rect(100, line_height
, 0, line_height
);
753 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
754 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
755 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
757 SetDraggingEnabled(true);
759 // Move the extent, not triggering a swap of points.
760 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
,
761 end_rect
.x(), end_rect
.bottom());
762 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
763 EXPECT_FALSE(GetAndResetSelectionMoved());
764 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
766 gfx::PointF base_offset
= start_rect
.CenterPoint();
767 gfx::PointF extent_offset
= end_rect
.CenterPoint();
768 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
769 end_rect
.x(), end_rect
.bottom() + 5);
770 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
771 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED
));
772 EXPECT_TRUE(GetAndResetSelectionMoved());
773 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
774 EXPECT_EQ(base_offset
, GetLastSelectionStart());
775 EXPECT_EQ(extent_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
777 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
778 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
779 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED
));
780 EXPECT_FALSE(GetAndResetSelectionMoved());
782 end_rect
+= gfx::Vector2dF(0, 5);
783 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
784 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_MOVED
));
786 // Move the base, triggering a swap of points.
787 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
,
788 start_rect
.x(), start_rect
.bottom());
789 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
790 EXPECT_FALSE(GetAndResetSelectionMoved());
791 EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
793 base_offset
= end_rect
.CenterPoint();
794 extent_offset
= start_rect
.CenterPoint();
795 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
796 start_rect
.x(), start_rect
.bottom() + 5);
797 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
798 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED
));
799 EXPECT_TRUE(GetAndResetSelectionMoved());
800 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
801 EXPECT_EQ(base_offset
, GetLastSelectionStart());
802 EXPECT_EQ(extent_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
804 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
805 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
806 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED
));
807 EXPECT_FALSE(GetAndResetSelectionMoved());
809 start_rect
+= gfx::Vector2dF(0, 5);
810 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
811 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_MOVED
));
813 // Move the same point again, not triggering a swap of points.
814 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
,
815 start_rect
.x(), start_rect
.bottom());
816 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
817 EXPECT_FALSE(GetAndResetSelectionMoved());
818 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
820 base_offset
= end_rect
.CenterPoint();
821 extent_offset
= start_rect
.CenterPoint();
822 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
823 start_rect
.x(), start_rect
.bottom() + 5);
824 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
825 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED
));
826 EXPECT_TRUE(GetAndResetSelectionMoved());
827 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
828 EXPECT_EQ(base_offset
, GetLastSelectionStart());
829 EXPECT_EQ(extent_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
831 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
832 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
833 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED
));
834 EXPECT_FALSE(GetAndResetSelectionMoved());
836 start_rect
+= gfx::Vector2dF(0, 5);
837 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
838 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_MOVED
));
840 // Move the base, triggering a swap of points.
841 event
= MockMotionEvent(MockMotionEvent::ACTION_DOWN
, event_time
,
842 end_rect
.x(), end_rect
.bottom());
843 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
844 EXPECT_FALSE(GetAndResetSelectionMoved());
845 EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
847 base_offset
= start_rect
.CenterPoint();
848 extent_offset
= end_rect
.CenterPoint();
849 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
850 end_rect
.x(), end_rect
.bottom() + 5);
851 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
852 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED
));
853 EXPECT_TRUE(GetAndResetSelectionMoved());
854 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
855 EXPECT_EQ(base_offset
, GetLastSelectionStart());
856 EXPECT_EQ(extent_offset
+ gfx::Vector2dF(0, 5), GetLastSelectionEnd());
858 event
= MockMotionEvent(MockMotionEvent::ACTION_UP
, event_time
, 10, 5);
859 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
860 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED
));
861 EXPECT_FALSE(GetAndResetSelectionMoved());
864 TEST_F(TouchSelectionControllerTest
, SelectionDragExtremeLineSize
) {
865 base::TimeTicks event_time
= base::TimeTicks::Now();
868 float small_line_height
= 1.f
;
869 float large_line_height
= 50.f
;
870 gfx::RectF
small_line_rect(0, 0, 0, small_line_height
);
871 gfx::RectF
large_line_rect(50, 50, 0, large_line_height
);
873 ChangeSelection(small_line_rect
, visible
, large_line_rect
, visible
);
874 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
875 EXPECT_EQ(small_line_rect
.bottom_left(), GetLastEventStart());
877 // Start dragging the handle on the small line.
878 MockMotionEvent
event(MockMotionEvent::ACTION_DOWN
, event_time
,
879 small_line_rect
.x(), small_line_rect
.y());
880 SetDraggingEnabled(true);
881 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
882 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED
));
883 // The drag coordinate for large lines should be capped to a reasonable
884 // offset, allowing seamless transition to neighboring lines with different
885 // sizes. The drag coordinate for small lines should have an offset
886 // commensurate with the small line size.
887 EXPECT_EQ(large_line_rect
.bottom_left() - gfx::Vector2dF(0, 8.f
),
888 GetLastSelectionStart());
889 EXPECT_EQ(small_line_rect
.CenterPoint(), GetLastSelectionEnd());
891 small_line_rect
+= gfx::Vector2dF(25.f
, 0);
892 event
= MockMotionEvent(MockMotionEvent::ACTION_MOVE
, event_time
,
893 small_line_rect
.x(), small_line_rect
.y());
894 EXPECT_TRUE(controller().WillHandleTouchEvent(event
));
895 EXPECT_TRUE(GetAndResetSelectionMoved());
896 EXPECT_EQ(small_line_rect
.CenterPoint(), GetLastSelectionEnd());
899 TEST_F(TouchSelectionControllerTest
, Animation
) {
901 controller().OnSelectionEditable(true);
903 gfx::RectF
insertion_rect(5, 5, 0, 10);
906 ChangeInsertion(insertion_rect
, visible
);
907 EXPECT_FALSE(GetAndResetNeedsAnimate());
910 ChangeInsertion(insertion_rect
, visible
);
911 EXPECT_TRUE(GetAndResetNeedsAnimate());
914 ChangeInsertion(insertion_rect
, visible
);
915 EXPECT_TRUE(GetAndResetNeedsAnimate());
917 // If the handles are explicity hidden, no animation should be triggered.
918 controller().HideAndDisallowShowingAutomatically();
919 EXPECT_FALSE(GetAndResetNeedsAnimate());
921 // If the client doesn't support animation, no animation should be triggered.
922 SetAnimationEnabled(false);
925 ChangeInsertion(insertion_rect
, visible
);
926 EXPECT_FALSE(GetAndResetNeedsAnimate());
929 TEST_F(TouchSelectionControllerTest
, TemporarilyHidden
) {
930 TouchSelectionControllerTestApi
test_controller(&controller());
933 controller().OnSelectionEditable(true);
935 gfx::RectF
insertion_rect(5, 5, 0, 10);
938 ChangeInsertion(insertion_rect
, visible
);
939 EXPECT_FALSE(GetAndResetNeedsAnimate());
940 EXPECT_TRUE(test_controller
.GetStartVisible());
941 EXPECT_TRUE(test_controller
.GetEndVisible());
943 controller().SetTemporarilyHidden(true);
944 EXPECT_TRUE(GetAndResetNeedsAnimate());
945 EXPECT_FALSE(test_controller
.GetStartVisible());
946 EXPECT_FALSE(test_controller
.GetEndVisible());
949 ChangeInsertion(insertion_rect
, visible
);
950 EXPECT_FALSE(GetAndResetNeedsAnimate());
951 EXPECT_FALSE(test_controller
.GetStartVisible());
954 ChangeInsertion(insertion_rect
, visible
);
955 EXPECT_FALSE(GetAndResetNeedsAnimate());
956 EXPECT_FALSE(test_controller
.GetStartVisible());
958 controller().SetTemporarilyHidden(false);
959 EXPECT_TRUE(GetAndResetNeedsAnimate());
960 EXPECT_TRUE(test_controller
.GetStartVisible());
963 TEST_F(TouchSelectionControllerTest
, SelectionClearOnTap
) {
964 gfx::RectF
start_rect(5, 5, 0, 10);
965 gfx::RectF
end_rect(50, 5, 0, 10);
969 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
970 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
972 // Selection should not be cleared if the selection bounds have not changed.
974 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
975 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
979 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED
));
980 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
983 TEST_F(TouchSelectionControllerTest
, NoSelectionAfterLongpressThenTap
) {
984 gfx::RectF
start_rect(5, 5, 0, 10);
985 gfx::RectF
end_rect(50, 5, 0, 10);
988 // Tap-triggered selections should not be allowed.
991 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
992 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
994 // Subsequent longpress selections will be allowed.
996 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
997 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
999 // Tapping again shouldn't have any effect on subsequent selection events.
1001 end_rect
.Offset(10, 10);
1002 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1003 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_MOVED
));
1005 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED
));
1008 TEST_F(TouchSelectionControllerTest
, AllowShowingFromCurrentSelection
) {
1009 gfx::RectF
start_rect(5, 5, 0, 10);
1010 gfx::RectF
end_rect(50, 5, 0, 10);
1011 bool visible
= true;
1013 // The selection should not be activated, as it wasn't yet allowed.
1014 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1015 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
1017 // A longpress should have no immediate effect.
1020 // Now explicitly allow showing from the previously supplied bounds.
1021 controller().AllowShowingFromCurrentSelection();
1022 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
1023 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1025 // Repeated calls to show from the current selection should be ignored.
1026 controller().AllowShowingFromCurrentSelection();
1027 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1028 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1030 // Trying to show from an empty selection will have no result.
1032 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED
));
1033 controller().AllowShowingFromCurrentSelection();
1034 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1036 // Showing the insertion handle should also be supported.
1037 controller().OnSelectionEditable(true);
1038 controller().OnSelectionEmpty(false);
1039 controller().HideAndDisallowShowingAutomatically();
1040 gfx::RectF
insertion_rect(5, 5, 0, 10);
1041 ChangeInsertion(insertion_rect
, visible
);
1042 controller().AllowShowingFromCurrentSelection();
1043 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN
));
1044 EXPECT_EQ(insertion_rect
.bottom_left(), GetLastEventStart());
1047 TEST_F(TouchSelectionControllerTest
, HandlesShowOnTapInsideRect
) {
1048 bool visible
= false;
1049 gfx::RectF
start_rect(5, 5, 0, 10);
1050 gfx::RectF
end_rect(50, 5, 0, 10);
1051 gfx::PointF
inner_point(25, 10);
1052 gfx::PointF
outer_point(100, 100);
1054 // Establish a selection without handles from 5 to 50 with height 10.
1055 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1056 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1058 // A point outside the rect should not be handled.
1059 EXPECT_FALSE(controller().WillHandleTapEvent(outer_point
));
1060 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1062 // A point inside the rect should be handled.
1063 EXPECT_TRUE(controller().WillHandleTapEvent(inner_point
));
1064 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
1067 TEST_F(TouchSelectionControllerTest
, HandlesShowOnLongPressInsideRect
) {
1068 bool visible
= false;
1069 gfx::RectF
start_rect(5, 5, 0, 10);
1070 gfx::RectF
end_rect(50, 5, 0, 10);
1071 gfx::PointF
inner_point(25, 10);
1072 gfx::PointF
outer_point(100, 100);
1074 // Establish a selection without handles from 5 to 50 with height 10.
1075 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1076 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1078 // A point outside the rect should not be handled.
1080 controller().WillHandleLongPressEvent(base::TimeTicks(), outer_point
));
1081 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1083 // A point inside the rect should be handled.
1085 controller().WillHandleLongPressEvent(base::TimeTicks(), inner_point
));
1086 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
1089 TEST_F(TouchSelectionControllerTest
, LongPressDrag
) {
1090 EnableLongPressDragSelection();
1091 TouchSelectionControllerTestApi
test_controller(&controller());
1093 gfx::RectF
start_rect(-50, 0, 0, 10);
1094 gfx::RectF
end_rect(50, 0, 0, 10);
1095 bool visible
= true;
1097 // Start a touch sequence.
1098 MockMotionEvent event
;
1099 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.PressPoint(0, 0)));
1101 // Activate a longpress-triggered selection.
1103 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1104 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
1105 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1107 // The handles should remain invisible while the touch release and longpress
1108 // drag gesture are pending.
1109 EXPECT_FALSE(test_controller
.GetStartVisible());
1110 EXPECT_FALSE(test_controller
.GetEndVisible());
1112 // The selection coordinates should reflect the drag movement.
1113 gfx::PointF fixed_offset
= start_rect
.CenterPoint();
1114 gfx::PointF end_offset
= end_rect
.CenterPoint();
1115 EXPECT_TRUE(controller().WillHandleTouchEvent(event
.MovePoint(0, 0, 0)));
1116 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1119 controller().WillHandleTouchEvent(event
.MovePoint(0, 0, kDefaulTapSlop
)));
1120 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED
));
1121 EXPECT_EQ(fixed_offset
, GetLastSelectionStart());
1122 EXPECT_EQ(end_offset
, GetLastSelectionEnd());
1124 // Movement after the start of drag will be relative to the moved endpoint.
1125 EXPECT_TRUE(controller().WillHandleTouchEvent(
1126 event
.MovePoint(0, 0, 2 * kDefaulTapSlop
)));
1127 EXPECT_TRUE(GetAndResetSelectionMoved());
1128 EXPECT_EQ(end_offset
+ gfx::Vector2dF(0, kDefaulTapSlop
),
1129 GetLastSelectionEnd());
1131 EXPECT_TRUE(controller().WillHandleTouchEvent(
1132 event
.MovePoint(0, kDefaulTapSlop
, 2 * kDefaulTapSlop
)));
1133 EXPECT_TRUE(GetAndResetSelectionMoved());
1134 EXPECT_EQ(end_offset
+ gfx::Vector2dF(kDefaulTapSlop
, kDefaulTapSlop
),
1135 GetLastSelectionEnd());
1137 EXPECT_TRUE(controller().WillHandleTouchEvent(
1138 event
.MovePoint(0, 2 * kDefaulTapSlop
, 2 * kDefaulTapSlop
)));
1139 EXPECT_TRUE(GetAndResetSelectionMoved());
1140 EXPECT_EQ(end_offset
+ gfx::Vector2dF(2 * kDefaulTapSlop
, kDefaulTapSlop
),
1141 GetLastSelectionEnd());
1143 // The handles should still be hidden.
1144 EXPECT_FALSE(test_controller
.GetStartVisible());
1145 EXPECT_FALSE(test_controller
.GetEndVisible());
1147 // Releasing the touch sequence should end the drag and show the handles.
1148 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.ReleasePoint()));
1149 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED
));
1150 EXPECT_TRUE(test_controller
.GetStartVisible());
1151 EXPECT_TRUE(test_controller
.GetEndVisible());
1154 TEST_F(TouchSelectionControllerTest
, LongPressNoDrag
) {
1155 EnableLongPressDragSelection();
1156 TouchSelectionControllerTestApi
test_controller(&controller());
1158 gfx::RectF
start_rect(-50, 0, 0, 10);
1159 gfx::RectF
end_rect(50, 0, 0, 10);
1160 bool visible
= true;
1162 // Start a touch sequence.
1163 MockMotionEvent event
;
1164 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.PressPoint(0, 0)));
1166 // Activate a longpress-triggered selection.
1168 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1169 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
1170 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1172 // The handles should remain invisible while the touch release and longpress
1173 // drag gesture are pending.
1174 EXPECT_FALSE(test_controller
.GetStartVisible());
1175 EXPECT_FALSE(test_controller
.GetEndVisible());
1177 // If no drag movement occurs, the handles should reappear after the touch
1179 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.ReleasePoint()));
1180 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1181 EXPECT_TRUE(test_controller
.GetStartVisible());
1182 EXPECT_TRUE(test_controller
.GetEndVisible());
1185 TEST_F(TouchSelectionControllerTest
, NoLongPressDragIfDisabled
) {
1186 // The TouchSelectionController disables longpress drag selection by default.
1187 TouchSelectionControllerTestApi
test_controller(&controller());
1189 gfx::RectF
start_rect(-50, 0, 0, 10);
1190 gfx::RectF
end_rect(50, 0, 0, 10);
1191 bool visible
= true;
1193 // Start a touch sequence.
1194 MockMotionEvent event
;
1195 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.PressPoint(0, 0)));
1197 // Activate a longpress-triggered selection.
1199 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1200 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
1201 EXPECT_EQ(start_rect
.bottom_left(), GetLastEventStart());
1202 EXPECT_TRUE(test_controller
.GetStartVisible());
1203 EXPECT_TRUE(test_controller
.GetEndVisible());
1205 // Subsequent motion of the same touch sequence after longpress shouldn't
1206 // trigger drag selection.
1207 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.MovePoint(0, 0, 0)));
1208 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1210 EXPECT_FALSE(controller().WillHandleTouchEvent(
1211 event
.MovePoint(0, 0, kDefaulTapSlop
* 10)));
1212 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1214 // Releasing the touch sequence should have no effect.
1215 EXPECT_FALSE(controller().WillHandleTouchEvent(event
.ReleasePoint()));
1216 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1217 EXPECT_TRUE(test_controller
.GetStartVisible());
1218 EXPECT_TRUE(test_controller
.GetEndVisible());
1221 TEST_F(TouchSelectionControllerTest
, RectBetweenBounds
) {
1222 gfx::RectF
start_rect(5, 5, 0, 10);
1223 gfx::RectF
end_rect(50, 5, 0, 10);
1224 bool visible
= true;
1226 EXPECT_EQ(gfx::RectF(), controller().GetRectBetweenBounds());
1229 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1230 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN
));
1231 EXPECT_EQ(gfx::RectF(5, 5, 45, 10), controller().GetRectBetweenBounds());
1233 // The result of |GetRectBetweenBounds| should be available within the
1234 // |OnSelectionEvent| callback, as stored by |GetLastEventBoundsRect()|.
1235 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1237 start_rect
.Offset(1, 0);
1238 ChangeSelection(start_rect
, visible
, end_rect
, visible
);
1239 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_MOVED
));
1240 EXPECT_EQ(gfx::RectF(6, 5, 44, 10), controller().GetRectBetweenBounds());
1241 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1243 // If only one bound is visible, the selection bounding rect should reflect
1244 // only the visible bound.
1245 ChangeSelection(start_rect
, visible
, end_rect
, false);
1246 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_MOVED
));
1247 EXPECT_EQ(start_rect
, controller().GetRectBetweenBounds());
1248 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1250 ChangeSelection(start_rect
, false, end_rect
, visible
);
1251 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_MOVED
));
1252 EXPECT_EQ(end_rect
, controller().GetRectBetweenBounds());
1253 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1255 // If both bounds are visible, the full bounding rect should be returned.
1256 ChangeSelection(start_rect
, false, end_rect
, false);
1257 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_MOVED
));
1258 EXPECT_EQ(gfx::RectF(6, 5, 44, 10), controller().GetRectBetweenBounds());
1259 EXPECT_EQ(GetLastEventBoundsRect(), controller().GetRectBetweenBounds());
1262 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED
));
1263 EXPECT_EQ(gfx::RectF(), controller().GetRectBetweenBounds());