6389c38a722b29282d5ee1de7dc8c867557c91eb
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / input / touch_selection_controller_unittest.cc
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.
4
5 #include "content/browser/renderer_host/input/touch_selection_controller.h"
6
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "ui/events/test/mock_motion_event.h"
9
10 using ui::test::MockMotionEvent;
11
12 namespace content {
13 namespace {
14
15 class MockTouchHandleDrawable : public TouchHandleDrawable {
16  public:
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_;
27   }
28
29  private:
30   bool* intersects_rect_;
31 };
32
33 }  // namespace
34
35 class TouchSelectionControllerTest : public testing::Test,
36                                      public TouchSelectionControllerClient {
37  public:
38   TouchSelectionControllerTest()
39       : last_event_(SELECTION_CLEARED),
40         caret_moved_(false),
41         selection_moved_(false),
42         needs_animate_(false),
43         animation_enabled_(true),
44         dragging_enabled_(false) {}
45
46   virtual ~TouchSelectionControllerTest() {}
47
48   // testing::Test implementation.
49   virtual void SetUp() OVERRIDE {
50     controller_.reset(new TouchSelectionController(this));
51   }
52
53   virtual void TearDown() OVERRIDE { controller_.reset(); }
54
55   // TouchSelectionControllerClient implementation.
56
57   virtual bool SupportsAnimation() const OVERRIDE { return animation_enabled_; }
58
59   virtual void SetNeedsAnimate() OVERRIDE { needs_animate_ = true; }
60
61   virtual void MoveCaret(const gfx::PointF& position) OVERRIDE {
62     caret_moved_ = true;
63     caret_position_ = position;
64   }
65
66   virtual void SelectBetweenCoordinates(const gfx::PointF& start,
67                                         const gfx::PointF& end) OVERRIDE {
68     selection_moved_ = true;
69     selection_start_ = start;
70     selection_end_ = end;
71   }
72
73   virtual void OnSelectionEvent(SelectionEventType event,
74                                 const gfx::PointF& end_position) OVERRIDE {
75     last_event_ = event;
76     last_event_start_ = end_position;
77   }
78
79   virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() OVERRIDE {
80     return scoped_ptr<TouchHandleDrawable>(
81         new MockTouchHandleDrawable(&dragging_enabled_));
82   }
83
84   void SetAnimationEnabled(bool enabled) { animation_enabled_ = enabled; }
85   void SetDraggingEnabled(bool enabled) { dragging_enabled_ = enabled; }
86
87   void ClearSelection() {
88     controller_->OnSelectionBoundsChanged(gfx::RectF(),
89                                           TOUCH_HANDLE_ORIENTATION_UNDEFINED,
90                                           false,
91                                           gfx::RectF(),
92                                           TOUCH_HANDLE_ORIENTATION_UNDEFINED,
93                                           false);
94   }
95
96   void ClearInsertion() { ClearSelection(); }
97
98   void ChangeInsertion(const gfx::RectF& rect,
99                        TouchHandleOrientation orientation,
100                        bool visible) {
101     controller_->OnSelectionBoundsChanged(
102         rect, orientation, visible, rect, orientation, visible);
103   }
104
105   void ChangeInsertion(const gfx::RectF& rect, bool visible) {
106     ChangeInsertion(rect, TOUCH_HANDLE_CENTER, visible);
107   }
108
109   void ChangeSelection(const gfx::RectF& start_rect,
110                        TouchHandleOrientation start_orientation,
111                        bool start_visible,
112                        const gfx::RectF& end_rect,
113                        TouchHandleOrientation end_orientation,
114                        bool end_visible) {
115     controller_->OnSelectionBoundsChanged(start_rect,
116                                           start_orientation,
117                                           start_visible,
118                                           end_rect,
119                                           end_orientation,
120                                           end_visible);
121   }
122
123   void ChangeSelection(const gfx::RectF& start_rect,
124                        bool start_visible,
125                        const gfx::RectF& end_rect,
126                        bool end_visible) {
127     ChangeSelection(start_rect,
128                     TOUCH_HANDLE_LEFT,
129                     start_visible,
130                     end_rect,
131                     TOUCH_HANDLE_RIGHT,
132                     end_visible);
133   }
134
135   void Animate() {
136     base::TimeTicks now = base::TimeTicks::Now();
137     while (needs_animate_) {
138       needs_animate_ = controller_->Animate(now);
139       now += base::TimeDelta::FromMilliseconds(16);
140     }
141   }
142
143   bool GetAndResetNeedsAnimate() {
144     bool needs_animate = needs_animate_;
145     Animate();
146     return needs_animate;
147   }
148
149   bool GetAndResetCaretMoved() {
150     bool moved = caret_moved_;
151     caret_moved_ = false;
152     return moved;
153   }
154
155   bool GetAndResetSelectionMoved() {
156     bool moved = selection_moved_;
157     selection_moved_ = false;
158     return moved;
159   }
160
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_; }
166
167   TouchSelectionController& controller() { return *controller_; }
168
169  private:
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_;
175   bool caret_moved_;
176   bool selection_moved_;
177   bool needs_animate_;
178   bool animation_enabled_;
179   bool dragging_enabled_;
180   scoped_ptr<TouchSelectionController> controller_;
181 };
182
183 TEST_F(TouchSelectionControllerTest, InsertionBasic) {
184   gfx::RectF insertion_rect(5, 5, 0, 10);
185   bool visible = true;
186
187   // Insertion events are ignored until automatic showing is enabled.
188   ChangeInsertion(insertion_rect, visible);
189   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
190   controller().OnTapEvent();
191
192   // Insertion events are ignored until the selection region is marked editable.
193   ChangeInsertion(insertion_rect, visible);
194   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
195
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());
201
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());
206
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());
211
212   ClearInsertion();
213   EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
214 }
215
216 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
217   gfx::RectF insertion_rect(5, 5, 0, 10);
218   bool visible = true;
219   controller().OnTapEvent();
220   controller().OnSelectionEditable(true);
221
222   ChangeInsertion(insertion_rect, visible);
223   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
224   EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
225
226   controller().OnSelectionEditable(false);
227   EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
228 }
229
230 TEST_F(TouchSelectionControllerTest, InsertionStaysHiddenIfEmptyRegionTapped) {
231   gfx::RectF insertion_rect(5, 5, 0, 10);
232   bool visible = true;
233   controller().OnSelectionEditable(true);
234
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());
240
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());
247
248   // Reset the selection.
249   controller().HideAndDisallowShowingAutomatically();
250   EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
251
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());
259 }
260
261 TEST_F(TouchSelectionControllerTest, InsertionAppearsAfterTapFollowingTyping) {
262   gfx::RectF insertion_rect(5, 5, 0, 10);
263   bool visible = true;
264
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());
271
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());
277
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());
284 }
285
286 TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
287   controller().OnLongPressEvent();
288   controller().OnSelectionEditable(true);
289
290   gfx::RectF start_rect(5, 5, 0, 10);
291   gfx::RectF end_rect(50, 5, 0, 10);
292   bool visible = true;
293
294   ChangeInsertion(start_rect, visible);
295   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
296   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
297
298   ChangeSelection(start_rect, visible, end_rect, visible);
299   EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
300   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
301
302   ChangeInsertion(end_rect, visible);
303   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
304   EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
305
306   controller().HideAndDisallowShowingAutomatically();
307   EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
308
309   controller().OnTapEvent();
310   ChangeInsertion(end_rect, visible);
311   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
312   EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
313 }
314
315 TEST_F(TouchSelectionControllerTest, InsertionDragged) {
316   base::TimeTicks event_time = base::TimeTicks::Now();
317   controller().OnTapEvent();
318   controller().OnSelectionEditable(true);
319
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));
323
324   float line_height = 10.f;
325   gfx::RectF start_rect(10, 0, 0, line_height);
326   bool visible = true;
327   ChangeInsertion(start_rect, visible);
328   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
329   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
330
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());
336
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());
344
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());
349
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());
354
355   event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
356   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
357   EXPECT_FALSE(GetAndResetCaretMoved());
358
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));
362 }
363
364 TEST_F(TouchSelectionControllerTest, InsertionTapped) {
365   base::TimeTicks event_time = base::TimeTicks::Now();
366   controller().OnTapEvent();
367   controller().OnSelectionEditable(true);
368   SetDraggingEnabled(true);
369
370   gfx::RectF start_rect(10, 0, 0, 10);
371   bool visible = true;
372   ChangeInsertion(start_rect, visible);
373   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
374
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());
379
380   event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
381   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
382   EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
383
384   // Reset the insertion.
385   ClearInsertion();
386   controller().OnTapEvent();
387   ChangeInsertion(start_rect, visible);
388   ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
389
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),
395                           0,
396                           0);
397   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
398   EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
399
400   // Reset the insertion.
401   ClearInsertion();
402   controller().OnTapEvent();
403   ChangeInsertion(start_rect, visible);
404   ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
405
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());
412 }
413
414 TEST_F(TouchSelectionControllerTest, InsertionNotResetByRepeatedTapOrPress) {
415   base::TimeTicks event_time = base::TimeTicks::Now();
416   controller().OnTapEvent();
417   controller().OnSelectionEditable(true);
418   SetDraggingEnabled(true);
419
420   gfx::RectF anchor_rect(10, 0, 0, 10);
421   bool visible = true;
422   ChangeInsertion(anchor_rect, visible);
423   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
424   EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
425
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());
432
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());
437
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());
442
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());
450
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());
455 }
456
457 TEST_F(TouchSelectionControllerTest, SelectionBasic) {
458   gfx::RectF start_rect(5, 5, 0, 10);
459   gfx::RectF end_rect(50, 5, 0, 10);
460   bool visible = true;
461
462   // Selection events are ignored until automatic showing is enabled.
463   ChangeSelection(start_rect, visible, end_rect, visible);
464   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
465
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());
470
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());
475
476   ClearSelection();
477   EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
478   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
479 }
480
481 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
482   base::TimeTicks event_time = base::TimeTicks::Now();
483   controller().OnLongPressEvent();
484
485   // The touch sequence should not be handled if selection is not active.
486   MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
487   EXPECT_FALSE(controller().WillHandleTouchEvent(event));
488
489   float line_height = 10.f;
490   gfx::RectF start_rect(0, 0, 0, line_height);
491   gfx::RectF end_rect(50, 0, 0, line_height);
492   bool visible = true;
493   ChangeSelection(start_rect, visible, end_rect, visible);
494   EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
495   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
496
497   // The touch sequence should be handled only if the drawable reports a hit.
498   EXPECT_FALSE(controller().WillHandleTouchEvent(event));
499   SetDraggingEnabled(true);
500   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
501   EXPECT_FALSE(GetAndResetSelectionMoved());
502
503   // The SelectBetweenCoordinates() result should reflect the movement. Note
504   // that the start coordinate will always reflect the "fixed" handle's
505   // position, in this case the position from |end_rect|.
506   // Note that the reported position is offset from the center of the
507   // input rects (i.e., the middle of the corresponding text line).
508   gfx::PointF fixed_offset = end_rect.CenterPoint();
509   gfx::PointF start_offset = start_rect.CenterPoint();
510   event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
511   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
512   EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
513   EXPECT_TRUE(GetAndResetSelectionMoved());
514   EXPECT_EQ(fixed_offset, GetLastSelectionStart());
515   EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
516
517   event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
518   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
519   EXPECT_TRUE(GetAndResetSelectionMoved());
520   EXPECT_EQ(fixed_offset, GetLastSelectionStart());
521   EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd());
522
523   event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5);
524   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
525   EXPECT_TRUE(GetAndResetSelectionMoved());
526   EXPECT_EQ(fixed_offset, GetLastSelectionStart());
527   EXPECT_EQ(start_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd());
528
529   event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
530   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
531   EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
532   EXPECT_FALSE(GetAndResetSelectionMoved());
533
534   // Once the drag is complete, no more touch events should be consumed until
535   // the next ACTION_DOWN.
536   EXPECT_FALSE(controller().WillHandleTouchEvent(event));
537 }
538
539 TEST_F(TouchSelectionControllerTest, SelectionDraggedWithOverlap) {
540   base::TimeTicks event_time = base::TimeTicks::Now();
541   controller().OnLongPressEvent();
542
543   float line_height = 10.f;
544   gfx::RectF start_rect(0, 0, 0, line_height);
545   gfx::RectF end_rect(50, 0, 0, line_height);
546   bool visible = true;
547   ChangeSelection(start_rect, visible, end_rect, visible);
548   EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
549   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
550
551   // The ACTION_DOWN should lock to the closest handle.
552   gfx::PointF end_offset = end_rect.CenterPoint();
553   gfx::PointF fixed_offset = start_rect.CenterPoint();
554   float touch_down_x = (end_offset.x() + fixed_offset.x()) / 2 + 1.f;
555   MockMotionEvent event(
556       MockMotionEvent::ACTION_DOWN, event_time, touch_down_x, 0);
557   SetDraggingEnabled(true);
558   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
559   EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
560   EXPECT_FALSE(GetAndResetSelectionMoved());
561
562   // Even though the ACTION_MOVE is over the start handle, it should continue
563   // targetting the end handle that consumed the ACTION_DOWN.
564   event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 0);
565   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
566   EXPECT_TRUE(GetAndResetSelectionMoved());
567   EXPECT_EQ(fixed_offset, GetLastSelectionStart());
568   EXPECT_EQ(end_offset - gfx::Vector2dF(touch_down_x, 0),
569             GetLastSelectionEnd());
570
571   event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
572   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
573   EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
574   EXPECT_FALSE(GetAndResetSelectionMoved());
575 }
576
577 TEST_F(TouchSelectionControllerTest, Animation) {
578   controller().OnTapEvent();
579   controller().OnSelectionEditable(true);
580
581   gfx::RectF insertion_rect(5, 5, 0, 10);
582
583   bool visible = true;
584   ChangeInsertion(insertion_rect, visible);
585   EXPECT_FALSE(GetAndResetNeedsAnimate());
586
587   visible = false;
588   ChangeInsertion(insertion_rect, visible);
589   EXPECT_TRUE(GetAndResetNeedsAnimate());
590
591   visible = true;
592   ChangeInsertion(insertion_rect, visible);
593   EXPECT_TRUE(GetAndResetNeedsAnimate());
594
595   // If the handles are explicity hidden, no animation should be triggered.
596   controller().HideAndDisallowShowingAutomatically();
597   EXPECT_FALSE(GetAndResetNeedsAnimate());
598
599   // If the client doesn't support animation, no animation should be triggered.
600   SetAnimationEnabled(false);
601   controller().OnTapEvent();
602   visible = true;
603   ChangeInsertion(insertion_rect, visible);
604   EXPECT_FALSE(GetAndResetNeedsAnimate());
605 }
606
607 TEST_F(TouchSelectionControllerTest, TemporarilyHidden) {
608   controller().OnTapEvent();
609   controller().OnSelectionEditable(true);
610
611   gfx::RectF insertion_rect(5, 5, 0, 10);
612
613   bool visible = true;
614   ChangeInsertion(insertion_rect, visible);
615   EXPECT_FALSE(GetAndResetNeedsAnimate());
616
617   controller().SetTemporarilyHidden(true);
618   EXPECT_TRUE(GetAndResetNeedsAnimate());
619
620   visible = false;
621   ChangeInsertion(insertion_rect, visible);
622   EXPECT_FALSE(GetAndResetNeedsAnimate());
623
624   visible = true;
625   ChangeInsertion(insertion_rect, visible);
626   EXPECT_FALSE(GetAndResetNeedsAnimate());
627
628   controller().SetTemporarilyHidden(false);
629   EXPECT_TRUE(GetAndResetNeedsAnimate());
630 }
631
632 }  // namespace content