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 class MockTouchHandleDrawable : public TouchHandleDrawable {
17 explicit MockTouchHandleDrawable(bool* contains_point)
18 : intersects_rect_(contains_point) {}
19 virtual ~MockTouchHandleDrawable() {}
20 virtual void SetEnabled(bool enabled) OVERRIDE {}
21 virtual void SetOrientation(TouchHandleOrientation orientation) OVERRIDE {}
22 virtual void SetAlpha(float alpha) OVERRIDE {}
23 virtual void SetFocus(const gfx::PointF& position) OVERRIDE {}
24 virtual void SetVisible(bool visible) OVERRIDE {}
25 virtual bool IntersectsWith(const gfx::RectF& rect) const OVERRIDE {
26 return *intersects_rect_;
30 bool* intersects_rect_;
35 class TouchSelectionControllerTest : public testing::Test,
36 public TouchSelectionControllerClient {
38 TouchSelectionControllerTest()
39 : last_event_(SELECTION_CLEARED),
41 selection_moved_(false),
42 needs_animate_(false),
43 animation_enabled_(true),
44 dragging_enabled_(false) {}
46 virtual ~TouchSelectionControllerTest() {}
48 // testing::Test implementation.
49 virtual void SetUp() OVERRIDE {
50 controller_.reset(new TouchSelectionController(this));
53 virtual void TearDown() OVERRIDE { controller_.reset(); }
55 // TouchSelectionControllerClient implementation.
57 virtual bool SupportsAnimation() const OVERRIDE { return animation_enabled_; }
59 virtual void SetNeedsAnimate() OVERRIDE { needs_animate_ = true; }
61 virtual void MoveCaret(const gfx::PointF& position) OVERRIDE {
63 caret_position_ = position;
66 virtual void SelectBetweenCoordinates(const gfx::PointF& start,
67 const gfx::PointF& end) OVERRIDE {
68 selection_moved_ = true;
69 selection_start_ = start;
73 virtual void OnSelectionEvent(SelectionEventType event,
74 const gfx::PointF& end_position) OVERRIDE {
76 last_event_start_ = end_position;
79 virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() OVERRIDE {
80 return scoped_ptr<TouchHandleDrawable>(
81 new MockTouchHandleDrawable(&dragging_enabled_));
84 void SetAnimationEnabled(bool enabled) { animation_enabled_ = enabled; }
85 void SetDraggingEnabled(bool enabled) { dragging_enabled_ = enabled; }
87 void ClearSelection() {
88 controller_->OnSelectionBoundsChanged(gfx::RectF(),
89 TOUCH_HANDLE_ORIENTATION_UNDEFINED,
92 TOUCH_HANDLE_ORIENTATION_UNDEFINED,
96 void ClearInsertion() { ClearSelection(); }
98 void ChangeInsertion(const gfx::RectF& rect,
99 TouchHandleOrientation orientation,
101 controller_->OnSelectionBoundsChanged(
102 rect, orientation, visible, rect, orientation, visible);
105 void ChangeInsertion(const gfx::RectF& rect, bool visible) {
106 ChangeInsertion(rect, TOUCH_HANDLE_CENTER, visible);
109 void ChangeSelection(const gfx::RectF& start_rect,
110 TouchHandleOrientation start_orientation,
112 const gfx::RectF& end_rect,
113 TouchHandleOrientation end_orientation,
115 controller_->OnSelectionBoundsChanged(start_rect,
123 void ChangeSelection(const gfx::RectF& start_rect,
125 const gfx::RectF& end_rect,
127 ChangeSelection(start_rect,
136 base::TimeTicks now = base::TimeTicks::Now();
137 while (needs_animate_) {
138 needs_animate_ = controller_->Animate(now);
139 now += base::TimeDelta::FromMilliseconds(16);
143 bool GetAndResetNeedsAnimate() {
144 bool needs_animate = needs_animate_;
146 return needs_animate;
149 bool GetAndResetCaretMoved() {
150 bool moved = caret_moved_;
151 caret_moved_ = false;
155 bool GetAndResetSelectionMoved() {
156 bool moved = selection_moved_;
157 selection_moved_ = false;
161 const gfx::PointF& GetLastCaretPosition() const { return caret_position_; }
162 const gfx::PointF& GetLastSelectionStart() const { return selection_start_; }
163 const gfx::PointF& GetLastSelectionEnd() const { return selection_end_; }
164 SelectionEventType GetLastEventType() const { return last_event_; }
165 const gfx::PointF& GetLastEventAnchor() const { return last_event_start_; }
167 TouchSelectionController& controller() { return *controller_; }
170 gfx::PointF last_event_start_;
171 gfx::PointF caret_position_;
172 gfx::PointF selection_start_;
173 gfx::PointF selection_end_;
174 SelectionEventType last_event_;
176 bool selection_moved_;
178 bool animation_enabled_;
179 bool dragging_enabled_;
180 scoped_ptr<TouchSelectionController> controller_;
183 TEST_F(TouchSelectionControllerTest, InsertionBasic) {
184 gfx::RectF insertion_rect(5, 5, 0, 10);
187 // Insertion events are ignored until automatic showing is enabled.
188 ChangeInsertion(insertion_rect, visible);
189 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
190 controller().OnTapEvent();
192 // Insertion events are ignored until the selection region is marked editable.
193 ChangeInsertion(insertion_rect, visible);
194 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
196 controller().OnTapEvent();
197 controller().OnSelectionEditable(true);
198 ChangeInsertion(insertion_rect, visible);
199 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
200 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
202 insertion_rect.Offset(1, 0);
203 ChangeInsertion(insertion_rect, visible);
204 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
205 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
207 insertion_rect.Offset(0, 1);
208 ChangeInsertion(insertion_rect, visible);
209 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
210 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
213 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
216 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
217 gfx::RectF insertion_rect(5, 5, 0, 10);
219 controller().OnTapEvent();
220 controller().OnSelectionEditable(true);
222 ChangeInsertion(insertion_rect, visible);
223 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
224 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
226 controller().OnSelectionEditable(false);
227 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
230 TEST_F(TouchSelectionControllerTest, InsertionStaysHiddenIfEmptyRegionTapped) {
231 gfx::RectF insertion_rect(5, 5, 0, 10);
233 controller().OnSelectionEditable(true);
235 // Taps should be ignored if they're in an empty editable region.
236 controller().OnTapEvent();
237 controller().OnSelectionEmpty(true);
238 ChangeInsertion(insertion_rect, visible);
239 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
241 // Once the region becomes editable, taps should show the insertion handle.
242 controller().OnTapEvent();
243 controller().OnSelectionEmpty(false);
244 ChangeInsertion(insertion_rect, visible);
245 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
246 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
248 // Reset the selection.
249 controller().HideAndDisallowShowingAutomatically();
250 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
252 // Long-pressing should show the handle even if the editable region is empty.
253 insertion_rect.Offset(2, -2);
254 controller().OnLongPressEvent();
255 controller().OnSelectionEmpty(true);
256 ChangeInsertion(insertion_rect, visible);
257 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
258 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
261 TEST_F(TouchSelectionControllerTest, InsertionAppearsAfterTapFollowingTyping) {
262 gfx::RectF insertion_rect(5, 5, 0, 10);
265 // Simulate the user tapping an empty text field.
266 controller().OnTapEvent();
267 controller().OnSelectionEditable(true);
268 controller().OnSelectionEmpty(true);
269 ChangeInsertion(insertion_rect, visible);
270 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
272 // Simulate the cursor moving while a user is typing.
273 insertion_rect.Offset(10, 0);
274 controller().OnSelectionEmpty(false);
275 ChangeInsertion(insertion_rect, visible);
276 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
278 // If the user taps the *same* position as the cursor at the end of the text
279 // entry, the handle should appear.
280 controller().OnTapEvent();
281 ChangeInsertion(insertion_rect, visible);
282 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
283 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
286 TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
287 controller().OnLongPressEvent();
288 controller().OnSelectionEditable(true);
290 gfx::RectF start_rect(5, 5, 0, 10);
291 gfx::RectF end_rect(50, 5, 0, 10);
294 ChangeInsertion(start_rect, visible);
295 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
296 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
298 ChangeSelection(start_rect, visible, end_rect, visible);
299 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
300 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
302 ChangeInsertion(end_rect, visible);
303 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
304 EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
306 controller().HideAndDisallowShowingAutomatically();
307 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
309 controller().OnTapEvent();
310 ChangeInsertion(end_rect, visible);
311 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
312 EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
315 TEST_F(TouchSelectionControllerTest, InsertionDragged) {
316 base::TimeTicks event_time = base::TimeTicks::Now();
317 controller().OnTapEvent();
318 controller().OnSelectionEditable(true);
320 // The touch sequence should not be handled if insertion is not active.
321 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
322 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
324 float line_height = 10.f;
325 gfx::RectF start_rect(10, 0, 0, line_height);
327 ChangeInsertion(start_rect, visible);
328 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
329 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
331 // The touch sequence should be handled only if the drawable reports a hit.
332 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
333 SetDraggingEnabled(true);
334 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
335 EXPECT_FALSE(GetAndResetCaretMoved());
337 // The MoveCaret() result should reflect the movement.
338 // The reported position is offset from the center of |start_rect|.
339 gfx::PointF start_offset = start_rect.CenterPoint();
340 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
341 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
342 EXPECT_TRUE(GetAndResetCaretMoved());
343 EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition());
345 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
346 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
347 EXPECT_TRUE(GetAndResetCaretMoved());
348 EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastCaretPosition());
350 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 10);
351 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
352 EXPECT_TRUE(GetAndResetCaretMoved());
353 EXPECT_EQ(start_offset + gfx::Vector2dF(10, 10), GetLastCaretPosition());
355 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
356 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
357 EXPECT_FALSE(GetAndResetCaretMoved());
359 // Once the drag is complete, no more touch events should be consumed until
360 // the next ACTION_DOWN.
361 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
364 TEST_F(TouchSelectionControllerTest, InsertionTapped) {
365 base::TimeTicks event_time = base::TimeTicks::Now();
366 controller().OnTapEvent();
367 controller().OnSelectionEditable(true);
368 SetDraggingEnabled(true);
370 gfx::RectF start_rect(10, 0, 0, 10);
372 ChangeInsertion(start_rect, visible);
373 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
375 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
376 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
377 //TODO(AKV): this test case has to be modified once crbug.com/394093 is fixed.
378 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
380 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
381 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
382 EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
384 // Reset the insertion.
386 controller().OnTapEvent();
387 ChangeInsertion(start_rect, visible);
388 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
390 // No tap should be signalled if the time between DOWN and UP was too long.
391 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
392 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
393 event = MockMotionEvent(MockMotionEvent::ACTION_UP,
394 event_time + base::TimeDelta::FromSeconds(1),
397 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
398 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
400 // Reset the insertion.
402 controller().OnTapEvent();
403 ChangeInsertion(start_rect, visible);
404 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
406 // No tap should be signalled if the touch sequence is cancelled.
407 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
408 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
409 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
410 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
411 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
414 TEST_F(TouchSelectionControllerTest, InsertionNotResetByRepeatedTapOrPress) {
415 base::TimeTicks event_time = base::TimeTicks::Now();
416 controller().OnTapEvent();
417 controller().OnSelectionEditable(true);
418 SetDraggingEnabled(true);
420 gfx::RectF anchor_rect(10, 0, 0, 10);
422 ChangeInsertion(anchor_rect, visible);
423 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
424 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
426 // Tapping again shouldn't reset the active insertion point.
427 controller().OnTapEvent();
428 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
429 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
430 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
431 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
433 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
434 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
435 EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
436 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
438 anchor_rect.Offset(5, 15);
439 ChangeInsertion(anchor_rect, visible);
440 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
441 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
443 // Pressing shouldn't reset the active insertion point.
444 controller().OnLongPressEvent();
445 controller().OnSelectionEmpty(true);
446 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
447 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
448 EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
449 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
451 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
452 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
453 EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
454 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
457 TEST_F(TouchSelectionControllerTest, SelectionBasic) {
458 gfx::RectF start_rect(5, 5, 0, 10);
459 gfx::RectF end_rect(50, 5, 0, 10);
462 // Selection events are ignored until automatic showing is enabled.
463 ChangeSelection(start_rect, visible, end_rect, visible);
464 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
466 controller().OnLongPressEvent();
467 ChangeSelection(start_rect, visible, end_rect, visible);
468 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
469 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
471 start_rect.Offset(1, 0);
472 ChangeSelection(start_rect, visible, end_rect, visible);
473 // Selection movement does not currently trigger a separate event.
474 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
477 EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
478 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
481 TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) {
482 gfx::RectF start_rect(5, 5, 0, 10);
483 gfx::RectF end_rect(50, 5, 0, 10);
486 controller().OnLongPressEvent();
487 ChangeSelection(start_rect, visible, end_rect, visible);
488 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
489 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
491 // A long press triggering a new selection should re-send the SELECTION_SHOWN
492 // event notification.
493 start_rect.Offset(10, 10);
494 controller().OnLongPressEvent();
495 ChangeSelection(start_rect, visible, end_rect, visible);
496 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
497 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
500 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
501 base::TimeTicks event_time = base::TimeTicks::Now();
502 controller().OnLongPressEvent();
504 // The touch sequence should not be handled if selection is not active.
505 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
506 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
508 float line_height = 10.f;
509 gfx::RectF start_rect(0, 0, 0, line_height);
510 gfx::RectF end_rect(50, 0, 0, line_height);
512 ChangeSelection(start_rect, visible, end_rect, visible);
513 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
514 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
516 // The touch sequence should be handled only if the drawable reports a hit.
517 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
518 SetDraggingEnabled(true);
519 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
520 EXPECT_FALSE(GetAndResetSelectionMoved());
522 // The SelectBetweenCoordinates() result should reflect the movement. Note
523 // that the start coordinate will always reflect the "fixed" handle's
524 // position, in this case the position from |end_rect|.
525 // Note that the reported position is offset from the center of the
526 // input rects (i.e., the middle of the corresponding text line).
527 gfx::PointF fixed_offset = end_rect.CenterPoint();
528 gfx::PointF start_offset = start_rect.CenterPoint();
529 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
530 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
531 EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
532 EXPECT_TRUE(GetAndResetSelectionMoved());
533 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
534 EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
536 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
537 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
538 EXPECT_TRUE(GetAndResetSelectionMoved());
539 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
540 EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd());
542 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5);
543 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
544 EXPECT_TRUE(GetAndResetSelectionMoved());
545 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
546 EXPECT_EQ(start_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd());
548 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
549 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
550 EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
551 EXPECT_FALSE(GetAndResetSelectionMoved());
553 // Once the drag is complete, no more touch events should be consumed until
554 // the next ACTION_DOWN.
555 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
558 TEST_F(TouchSelectionControllerTest, SelectionDraggedWithOverlap) {
559 base::TimeTicks event_time = base::TimeTicks::Now();
560 controller().OnLongPressEvent();
562 float line_height = 10.f;
563 gfx::RectF start_rect(0, 0, 0, line_height);
564 gfx::RectF end_rect(50, 0, 0, line_height);
566 ChangeSelection(start_rect, visible, end_rect, visible);
567 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
568 EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
570 // The ACTION_DOWN should lock to the closest handle.
571 gfx::PointF end_offset = end_rect.CenterPoint();
572 gfx::PointF fixed_offset = start_rect.CenterPoint();
573 float touch_down_x = (end_offset.x() + fixed_offset.x()) / 2 + 1.f;
574 MockMotionEvent event(
575 MockMotionEvent::ACTION_DOWN, event_time, touch_down_x, 0);
576 SetDraggingEnabled(true);
577 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
578 EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
579 EXPECT_FALSE(GetAndResetSelectionMoved());
581 // Even though the ACTION_MOVE is over the start handle, it should continue
582 // targetting the end handle that consumed the ACTION_DOWN.
583 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 0);
584 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
585 EXPECT_TRUE(GetAndResetSelectionMoved());
586 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
587 EXPECT_EQ(end_offset - gfx::Vector2dF(touch_down_x, 0),
588 GetLastSelectionEnd());
590 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
591 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
592 EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
593 EXPECT_FALSE(GetAndResetSelectionMoved());
596 TEST_F(TouchSelectionControllerTest, Animation) {
597 controller().OnTapEvent();
598 controller().OnSelectionEditable(true);
600 gfx::RectF insertion_rect(5, 5, 0, 10);
603 ChangeInsertion(insertion_rect, visible);
604 EXPECT_FALSE(GetAndResetNeedsAnimate());
607 ChangeInsertion(insertion_rect, visible);
608 EXPECT_TRUE(GetAndResetNeedsAnimate());
611 ChangeInsertion(insertion_rect, visible);
612 EXPECT_TRUE(GetAndResetNeedsAnimate());
614 // If the handles are explicity hidden, no animation should be triggered.
615 controller().HideAndDisallowShowingAutomatically();
616 EXPECT_FALSE(GetAndResetNeedsAnimate());
618 // If the client doesn't support animation, no animation should be triggered.
619 SetAnimationEnabled(false);
620 controller().OnTapEvent();
622 ChangeInsertion(insertion_rect, visible);
623 EXPECT_FALSE(GetAndResetNeedsAnimate());
626 TEST_F(TouchSelectionControllerTest, TemporarilyHidden) {
627 controller().OnTapEvent();
628 controller().OnSelectionEditable(true);
630 gfx::RectF insertion_rect(5, 5, 0, 10);
633 ChangeInsertion(insertion_rect, visible);
634 EXPECT_FALSE(GetAndResetNeedsAnimate());
636 controller().SetTemporarilyHidden(true);
637 EXPECT_TRUE(GetAndResetNeedsAnimate());
640 ChangeInsertion(insertion_rect, visible);
641 EXPECT_FALSE(GetAndResetNeedsAnimate());
644 ChangeInsertion(insertion_rect, visible);
645 EXPECT_FALSE(GetAndResetNeedsAnimate());
647 controller().SetTemporarilyHidden(false);
648 EXPECT_TRUE(GetAndResetNeedsAnimate());
651 } // namespace content