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 "content/browser/renderer_host/input/touch_selection_controller.h"
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "ui/events/test/mock_motion_event.h"
10 using ui::test::MockMotionEvent;
15 const int kDefaultTapTimeoutMs = 200;
16 const float kDefaulTapSlop = 10.f;
18 class MockTouchHandleDrawable : public TouchHandleDrawable {
20 explicit MockTouchHandleDrawable(bool* contains_point)
21 : intersects_rect_(contains_point) {}
22 virtual ~MockTouchHandleDrawable() {}
23 virtual void SetEnabled(bool enabled) OVERRIDE {}
24 virtual void SetOrientation(TouchHandleOrientation orientation) OVERRIDE {}
25 virtual void SetAlpha(float alpha) OVERRIDE {}
26 virtual void SetFocus(const gfx::PointF& position) OVERRIDE {}
27 virtual void SetVisible(bool visible) OVERRIDE {}
28 virtual bool IntersectsWith(const gfx::RectF& rect) const OVERRIDE {
29 return *intersects_rect_;
33 bool* intersects_rect_;
38 class TouchSelectionControllerTest : public testing::Test,
39 public TouchSelectionControllerClient {
41 TouchSelectionControllerTest()
42 : last_event_(SELECTION_CLEARED),
44 selection_moved_(false),
45 needs_animate_(false),
46 animation_enabled_(true),
47 dragging_enabled_(false) {}
49 virtual ~TouchSelectionControllerTest() {}
51 // testing::Test implementation.
52 virtual void SetUp() OVERRIDE {
53 controller_.reset(new TouchSelectionController(
55 base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs),
59 virtual void TearDown() OVERRIDE { controller_.reset(); }
61 // TouchSelectionControllerClient implementation.
63 virtual bool SupportsAnimation() const OVERRIDE { return animation_enabled_; }
65 virtual void SetNeedsAnimate() OVERRIDE { needs_animate_ = true; }
67 virtual void MoveCaret(const gfx::PointF& position) OVERRIDE {
69 caret_position_ = position;
72 virtual void SelectBetweenCoordinates(const gfx::PointF& start,
73 const gfx::PointF& end) OVERRIDE {
74 selection_moved_ = true;
75 selection_start_ = start;
79 virtual void OnSelectionEvent(SelectionEventType event,
80 const gfx::PointF& end_position) OVERRIDE {
82 last_event_start_ = end_position;
85 virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() OVERRIDE {
86 return scoped_ptr<TouchHandleDrawable>(
87 new MockTouchHandleDrawable(&dragging_enabled_));
90 void SetAnimationEnabled(bool enabled) { animation_enabled_ = enabled; }
91 void SetDraggingEnabled(bool enabled) { dragging_enabled_ = enabled; }
93 void ClearSelection() {
94 controller_->OnSelectionBoundsChanged(cc::ViewportSelectionBound(),
95 cc::ViewportSelectionBound());
98 void ClearInsertion() { ClearSelection(); }
100 void ChangeInsertion(const gfx::RectF& rect, bool visible) {
101 cc::ViewportSelectionBound bound;
102 bound.type = cc::SELECTION_BOUND_CENTER;
103 bound.edge_top = rect.origin();
104 bound.edge_bottom = rect.bottom_left();
105 bound.visible = visible;
106 controller_->OnSelectionBoundsChanged(bound, bound);
109 void ChangeSelection(const gfx::RectF& start_rect,
111 const gfx::RectF& end_rect,
113 cc::ViewportSelectionBound start_bound, end_bound;
114 start_bound.type = cc::SELECTION_BOUND_LEFT;
115 end_bound.type = cc::SELECTION_BOUND_RIGHT;
116 start_bound.edge_top = start_rect.origin();
117 start_bound.edge_bottom = start_rect.bottom_left();
118 end_bound.edge_top = end_rect.origin();
119 end_bound.edge_bottom = end_rect.bottom_left();
120 start_bound.visible = start_visible;
121 end_bound.visible = end_visible;
122 controller_->OnSelectionBoundsChanged(start_bound, end_bound);
126 base::TimeTicks now = base::TimeTicks::Now();
127 while (needs_animate_) {
128 needs_animate_ = controller_->Animate(now);
129 now += base::TimeDelta::FromMilliseconds(16);
133 bool GetAndResetNeedsAnimate() {
134 bool needs_animate = needs_animate_;
136 return needs_animate;
139 bool GetAndResetCaretMoved() {
140 bool moved = caret_moved_;
141 caret_moved_ = false;
145 bool GetAndResetSelectionMoved() {
146 bool moved = selection_moved_;
147 selection_moved_ = false;
151 const gfx::PointF& GetLastCaretPosition() const { return caret_position_; }
152 const gfx::PointF& GetLastSelectionStart() const { return selection_start_; }
153 const gfx::PointF& GetLastSelectionEnd() const { return selection_end_; }
154 SelectionEventType GetLastEventType() const { return last_event_; }
155 const gfx::PointF& GetLastEventAnchor() const { return last_event_start_; }
157 TouchSelectionController& controller() { return *controller_; }
160 gfx::PointF last_event_start_;
161 gfx::PointF caret_position_;
162 gfx::PointF selection_start_;
163 gfx::PointF selection_end_;
164 SelectionEventType last_event_;
166 bool selection_moved_;
168 bool animation_enabled_;
169 bool dragging_enabled_;
170 scoped_ptr<TouchSelectionController> controller_;
173 TEST_F(TouchSelectionControllerTest, InsertionBasic) {
174 gfx::RectF insertion_rect(5, 5, 0, 10);
177 // Insertion events are ignored until automatic showing is enabled.
178 ChangeInsertion(insertion_rect, visible);
179 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
180 controller().OnTapEvent();
182 // Insertion events are ignored until the selection region is marked editable.
183 ChangeInsertion(insertion_rect, visible);
184 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
186 controller().OnTapEvent();
187 controller().OnSelectionEditable(true);
188 ChangeInsertion(insertion_rect, visible);
189 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
190 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
192 insertion_rect.Offset(1, 0);
193 ChangeInsertion(insertion_rect, visible);
194 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
195 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
197 insertion_rect.Offset(0, 1);
198 ChangeInsertion(insertion_rect, visible);
199 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
200 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
203 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
206 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
207 gfx::RectF insertion_rect(5, 5, 0, 10);
209 controller().OnTapEvent();
210 controller().OnSelectionEditable(true);
212 ChangeInsertion(insertion_rect, visible);
213 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
214 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
216 controller().OnSelectionEditable(false);
217 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
220 TEST_F(TouchSelectionControllerTest, InsertionStaysHiddenIfEmptyRegionTapped) {
221 gfx::RectF insertion_rect(5, 5, 0, 10);
223 controller().OnSelectionEditable(true);
225 // Taps should be ignored if they're in an empty editable region.
226 controller().OnTapEvent();
227 controller().OnSelectionEmpty(true);
228 ChangeInsertion(insertion_rect, visible);
229 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
231 // Once the region becomes editable, taps should show the insertion handle.
232 controller().OnTapEvent();
233 controller().OnSelectionEmpty(false);
234 ChangeInsertion(insertion_rect, visible);
235 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
236 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
238 // Reset the selection.
239 controller().HideAndDisallowShowingAutomatically();
240 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
242 // Long-pressing should show the handle even if the editable region is empty.
243 insertion_rect.Offset(2, -2);
244 controller().OnLongPressEvent();
245 controller().OnSelectionEmpty(true);
246 ChangeInsertion(insertion_rect, visible);
247 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
248 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
250 // Single Tap on an empty edit field should clear insertion handle.
251 controller().OnTapEvent();
252 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
255 TEST_F(TouchSelectionControllerTest, InsertionAppearsAfterTapFollowingTyping) {
256 gfx::RectF insertion_rect(5, 5, 0, 10);
259 // Simulate the user tapping an empty text field.
260 controller().OnTapEvent();
261 controller().OnSelectionEditable(true);
262 controller().OnSelectionEmpty(true);
263 ChangeInsertion(insertion_rect, visible);
264 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
266 // Simulate the cursor moving while a user is typing.
267 insertion_rect.Offset(10, 0);
268 controller().OnSelectionEmpty(false);
269 ChangeInsertion(insertion_rect, visible);
270 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
272 // If the user taps the *same* position as the cursor at the end of the text
273 // entry, the handle should appear.
274 controller().OnTapEvent();
275 ChangeInsertion(insertion_rect, visible);
276 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
277 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
280 TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
281 controller().OnLongPressEvent();
282 controller().OnSelectionEditable(true);
284 gfx::RectF start_rect(5, 5, 0, 10);
285 gfx::RectF end_rect(50, 5, 0, 10);
288 ChangeInsertion(start_rect, visible);
289 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
290 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
292 ChangeSelection(start_rect, visible, end_rect, visible);
293 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
294 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
296 ChangeInsertion(end_rect, visible);
297 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
298 EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
300 controller().HideAndDisallowShowingAutomatically();
301 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
303 controller().OnTapEvent();
304 ChangeInsertion(end_rect, visible);
305 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
306 EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
309 TEST_F(TouchSelectionControllerTest, InsertionDragged) {
310 base::TimeTicks event_time = base::TimeTicks::Now();
311 controller().OnTapEvent();
312 controller().OnSelectionEditable(true);
314 // The touch sequence should not be handled if insertion is not active.
315 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
316 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
318 float line_height = 10.f;
319 gfx::RectF start_rect(10, 0, 0, line_height);
321 ChangeInsertion(start_rect, visible);
322 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
323 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
325 // The touch sequence should be handled only if the drawable reports a hit.
326 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
327 SetDraggingEnabled(true);
328 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
329 EXPECT_FALSE(GetAndResetCaretMoved());
331 // The MoveCaret() result should reflect the movement.
332 // The reported position is offset from the center of |start_rect|.
333 gfx::PointF start_offset = start_rect.CenterPoint();
334 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
335 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
336 EXPECT_TRUE(GetAndResetCaretMoved());
337 EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition());
339 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
340 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
341 EXPECT_TRUE(GetAndResetCaretMoved());
342 EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastCaretPosition());
344 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 10);
345 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
346 EXPECT_TRUE(GetAndResetCaretMoved());
347 EXPECT_EQ(start_offset + gfx::Vector2dF(10, 10), GetLastCaretPosition());
349 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
350 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
351 EXPECT_FALSE(GetAndResetCaretMoved());
353 // Once the drag is complete, no more touch events should be consumed until
354 // the next ACTION_DOWN.
355 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
358 TEST_F(TouchSelectionControllerTest, InsertionTapped) {
359 base::TimeTicks event_time = base::TimeTicks::Now();
360 controller().OnTapEvent();
361 controller().OnSelectionEditable(true);
362 SetDraggingEnabled(true);
364 gfx::RectF start_rect(10, 0, 0, 10);
366 ChangeInsertion(start_rect, visible);
367 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
369 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
370 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
371 //TODO(AKV): this test case has to be modified once crbug.com/394093 is fixed.
372 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
374 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
375 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
376 EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
378 // Reset the insertion.
380 controller().OnTapEvent();
381 ChangeInsertion(start_rect, visible);
382 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
384 // No tap should be signalled if the time between DOWN and UP was too long.
385 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
386 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
387 event = MockMotionEvent(MockMotionEvent::ACTION_UP,
388 event_time + base::TimeDelta::FromSeconds(1),
391 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
392 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
394 // Reset the insertion.
396 controller().OnTapEvent();
397 ChangeInsertion(start_rect, visible);
398 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
400 // No tap should be signalled if the drag was too long.
401 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
402 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
403 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 100, 0);
404 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
405 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 100, 0);
406 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
407 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
409 // Reset the insertion.
411 controller().OnTapEvent();
412 ChangeInsertion(start_rect, visible);
413 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
415 // No tap should be signalled if the touch sequence is cancelled.
416 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
417 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
418 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
419 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
420 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
423 TEST_F(TouchSelectionControllerTest, InsertionNotResetByRepeatedTapOrPress) {
424 base::TimeTicks event_time = base::TimeTicks::Now();
425 controller().OnTapEvent();
426 controller().OnSelectionEditable(true);
427 SetDraggingEnabled(true);
429 gfx::RectF anchor_rect(10, 0, 0, 10);
431 ChangeInsertion(anchor_rect, visible);
432 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
433 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
435 // Tapping again shouldn't reset the active insertion point.
436 controller().OnTapEvent();
437 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
438 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
439 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
440 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
442 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
443 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
444 EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
445 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
447 anchor_rect.Offset(5, 15);
448 ChangeInsertion(anchor_rect, visible);
449 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
450 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
452 // Pressing shouldn't reset the active insertion point.
453 controller().OnLongPressEvent();
454 controller().OnSelectionEmpty(true);
455 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
456 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
457 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
458 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
460 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
461 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
462 EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
463 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
466 TEST_F(TouchSelectionControllerTest, SelectionBasic) {
467 gfx::RectF start_rect(5, 5, 0, 10);
468 gfx::RectF end_rect(50, 5, 0, 10);
471 // Selection events are ignored until automatic showing is enabled.
472 ChangeSelection(start_rect, visible, end_rect, visible);
473 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
475 controller().OnLongPressEvent();
476 ChangeSelection(start_rect, visible, end_rect, visible);
477 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
478 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
480 start_rect.Offset(1, 0);
481 ChangeSelection(start_rect, visible, end_rect, visible);
482 // Selection movement does not currently trigger a separate event.
483 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
486 EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
487 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
490 TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) {
491 gfx::RectF start_rect(5, 5, 0, 10);
492 gfx::RectF end_rect(50, 5, 0, 10);
495 controller().OnLongPressEvent();
496 ChangeSelection(start_rect, visible, end_rect, visible);
497 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
498 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
500 // A long press triggering a new selection should re-send the SELECTION_SHOWN
501 // event notification.
502 start_rect.Offset(10, 10);
503 controller().OnLongPressEvent();
504 ChangeSelection(start_rect, visible, end_rect, visible);
505 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
506 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
509 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
510 base::TimeTicks event_time = base::TimeTicks::Now();
511 controller().OnLongPressEvent();
513 // The touch sequence should not be handled if selection is not active.
514 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
515 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
517 float line_height = 10.f;
518 gfx::RectF start_rect(0, 0, 0, line_height);
519 gfx::RectF end_rect(50, 0, 0, line_height);
521 ChangeSelection(start_rect, visible, end_rect, visible);
522 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
523 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
525 // The touch sequence should be handled only if the drawable reports a hit.
526 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
527 SetDraggingEnabled(true);
528 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
529 EXPECT_FALSE(GetAndResetSelectionMoved());
531 // The SelectBetweenCoordinates() result should reflect the movement. Note
532 // that the start coordinate will always reflect the "fixed" handle's
533 // position, in this case the position from |end_rect|.
534 // Note that the reported position is offset from the center of the
535 // input rects (i.e., the middle of the corresponding text line).
536 gfx::PointF fixed_offset = end_rect.CenterPoint();
537 gfx::PointF start_offset = start_rect.CenterPoint();
538 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
539 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
540 EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
541 EXPECT_TRUE(GetAndResetSelectionMoved());
542 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
543 EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
545 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
546 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
547 EXPECT_TRUE(GetAndResetSelectionMoved());
548 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
549 EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd());
551 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5);
552 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
553 EXPECT_TRUE(GetAndResetSelectionMoved());
554 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
555 EXPECT_EQ(start_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd());
557 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
558 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
559 EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
560 EXPECT_FALSE(GetAndResetSelectionMoved());
562 // Once the drag is complete, no more touch events should be consumed until
563 // the next ACTION_DOWN.
564 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
567 TEST_F(TouchSelectionControllerTest, SelectionDraggedWithOverlap) {
568 base::TimeTicks event_time = base::TimeTicks::Now();
569 controller().OnLongPressEvent();
571 float line_height = 10.f;
572 gfx::RectF start_rect(0, 0, 0, line_height);
573 gfx::RectF end_rect(50, 0, 0, line_height);
575 ChangeSelection(start_rect, visible, end_rect, visible);
576 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
577 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
579 // The ACTION_DOWN should lock to the closest handle.
580 gfx::PointF end_offset = end_rect.CenterPoint();
581 gfx::PointF fixed_offset = start_rect.CenterPoint();
582 float touch_down_x = (end_offset.x() + fixed_offset.x()) / 2 + 1.f;
583 MockMotionEvent event(
584 MockMotionEvent::ACTION_DOWN, event_time, touch_down_x, 0);
585 SetDraggingEnabled(true);
586 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
587 EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
588 EXPECT_FALSE(GetAndResetSelectionMoved());
590 // Even though the ACTION_MOVE is over the start handle, it should continue
591 // targetting the end handle that consumed the ACTION_DOWN.
592 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 0);
593 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
594 EXPECT_TRUE(GetAndResetSelectionMoved());
595 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
596 EXPECT_EQ(end_offset - gfx::Vector2dF(touch_down_x, 0),
597 GetLastSelectionEnd());
599 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
600 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
601 EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
602 EXPECT_FALSE(GetAndResetSelectionMoved());
605 TEST_F(TouchSelectionControllerTest, Animation) {
606 controller().OnTapEvent();
607 controller().OnSelectionEditable(true);
609 gfx::RectF insertion_rect(5, 5, 0, 10);
612 ChangeInsertion(insertion_rect, visible);
613 EXPECT_FALSE(GetAndResetNeedsAnimate());
616 ChangeInsertion(insertion_rect, visible);
617 EXPECT_TRUE(GetAndResetNeedsAnimate());
620 ChangeInsertion(insertion_rect, visible);
621 EXPECT_TRUE(GetAndResetNeedsAnimate());
623 // If the handles are explicity hidden, no animation should be triggered.
624 controller().HideAndDisallowShowingAutomatically();
625 EXPECT_FALSE(GetAndResetNeedsAnimate());
627 // If the client doesn't support animation, no animation should be triggered.
628 SetAnimationEnabled(false);
629 controller().OnTapEvent();
631 ChangeInsertion(insertion_rect, visible);
632 EXPECT_FALSE(GetAndResetNeedsAnimate());
635 TEST_F(TouchSelectionControllerTest, TemporarilyHidden) {
636 controller().OnTapEvent();
637 controller().OnSelectionEditable(true);
639 gfx::RectF insertion_rect(5, 5, 0, 10);
642 ChangeInsertion(insertion_rect, visible);
643 EXPECT_FALSE(GetAndResetNeedsAnimate());
645 controller().SetTemporarilyHidden(true);
646 EXPECT_TRUE(GetAndResetNeedsAnimate());
649 ChangeInsertion(insertion_rect, visible);
650 EXPECT_FALSE(GetAndResetNeedsAnimate());
653 ChangeInsertion(insertion_rect, visible);
654 EXPECT_FALSE(GetAndResetNeedsAnimate());
656 controller().SetTemporarilyHidden(false);
657 EXPECT_TRUE(GetAndResetNeedsAnimate());
660 TEST_F(TouchSelectionControllerTest, SelectionClearOnTap) {
661 gfx::RectF start_rect(5, 5, 0, 10);
662 gfx::RectF end_rect(50, 5, 0, 10);
665 controller().OnLongPressEvent();
666 ChangeSelection(start_rect, visible, end_rect, visible);
668 // Selection should not be cleared if the selection bounds have not changed.
669 controller().OnTapEvent();
670 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
671 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
673 controller().OnTapEvent();
675 EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
676 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
679 } // namespace content