[Android WebViewShell] Make WebViewLayoutTest runnable with test_runner.py
[chromium-blink-merge.git] / ui / touch_selection / touch_selection_controller_unittest.cc
blobcf585c972525910cb215392022cce28888dd2ebb
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/touch_selection/touch_selection_controller.h"
7 #include <vector>
9 #include "testing/gmock/include/gmock/gmock.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "ui/events/test/motion_event_test_utils.h"
13 using testing::ElementsAre;
14 using testing::IsEmpty;
15 using ui::test::MockMotionEvent;
17 namespace ui {
18 namespace {
20 const int kDefaultTapTimeoutMs = 200;
21 const float kDefaulTapSlop = 10.f;
22 const gfx::PointF kIgnoredPoint(0, 0);
24 class MockTouchHandleDrawable : public TouchHandleDrawable {
25 public:
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);
38 private:
39 bool* intersects_rect_;
41 DISALLOW_COPY_AND_ASSIGN(MockTouchHandleDrawable);
44 } // namespace
46 class TouchSelectionControllerTestApi {
47 public:
48 explicit TouchSelectionControllerTestApi(TouchSelectionController* controller)
49 : controller_(controller) {}
50 ~TouchSelectionControllerTestApi() {}
52 bool GetStartVisible() const { return controller_->GetStartVisible(); }
53 bool GetEndVisible() const { return controller_->GetEndVisible(); }
55 private:
56 TouchSelectionController* controller_;
58 DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerTestApi);
61 class TouchSelectionControllerTest : public testing::Test,
62 public TouchSelectionControllerClient {
63 public:
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 {
89 caret_moved_ = true;
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(),
135 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,
149 bool start_visible,
150 const gfx::RectF& end_rect,
151 bool end_visible) {
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(),
164 kIgnoredPoint));
167 void OnTapEvent() {
168 ASSERT_FALSE(controller().WillHandleTapEvent(kIgnoredPoint));
171 void Animate() {
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_;
181 Animate();
182 return needs_animate;
185 bool GetAndResetCaretMoved() {
186 bool moved = caret_moved_;
187 caret_moved_ = false;
188 return moved;
191 bool GetAndResetSelectionMoved() {
192 bool moved = selection_moved_;
193 selection_moved_ = false;
194 return moved;
197 bool GetAndResetSelectionPointsSwapped() {
198 bool swapped = selection_points_swapped_;
199 selection_points_swapped_ = false;
200 return swapped;
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_);
215 return events;
218 TouchSelectionController& controller() { return *controller_; }
220 private:
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;
226 config.tap_timeout =
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;
231 return config;
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_;
241 bool caret_moved_;
242 bool selection_moved_;
243 bool selection_points_swapped_;
244 bool needs_animate_;
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);
254 bool visible = true;
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());
260 OnTapEvent();
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());
267 OnTapEvent();
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());
283 ClearInsertion();
284 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED));
287 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
288 gfx::RectF insertion_rect(5, 5, 0, 10);
289 bool visible = true;
290 OnTapEvent();
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);
303 bool visible = true;
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.
308 OnTapEvent();
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.
314 OnTapEvent();
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);
326 OnLongPressEvent();
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.
333 OnTapEvent();
334 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED));
337 TEST_F(TouchSelectionControllerTest, InsertionWithShowOnTapForEmptyEditable) {
338 AllowShowingOnTapForEmptyEditable();
340 gfx::RectF insertion_rect(5, 5, 0, 10);
341 bool visible = true;
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.
346 OnTapEvent();
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.
353 OnTapEvent();
354 ChangeInsertion(insertion_rect, visible);
355 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
358 TEST_F(TouchSelectionControllerTest, InsertionAppearsAfterTapFollowingTyping) {
359 gfx::RectF insertion_rect(5, 5, 0, 10);
360 bool visible = true;
362 // Simulate the user tapping an empty text field.
363 OnTapEvent();
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.
377 OnTapEvent();
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) {
384 OnLongPressEvent();
385 controller().OnSelectionEditable(true);
387 gfx::RectF start_rect(5, 5, 0, 10);
388 gfx::RectF end_rect(50, 5, 0, 10);
389 bool visible = true;
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,
397 SELECTION_SHOWN));
398 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
400 ChangeInsertion(end_rect, visible);
401 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED,
402 INSERTION_SHOWN));
403 EXPECT_EQ(end_rect.bottom_left(), GetLastEventStart());
405 controller().HideAndDisallowShowingAutomatically();
406 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED));
408 OnTapEvent();
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();
416 OnTapEvent();
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);
425 bool visible = true;
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();
467 OnTapEvent();
468 controller().OnSelectionEditable(true);
469 SetDraggingEnabled(true);
471 gfx::RectF start_rect(10, 0, 0, 10);
472 bool visible = true;
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.
486 ClearInsertion();
487 OnTapEvent();
488 ChangeInsertion(start_rect, visible);
489 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED,
490 INSERTION_SHOWN));
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.
504 ClearInsertion();
505 OnTapEvent();
506 ChangeInsertion(start_rect, visible);
507 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED,
508 INSERTION_SHOWN));
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.
521 ClearInsertion();
522 OnTapEvent();
523 ChangeInsertion(start_rect, visible);
524 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED,
525 INSERTION_SHOWN));
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();
538 OnTapEvent();
539 controller().OnSelectionEditable(true);
540 SetDraggingEnabled(true);
542 gfx::RectF anchor_rect(10, 0, 0, 10);
543 bool visible = true;
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.
549 OnTapEvent();
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.
567 OnLongPressEvent();
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);
584 bool visible = true;
586 // Selection events are ignored until automatic showing is enabled.
587 ChangeSelection(start_rect, visible, end_rect, visible);
588 EXPECT_EQ(gfx::PointF(), GetLastEventStart());
590 OnLongPressEvent();
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());
602 ClearSelection();
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);
610 bool visible = true;
612 OnLongPressEvent();
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.
618 ClearSelection();
619 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
621 ClearSelection();
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);
631 bool visible = true;
633 OnLongPressEvent();
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);
642 OnLongPressEvent();
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();
651 OnLongPressEvent();
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);
660 bool visible = true;
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();
709 OnLongPressEvent();
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);
714 bool visible = true;
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();
747 OnLongPressEvent();
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);
752 bool visible = true;
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();
866 OnLongPressEvent();
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);
872 bool visible = true;
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) {
900 OnTapEvent();
901 controller().OnSelectionEditable(true);
903 gfx::RectF insertion_rect(5, 5, 0, 10);
905 bool visible = true;
906 ChangeInsertion(insertion_rect, visible);
907 EXPECT_FALSE(GetAndResetNeedsAnimate());
909 visible = false;
910 ChangeInsertion(insertion_rect, visible);
911 EXPECT_TRUE(GetAndResetNeedsAnimate());
913 visible = true;
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);
923 OnTapEvent();
924 visible = true;
925 ChangeInsertion(insertion_rect, visible);
926 EXPECT_FALSE(GetAndResetNeedsAnimate());
929 TEST_F(TouchSelectionControllerTest, TemporarilyHidden) {
930 TouchSelectionControllerTestApi test_controller(&controller());
932 OnTapEvent();
933 controller().OnSelectionEditable(true);
935 gfx::RectF insertion_rect(5, 5, 0, 10);
937 bool visible = true;
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());
948 visible = false;
949 ChangeInsertion(insertion_rect, visible);
950 EXPECT_FALSE(GetAndResetNeedsAnimate());
951 EXPECT_FALSE(test_controller.GetStartVisible());
953 visible = true;
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);
966 bool visible = true;
968 OnLongPressEvent();
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.
973 OnTapEvent();
974 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
975 EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart());
977 OnTapEvent();
978 ClearSelection();
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);
986 bool visible = true;
988 // Tap-triggered selections should not be allowed.
989 OnLongPressEvent();
990 OnTapEvent();
991 ChangeSelection(start_rect, visible, end_rect, visible);
992 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
994 // Subsequent longpress selections will be allowed.
995 OnLongPressEvent();
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.
1000 OnTapEvent();
1001 end_rect.Offset(10, 10);
1002 ChangeSelection(start_rect, visible, end_rect, visible);
1003 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_MOVED));
1004 ClearSelection();
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.
1018 OnLongPressEvent();
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.
1031 ClearSelection();
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.
1079 EXPECT_FALSE(
1080 controller().WillHandleLongPressEvent(base::TimeTicks(), outer_point));
1081 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
1083 // A point inside the rect should be handled.
1084 EXPECT_TRUE(
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.
1102 OnLongPressEvent();
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());
1118 EXPECT_TRUE(
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.
1167 OnLongPressEvent();
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
1178 // is released.
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.
1198 OnLongPressEvent();
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());
1228 OnLongPressEvent();
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());
1261 ClearSelection();
1262 ASSERT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED));
1263 EXPECT_EQ(gfx::RectF(), controller().GetRectBetweenBounds());
1266 } // namespace ui