ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / ui / touch_selection / touch_selection_controller_unittest.cc
blobbc8a0bc9f8659dfae14673cbf8a6e85e66694b13
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;
23 class MockTouchHandleDrawable : public TouchHandleDrawable {
24 public:
25 explicit MockTouchHandleDrawable(bool* contains_point)
26 : intersects_rect_(contains_point) {}
27 ~MockTouchHandleDrawable() override {}
28 void SetEnabled(bool enabled) override {}
29 void SetOrientation(TouchHandleOrientation orientation) override {}
30 void SetAlpha(float alpha) override {}
31 void SetFocus(const gfx::PointF& position) override {}
32 gfx::RectF GetVisibleBounds() const override {
33 return *intersects_rect_ ? gfx::RectF(-1000, -1000, 2000, 2000)
34 : gfx::RectF(-1000, -1000, 0, 0);
37 private:
38 bool* intersects_rect_;
41 } // namespace
43 class TouchSelectionControllerTest : public testing::Test,
44 public TouchSelectionControllerClient {
45 public:
46 TouchSelectionControllerTest()
47 : caret_moved_(false),
48 selection_moved_(false),
49 selection_points_swapped_(false),
50 needs_animate_(false),
51 animation_enabled_(true),
52 dragging_enabled_(false) {}
54 ~TouchSelectionControllerTest() override {}
56 // testing::Test implementation.
58 void SetUp() override {
59 // Default touch selection controller is created with
60 // |show_on_tap_for_empty_editable| flag set to false. Use
61 // |AllowShowingOnTapForEmptyEditable()| function to override it.
62 bool show_on_tap_for_empty_editable = false;
63 controller_.reset(new TouchSelectionController(
64 this,
65 base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs),
66 kDefaulTapSlop,
67 show_on_tap_for_empty_editable));
70 void TearDown() override { controller_.reset(); }
72 // TouchSelectionControllerClient implementation.
74 bool SupportsAnimation() const override { return animation_enabled_; }
76 void SetNeedsAnimate() override { needs_animate_ = true; }
78 void MoveCaret(const gfx::PointF& position) override {
79 caret_moved_ = true;
80 caret_position_ = position;
83 void SelectBetweenCoordinates(const gfx::PointF& base,
84 const gfx::PointF& extent) override {
85 if (base == selection_end_ && extent == selection_start_)
86 selection_points_swapped_ = true;
88 selection_start_ = base;
89 selection_end_ = extent;
92 void MoveRangeSelectionExtent(const gfx::PointF& extent) override {
93 selection_moved_ = true;
94 selection_end_ = extent;
97 void OnSelectionEvent(SelectionEventType event,
98 const gfx::PointF& end_position) override {
99 events_.push_back(event);
100 last_event_start_ = end_position;
103 scoped_ptr<TouchHandleDrawable> CreateDrawable() override {
104 return make_scoped_ptr(new MockTouchHandleDrawable(&dragging_enabled_));
107 void AllowShowingOnTapForEmptyEditable() {
108 bool show_on_tap_for_empty_editable = true;
109 controller_.reset(new TouchSelectionController(
110 this,
111 base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs),
112 kDefaulTapSlop,
113 show_on_tap_for_empty_editable));
116 void SetAnimationEnabled(bool enabled) { animation_enabled_ = enabled; }
117 void SetDraggingEnabled(bool enabled) { dragging_enabled_ = enabled; }
119 void ClearSelection() {
120 controller_->OnSelectionBoundsChanged(SelectionBound(),
121 SelectionBound());
124 void ClearInsertion() { ClearSelection(); }
126 void ChangeInsertion(const gfx::RectF& rect, bool visible) {
127 SelectionBound bound;
128 bound.set_type(SelectionBound::CENTER);
129 bound.SetEdge(rect.origin(), rect.bottom_left());
130 bound.set_visible(visible);
131 controller_->OnSelectionBoundsChanged(bound, bound);
134 void ChangeSelection(const gfx::RectF& start_rect,
135 bool start_visible,
136 const gfx::RectF& end_rect,
137 bool end_visible) {
138 SelectionBound start_bound, end_bound;
139 start_bound.set_type(SelectionBound::LEFT);
140 end_bound.set_type(SelectionBound::RIGHT);
141 start_bound.SetEdge(start_rect.origin(), start_rect.bottom_left());
142 end_bound.SetEdge(end_rect.origin(), end_rect.bottom_left());
143 start_bound.set_visible(start_visible);
144 end_bound.set_visible(end_visible);
145 controller_->OnSelectionBoundsChanged(start_bound, end_bound);
148 void Animate() {
149 base::TimeTicks now = base::TimeTicks::Now();
150 while (needs_animate_) {
151 needs_animate_ = controller_->Animate(now);
152 now += base::TimeDelta::FromMilliseconds(16);
156 bool GetAndResetNeedsAnimate() {
157 bool needs_animate = needs_animate_;
158 Animate();
159 return needs_animate;
162 bool GetAndResetCaretMoved() {
163 bool moved = caret_moved_;
164 caret_moved_ = false;
165 return moved;
168 bool GetAndResetSelectionMoved() {
169 bool moved = selection_moved_;
170 selection_moved_ = false;
171 return moved;
174 bool GetAndResetSelectionPointsSwapped() {
175 bool swapped = selection_points_swapped_;
176 selection_points_swapped_ = false;
177 return swapped;
180 const gfx::PointF& GetLastCaretPosition() const { return caret_position_; }
181 const gfx::PointF& GetLastSelectionStart() const { return selection_start_; }
182 const gfx::PointF& GetLastSelectionEnd() const { return selection_end_; }
183 const gfx::PointF& GetLastEventAnchor() const { return last_event_start_; }
185 std::vector<SelectionEventType> GetAndResetEvents() {
186 std::vector<SelectionEventType> events;
187 events.swap(events_);
188 return events;
191 TouchSelectionController& controller() { return *controller_; }
193 private:
194 gfx::PointF last_event_start_;
195 gfx::PointF caret_position_;
196 gfx::PointF selection_start_;
197 gfx::PointF selection_end_;
198 std::vector<SelectionEventType> events_;
199 bool caret_moved_;
200 bool selection_moved_;
201 bool selection_points_swapped_;
202 bool needs_animate_;
203 bool animation_enabled_;
204 bool dragging_enabled_;
205 scoped_ptr<TouchSelectionController> controller_;
208 TEST_F(TouchSelectionControllerTest, InsertionBasic) {
209 gfx::RectF insertion_rect(5, 5, 0, 10);
210 bool visible = true;
212 // Insertion events are ignored until automatic showing is enabled.
213 ChangeInsertion(insertion_rect, visible);
214 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
215 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
216 controller().OnTapEvent();
218 // Insertion events are ignored until the selection region is marked editable.
219 ChangeInsertion(insertion_rect, visible);
220 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
221 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
223 controller().OnTapEvent();
224 controller().OnSelectionEditable(true);
225 ChangeInsertion(insertion_rect, visible);
226 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
227 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
229 insertion_rect.Offset(1, 0);
230 ChangeInsertion(insertion_rect, visible);
231 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_MOVED));
232 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
234 insertion_rect.Offset(0, 1);
235 ChangeInsertion(insertion_rect, visible);
236 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_MOVED));
237 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
239 ClearInsertion();
240 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED));
243 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
244 gfx::RectF insertion_rect(5, 5, 0, 10);
245 bool visible = true;
246 controller().OnTapEvent();
247 controller().OnSelectionEditable(true);
249 ChangeInsertion(insertion_rect, visible);
250 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
251 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
253 controller().OnSelectionEditable(false);
254 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED));
257 TEST_F(TouchSelectionControllerTest, InsertionWithNoShowOnTapForEmptyEditable) {
258 gfx::RectF insertion_rect(5, 5, 0, 10);
259 bool visible = true;
260 controller().OnSelectionEditable(true);
262 // Taps on an empty editable region should be ignored if the controller is
263 // created with |show_on_tap_for_empty_editable| set to false.
264 controller().OnTapEvent();
265 controller().OnSelectionEmpty(true);
266 ChangeInsertion(insertion_rect, visible);
267 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
269 // Once the region becomes non-empty, taps should show the insertion handle.
270 controller().OnTapEvent();
271 controller().OnSelectionEmpty(false);
272 ChangeInsertion(insertion_rect, visible);
273 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
274 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
276 // Reset the selection.
277 controller().HideAndDisallowShowingAutomatically();
278 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED));
280 // Long-pressing should show the handle even if the editable region is empty.
281 insertion_rect.Offset(2, -2);
282 controller().OnLongPressEvent();
283 controller().OnSelectionEmpty(true);
284 ChangeInsertion(insertion_rect, visible);
285 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
286 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
288 // Single Tap on an empty edit field should clear insertion handle.
289 controller().OnTapEvent();
290 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED));
293 TEST_F(TouchSelectionControllerTest, InsertionWithShowOnTapForEmptyEditable) {
294 AllowShowingOnTapForEmptyEditable();
296 gfx::RectF insertion_rect(5, 5, 0, 10);
297 bool visible = true;
298 controller().OnSelectionEditable(true);
300 // Taps on an empty editable region should show the insertion handle if the
301 // controller is created with |show_on_tap_for_empty_editable| set to true.
302 controller().OnTapEvent();
303 controller().OnSelectionEmpty(true);
304 ChangeInsertion(insertion_rect, visible);
305 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
306 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
309 TEST_F(TouchSelectionControllerTest, InsertionAppearsAfterTapFollowingTyping) {
310 gfx::RectF insertion_rect(5, 5, 0, 10);
311 bool visible = true;
313 // Simulate the user tapping an empty text field.
314 controller().OnTapEvent();
315 controller().OnSelectionEditable(true);
316 controller().OnSelectionEmpty(true);
317 ChangeInsertion(insertion_rect, visible);
318 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
320 // Simulate the cursor moving while a user is typing.
321 insertion_rect.Offset(10, 0);
322 controller().OnSelectionEmpty(false);
323 ChangeInsertion(insertion_rect, visible);
324 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
326 // If the user taps the *same* position as the cursor at the end of the text
327 // entry, the handle should appear.
328 controller().OnTapEvent();
329 ChangeInsertion(insertion_rect, visible);
330 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
331 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
334 TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
335 controller().OnLongPressEvent();
336 controller().OnSelectionEditable(true);
338 gfx::RectF start_rect(5, 5, 0, 10);
339 gfx::RectF end_rect(50, 5, 0, 10);
340 bool visible = true;
342 ChangeInsertion(start_rect, visible);
343 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
344 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
346 ChangeSelection(start_rect, visible, end_rect, visible);
347 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED,
348 SELECTION_SHOWN));
349 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
351 ChangeInsertion(end_rect, visible);
352 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED,
353 INSERTION_SHOWN));
354 EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
356 controller().HideAndDisallowShowingAutomatically();
357 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED));
359 controller().OnTapEvent();
360 ChangeInsertion(end_rect, visible);
361 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
362 EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
365 TEST_F(TouchSelectionControllerTest, InsertionDragged) {
366 base::TimeTicks event_time = base::TimeTicks::Now();
367 controller().OnTapEvent();
368 controller().OnSelectionEditable(true);
370 // The touch sequence should not be handled if insertion is not active.
371 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
372 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
374 float line_height = 10.f;
375 gfx::RectF start_rect(10, 0, 0, line_height);
376 bool visible = true;
377 ChangeInsertion(start_rect, visible);
378 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
379 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
381 // The touch sequence should be handled only if the drawable reports a hit.
382 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
383 SetDraggingEnabled(true);
384 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
385 EXPECT_FALSE(GetAndResetCaretMoved());
386 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED));
388 // The MoveCaret() result should reflect the movement.
389 // The reported position is offset from the center of |start_rect|.
390 gfx::PointF start_offset = start_rect.CenterPoint();
391 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
392 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
393 EXPECT_TRUE(GetAndResetCaretMoved());
394 EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition());
396 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
397 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
398 EXPECT_TRUE(GetAndResetCaretMoved());
399 EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastCaretPosition());
401 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 10);
402 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
403 EXPECT_TRUE(GetAndResetCaretMoved());
404 EXPECT_EQ(start_offset + gfx::Vector2dF(10, 10), GetLastCaretPosition());
406 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
407 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
408 EXPECT_FALSE(GetAndResetCaretMoved());
409 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STOPPED));
411 // Once the drag is complete, no more touch events should be consumed until
412 // the next ACTION_DOWN.
413 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
416 TEST_F(TouchSelectionControllerTest, InsertionTapped) {
417 base::TimeTicks event_time = base::TimeTicks::Now();
418 controller().OnTapEvent();
419 controller().OnSelectionEditable(true);
420 SetDraggingEnabled(true);
422 gfx::RectF start_rect(10, 0, 0, 10);
423 bool visible = true;
424 ChangeInsertion(start_rect, visible);
425 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
427 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
428 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
429 //TODO(AKV): this test case has to be modified once crbug.com/394093 is fixed.
430 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED));
432 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
433 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
434 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_TAPPED,
435 INSERTION_DRAG_STOPPED));
437 // Reset the insertion.
438 ClearInsertion();
439 controller().OnTapEvent();
440 ChangeInsertion(start_rect, visible);
441 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED,
442 INSERTION_SHOWN));
444 // No tap should be signalled if the time between DOWN and UP was too long.
445 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
446 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
447 event = MockMotionEvent(MockMotionEvent::ACTION_UP,
448 event_time + base::TimeDelta::FromSeconds(1),
451 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
452 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED,
453 INSERTION_DRAG_STOPPED));
455 // Reset the insertion.
456 ClearInsertion();
457 controller().OnTapEvent();
458 ChangeInsertion(start_rect, visible);
459 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED,
460 INSERTION_SHOWN));
462 // No tap should be signalled if the drag was too long.
463 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
464 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
465 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 100, 0);
466 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
467 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 100, 0);
468 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
469 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED,
470 INSERTION_DRAG_STOPPED));
472 // Reset the insertion.
473 ClearInsertion();
474 controller().OnTapEvent();
475 ChangeInsertion(start_rect, visible);
476 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_CLEARED,
477 INSERTION_SHOWN));
479 // No tap should be signalled if the touch sequence is cancelled.
480 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
481 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
482 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
483 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
484 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED,
485 INSERTION_DRAG_STOPPED));
488 TEST_F(TouchSelectionControllerTest, InsertionNotResetByRepeatedTapOrPress) {
489 base::TimeTicks event_time = base::TimeTicks::Now();
490 controller().OnTapEvent();
491 controller().OnSelectionEditable(true);
492 SetDraggingEnabled(true);
494 gfx::RectF anchor_rect(10, 0, 0, 10);
495 bool visible = true;
496 ChangeInsertion(anchor_rect, visible);
497 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
498 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
500 // Tapping again shouldn't reset the active insertion point.
501 controller().OnTapEvent();
502 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
503 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
504 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED));
505 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
507 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
508 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
509 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_TAPPED,
510 INSERTION_DRAG_STOPPED));
511 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
513 anchor_rect.Offset(5, 15);
514 ChangeInsertion(anchor_rect, visible);
515 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_MOVED));
516 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
518 // Pressing shouldn't reset the active insertion point.
519 controller().OnLongPressEvent();
520 controller().OnSelectionEmpty(true);
521 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
522 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
523 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_DRAG_STARTED));
524 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
526 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
527 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
528 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_TAPPED,
529 INSERTION_DRAG_STOPPED));
530 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
533 TEST_F(TouchSelectionControllerTest, SelectionBasic) {
534 gfx::RectF start_rect(5, 5, 0, 10);
535 gfx::RectF end_rect(50, 5, 0, 10);
536 bool visible = true;
538 // Selection events are ignored until automatic showing is enabled.
539 ChangeSelection(start_rect, visible, end_rect, visible);
540 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
542 controller().OnLongPressEvent();
543 ChangeSelection(start_rect, visible, end_rect, visible);
544 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
545 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
547 start_rect.Offset(1, 0);
548 ChangeSelection(start_rect, visible, end_rect, visible);
549 // Selection movement does not currently trigger a separate event.
550 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
552 ClearSelection();
553 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED));
554 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
557 TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) {
558 gfx::RectF start_rect(5, 5, 0, 10);
559 gfx::RectF end_rect(50, 5, 0, 10);
560 bool visible = true;
562 controller().OnLongPressEvent();
563 ChangeSelection(start_rect, visible, end_rect, visible);
564 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
565 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
567 // A long press triggering a new selection should re-send the SELECTION_SHOWN
568 // event notification.
569 start_rect.Offset(10, 10);
570 controller().OnLongPressEvent();
571 ChangeSelection(start_rect, visible, end_rect, visible);
572 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
573 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
576 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
577 base::TimeTicks event_time = base::TimeTicks::Now();
578 controller().OnLongPressEvent();
580 // The touch sequence should not be handled if selection is not active.
581 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
582 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
584 float line_height = 10.f;
585 gfx::RectF start_rect(0, 0, 0, line_height);
586 gfx::RectF end_rect(50, 0, 0, line_height);
587 bool visible = true;
588 ChangeSelection(start_rect, visible, end_rect, visible);
589 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
590 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
592 // The touch sequence should be handled only if the drawable reports a hit.
593 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
594 SetDraggingEnabled(true);
595 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
596 EXPECT_FALSE(GetAndResetSelectionMoved());
598 // The SelectBetweenCoordinates() result should reflect the movement. Note
599 // that the start coordinate will always reflect the "fixed" handle's
600 // position, in this case the position from |end_rect|.
601 // Note that the reported position is offset from the center of the
602 // input rects (i.e., the middle of the corresponding text line).
603 gfx::PointF fixed_offset = end_rect.CenterPoint();
604 gfx::PointF start_offset = start_rect.CenterPoint();
605 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
606 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
607 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED));
608 EXPECT_TRUE(GetAndResetSelectionMoved());
609 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
610 EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
612 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
613 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
614 EXPECT_TRUE(GetAndResetSelectionMoved());
615 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
616 EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd());
618 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5);
619 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
620 EXPECT_TRUE(GetAndResetSelectionMoved());
621 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
622 EXPECT_EQ(start_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd());
624 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
625 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
626 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED));
627 EXPECT_FALSE(GetAndResetSelectionMoved());
629 // Once the drag is complete, no more touch events should be consumed until
630 // the next ACTION_DOWN.
631 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
634 TEST_F(TouchSelectionControllerTest, SelectionDraggedWithOverlap) {
635 base::TimeTicks event_time = base::TimeTicks::Now();
636 controller().OnLongPressEvent();
638 float line_height = 10.f;
639 gfx::RectF start_rect(0, 0, 0, line_height);
640 gfx::RectF end_rect(50, 0, 0, line_height);
641 bool visible = true;
642 ChangeSelection(start_rect, visible, end_rect, visible);
643 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
644 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
646 // The ACTION_DOWN should lock to the closest handle.
647 gfx::PointF end_offset = end_rect.CenterPoint();
648 gfx::PointF fixed_offset = start_rect.CenterPoint();
649 float touch_down_x = (end_offset.x() + fixed_offset.x()) / 2 + 1.f;
650 MockMotionEvent event(
651 MockMotionEvent::ACTION_DOWN, event_time, touch_down_x, 0);
652 SetDraggingEnabled(true);
653 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
654 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED));
655 EXPECT_FALSE(GetAndResetSelectionMoved());
657 // Even though the ACTION_MOVE is over the start handle, it should continue
658 // targetting the end handle that consumed the ACTION_DOWN.
659 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 0);
660 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
661 EXPECT_TRUE(GetAndResetSelectionMoved());
662 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
663 EXPECT_EQ(end_offset - gfx::Vector2dF(touch_down_x, 0),
664 GetLastSelectionEnd());
666 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
667 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
668 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED));
669 EXPECT_FALSE(GetAndResetSelectionMoved());
672 TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) {
673 base::TimeTicks event_time = base::TimeTicks::Now();
674 controller().OnLongPressEvent();
676 float line_height = 10.f;
677 gfx::RectF start_rect(50, line_height, 0, line_height);
678 gfx::RectF end_rect(100, line_height, 0, line_height);
679 bool visible = true;
680 ChangeSelection(start_rect, visible, end_rect, visible);
681 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
682 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
684 SetDraggingEnabled(true);
686 // Move the extent, not triggering a swap of points.
687 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time,
688 end_rect.x(), end_rect.bottom());
689 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
690 EXPECT_FALSE(GetAndResetSelectionMoved());
691 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
693 gfx::PointF base_offset = start_rect.CenterPoint();
694 gfx::PointF extent_offset = end_rect.CenterPoint();
695 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
696 end_rect.x(), end_rect.bottom() + 5);
697 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
698 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED));
699 EXPECT_TRUE(GetAndResetSelectionMoved());
700 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
701 EXPECT_EQ(base_offset, GetLastSelectionStart());
702 EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
704 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
705 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
706 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED));
707 EXPECT_FALSE(GetAndResetSelectionMoved());
709 end_rect += gfx::Vector2dF(0, 5);
710 ChangeSelection(start_rect, visible, end_rect, visible);
712 // Move the base, triggering a swap of points.
713 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time,
714 start_rect.x(), start_rect.bottom());
715 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
716 EXPECT_FALSE(GetAndResetSelectionMoved());
717 EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
719 base_offset = end_rect.CenterPoint();
720 extent_offset = start_rect.CenterPoint();
721 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
722 start_rect.x(), start_rect.bottom() + 5);
723 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
724 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED));
725 EXPECT_TRUE(GetAndResetSelectionMoved());
726 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
727 EXPECT_EQ(base_offset, GetLastSelectionStart());
728 EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
730 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
731 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
732 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED));
733 EXPECT_FALSE(GetAndResetSelectionMoved());
735 start_rect += gfx::Vector2dF(0, 5);
736 ChangeSelection(start_rect, visible, end_rect, visible);
738 // Move the same point again, not triggering a swap of points.
739 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time,
740 start_rect.x(), start_rect.bottom());
741 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
742 EXPECT_FALSE(GetAndResetSelectionMoved());
743 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
745 base_offset = end_rect.CenterPoint();
746 extent_offset = start_rect.CenterPoint();
747 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
748 start_rect.x(), start_rect.bottom() + 5);
749 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
750 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED));
751 EXPECT_TRUE(GetAndResetSelectionMoved());
752 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
753 EXPECT_EQ(base_offset, GetLastSelectionStart());
754 EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
756 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
757 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
758 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED));
759 EXPECT_FALSE(GetAndResetSelectionMoved());
761 start_rect += gfx::Vector2dF(0, 5);
762 ChangeSelection(start_rect, visible, end_rect, visible);
764 // Move the base, triggering a swap of points.
765 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time,
766 end_rect.x(), end_rect.bottom());
767 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
768 EXPECT_FALSE(GetAndResetSelectionMoved());
769 EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
771 base_offset = start_rect.CenterPoint();
772 extent_offset = end_rect.CenterPoint();
773 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
774 end_rect.x(), end_rect.bottom() + 5);
775 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
776 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED));
777 EXPECT_TRUE(GetAndResetSelectionMoved());
778 EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
779 EXPECT_EQ(base_offset, GetLastSelectionStart());
780 EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
782 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
783 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
784 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STOPPED));
785 EXPECT_FALSE(GetAndResetSelectionMoved());
788 TEST_F(TouchSelectionControllerTest, SelectionDragExtremeLineSize) {
789 base::TimeTicks event_time = base::TimeTicks::Now();
790 controller().OnLongPressEvent();
792 float small_line_height = 1.f;
793 float large_line_height = 50.f;
794 gfx::RectF small_line_rect(0, 0, 0, small_line_height);
795 gfx::RectF large_line_rect(50, 50, 0, large_line_height);
796 bool visible = true;
797 ChangeSelection(small_line_rect, visible, large_line_rect, visible);
798 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
799 EXPECT_EQ(small_line_rect.bottom_left(), GetLastEventAnchor());
801 // Start dragging the handle on the small line.
802 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time,
803 small_line_rect.x(), small_line_rect.y());
804 SetDraggingEnabled(true);
805 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
806 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_DRAG_STARTED));
807 // The drag coordinate for large lines should be capped to a reasonable
808 // offset, allowing seamless transition to neighboring lines with different
809 // sizes. The drag coordinate for small lines should have an offset
810 // commensurate with the small line size.
811 EXPECT_EQ(large_line_rect.bottom_left() - gfx::Vector2dF(0, 5.f),
812 GetLastSelectionStart());
813 EXPECT_EQ(small_line_rect.CenterPoint(), GetLastSelectionEnd());
815 small_line_rect += gfx::Vector2dF(25.f, 0);
816 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
817 small_line_rect.x(), small_line_rect.y());
818 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
819 EXPECT_TRUE(GetAndResetSelectionMoved());
820 EXPECT_EQ(small_line_rect.CenterPoint(), GetLastSelectionEnd());
823 TEST_F(TouchSelectionControllerTest, Animation) {
824 controller().OnTapEvent();
825 controller().OnSelectionEditable(true);
827 gfx::RectF insertion_rect(5, 5, 0, 10);
829 bool visible = true;
830 ChangeInsertion(insertion_rect, visible);
831 EXPECT_FALSE(GetAndResetNeedsAnimate());
833 visible = false;
834 ChangeInsertion(insertion_rect, visible);
835 EXPECT_TRUE(GetAndResetNeedsAnimate());
837 visible = true;
838 ChangeInsertion(insertion_rect, visible);
839 EXPECT_TRUE(GetAndResetNeedsAnimate());
841 // If the handles are explicity hidden, no animation should be triggered.
842 controller().HideAndDisallowShowingAutomatically();
843 EXPECT_FALSE(GetAndResetNeedsAnimate());
845 // If the client doesn't support animation, no animation should be triggered.
846 SetAnimationEnabled(false);
847 controller().OnTapEvent();
848 visible = true;
849 ChangeInsertion(insertion_rect, visible);
850 EXPECT_FALSE(GetAndResetNeedsAnimate());
853 TEST_F(TouchSelectionControllerTest, TemporarilyHidden) {
854 controller().OnTapEvent();
855 controller().OnSelectionEditable(true);
857 gfx::RectF insertion_rect(5, 5, 0, 10);
859 bool visible = true;
860 ChangeInsertion(insertion_rect, visible);
861 EXPECT_FALSE(GetAndResetNeedsAnimate());
863 controller().SetTemporarilyHidden(true);
864 EXPECT_TRUE(GetAndResetNeedsAnimate());
866 visible = false;
867 ChangeInsertion(insertion_rect, visible);
868 EXPECT_FALSE(GetAndResetNeedsAnimate());
870 visible = true;
871 ChangeInsertion(insertion_rect, visible);
872 EXPECT_FALSE(GetAndResetNeedsAnimate());
874 controller().SetTemporarilyHidden(false);
875 EXPECT_TRUE(GetAndResetNeedsAnimate());
878 TEST_F(TouchSelectionControllerTest, SelectionClearOnTap) {
879 gfx::RectF start_rect(5, 5, 0, 10);
880 gfx::RectF end_rect(50, 5, 0, 10);
881 bool visible = true;
883 controller().OnLongPressEvent();
884 ChangeSelection(start_rect, visible, end_rect, visible);
885 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
887 // Selection should not be cleared if the selection bounds have not changed.
888 controller().OnTapEvent();
889 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
890 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
892 controller().OnTapEvent();
893 ClearSelection();
894 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED));
895 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
898 TEST_F(TouchSelectionControllerTest, AllowShowingFromCurrentSelection) {
899 gfx::RectF start_rect(5, 5, 0, 10);
900 gfx::RectF end_rect(50, 5, 0, 10);
901 bool visible = true;
903 // The selection should not be activated, as it wasn't yet allowed.
904 ChangeSelection(start_rect, visible, end_rect, visible);
905 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
907 // Now explicitly allow showing from the previously supplied bounds.
908 controller().AllowShowingFromCurrentSelection();
909 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_SHOWN));
910 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
912 // Repeated calls to show from the current selection should be ignored.
913 controller().AllowShowingFromCurrentSelection();
914 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
915 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
917 // Trying to show from an empty selection will have no result.
918 ClearSelection();
919 EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_CLEARED));
920 controller().AllowShowingFromCurrentSelection();
921 EXPECT_THAT(GetAndResetEvents(), IsEmpty());
923 // Showing the insertion handle should also be supported.
924 controller().OnSelectionEditable(true);
925 controller().OnSelectionEmpty(false);
926 controller().HideAndDisallowShowingAutomatically();
927 gfx::RectF insertion_rect(5, 5, 0, 10);
928 ChangeInsertion(insertion_rect, visible);
929 controller().AllowShowingFromCurrentSelection();
930 EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_SHOWN));
931 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
934 } // namespace ui