Upstream version 10.39.225.0
[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 const int kDefaultTapTimeoutMs = 200;
16 const float kDefaulTapSlop = 10.f;
17
18 class MockTouchHandleDrawable : public TouchHandleDrawable {
19  public:
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_;
30   }
31
32  private:
33   bool* intersects_rect_;
34 };
35
36 }  // namespace
37
38 class TouchSelectionControllerTest : public testing::Test,
39                                      public TouchSelectionControllerClient {
40  public:
41   TouchSelectionControllerTest()
42       : last_event_(SELECTION_CLEARED),
43         caret_moved_(false),
44         selection_moved_(false),
45         needs_animate_(false),
46         animation_enabled_(true),
47         dragging_enabled_(false) {}
48
49   virtual ~TouchSelectionControllerTest() {}
50
51   // testing::Test implementation.
52   virtual void SetUp() OVERRIDE {
53     controller_.reset(new TouchSelectionController(
54         this,
55         base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs),
56         kDefaulTapSlop));
57   }
58
59   virtual void TearDown() OVERRIDE { controller_.reset(); }
60
61   // TouchSelectionControllerClient implementation.
62
63   virtual bool SupportsAnimation() const OVERRIDE { return animation_enabled_; }
64
65   virtual void SetNeedsAnimate() OVERRIDE { needs_animate_ = true; }
66
67   virtual void MoveCaret(const gfx::PointF& position) OVERRIDE {
68     caret_moved_ = true;
69     caret_position_ = position;
70   }
71
72   virtual void SelectBetweenCoordinates(const gfx::PointF& start,
73                                         const gfx::PointF& end) OVERRIDE {
74     selection_moved_ = true;
75     selection_start_ = start;
76     selection_end_ = end;
77   }
78
79   virtual void OnSelectionEvent(SelectionEventType event,
80                                 const gfx::PointF& end_position) OVERRIDE {
81     last_event_ = event;
82     last_event_start_ = end_position;
83   }
84
85   virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() OVERRIDE {
86     return scoped_ptr<TouchHandleDrawable>(
87         new MockTouchHandleDrawable(&dragging_enabled_));
88   }
89
90   void SetAnimationEnabled(bool enabled) { animation_enabled_ = enabled; }
91   void SetDraggingEnabled(bool enabled) { dragging_enabled_ = enabled; }
92
93   void ClearSelection() {
94     controller_->OnSelectionBoundsChanged(cc::ViewportSelectionBound(),
95                                           cc::ViewportSelectionBound());
96   }
97
98   void ClearInsertion() { ClearSelection(); }
99
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);
107   }
108
109   void ChangeSelection(const gfx::RectF& start_rect,
110                        bool start_visible,
111                        const gfx::RectF& end_rect,
112                        bool end_visible) {
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);
123   }
124
125   void Animate() {
126     base::TimeTicks now = base::TimeTicks::Now();
127     while (needs_animate_) {
128       needs_animate_ = controller_->Animate(now);
129       now += base::TimeDelta::FromMilliseconds(16);
130     }
131   }
132
133   bool GetAndResetNeedsAnimate() {
134     bool needs_animate = needs_animate_;
135     Animate();
136     return needs_animate;
137   }
138
139   bool GetAndResetCaretMoved() {
140     bool moved = caret_moved_;
141     caret_moved_ = false;
142     return moved;
143   }
144
145   bool GetAndResetSelectionMoved() {
146     bool moved = selection_moved_;
147     selection_moved_ = false;
148     return moved;
149   }
150
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_; }
156
157   TouchSelectionController& controller() { return *controller_; }
158
159  private:
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_;
165   bool caret_moved_;
166   bool selection_moved_;
167   bool needs_animate_;
168   bool animation_enabled_;
169   bool dragging_enabled_;
170   scoped_ptr<TouchSelectionController> controller_;
171 };
172
173 TEST_F(TouchSelectionControllerTest, InsertionBasic) {
174   gfx::RectF insertion_rect(5, 5, 0, 10);
175   bool visible = true;
176
177   // Insertion events are ignored until automatic showing is enabled.
178   ChangeInsertion(insertion_rect, visible);
179   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
180   controller().OnTapEvent();
181
182   // Insertion events are ignored until the selection region is marked editable.
183   ChangeInsertion(insertion_rect, visible);
184   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
185
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());
191
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());
196
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());
201
202   ClearInsertion();
203   EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
204 }
205
206 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
207   gfx::RectF insertion_rect(5, 5, 0, 10);
208   bool visible = true;
209   controller().OnTapEvent();
210   controller().OnSelectionEditable(true);
211
212   ChangeInsertion(insertion_rect, visible);
213   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
214   EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
215
216   controller().OnSelectionEditable(false);
217   EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
218 }
219
220 TEST_F(TouchSelectionControllerTest, InsertionStaysHiddenIfEmptyRegionTapped) {
221   gfx::RectF insertion_rect(5, 5, 0, 10);
222   bool visible = true;
223   controller().OnSelectionEditable(true);
224
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());
230
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());
237
238   // Reset the selection.
239   controller().HideAndDisallowShowingAutomatically();
240   EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
241
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());
249
250   // Single Tap on an empty edit field should clear insertion handle.
251   controller().OnTapEvent();
252   EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
253 }
254
255 TEST_F(TouchSelectionControllerTest, InsertionAppearsAfterTapFollowingTyping) {
256   gfx::RectF insertion_rect(5, 5, 0, 10);
257   bool visible = true;
258
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());
265
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());
271
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());
278 }
279
280 TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
281   controller().OnLongPressEvent();
282   controller().OnSelectionEditable(true);
283
284   gfx::RectF start_rect(5, 5, 0, 10);
285   gfx::RectF end_rect(50, 5, 0, 10);
286   bool visible = true;
287
288   ChangeInsertion(start_rect, visible);
289   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
290   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
291
292   ChangeSelection(start_rect, visible, end_rect, visible);
293   EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
294   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
295
296   ChangeInsertion(end_rect, visible);
297   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
298   EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
299
300   controller().HideAndDisallowShowingAutomatically();
301   EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
302
303   controller().OnTapEvent();
304   ChangeInsertion(end_rect, visible);
305   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
306   EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
307 }
308
309 TEST_F(TouchSelectionControllerTest, InsertionDragged) {
310   base::TimeTicks event_time = base::TimeTicks::Now();
311   controller().OnTapEvent();
312   controller().OnSelectionEditable(true);
313
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));
317
318   float line_height = 10.f;
319   gfx::RectF start_rect(10, 0, 0, line_height);
320   bool visible = true;
321   ChangeInsertion(start_rect, visible);
322   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
323   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
324
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());
330
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());
338
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());
343
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());
348
349   event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
350   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
351   EXPECT_FALSE(GetAndResetCaretMoved());
352
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));
356 }
357
358 TEST_F(TouchSelectionControllerTest, InsertionTapped) {
359   base::TimeTicks event_time = base::TimeTicks::Now();
360   controller().OnTapEvent();
361   controller().OnSelectionEditable(true);
362   SetDraggingEnabled(true);
363
364   gfx::RectF start_rect(10, 0, 0, 10);
365   bool visible = true;
366   ChangeInsertion(start_rect, visible);
367   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
368
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());
373
374   event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
375   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
376   EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
377
378   // Reset the insertion.
379   ClearInsertion();
380   controller().OnTapEvent();
381   ChangeInsertion(start_rect, visible);
382   ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
383
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),
389                           0,
390                           0);
391   EXPECT_TRUE(controller().WillHandleTouchEvent(event));
392   EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
393
394   // Reset the insertion.
395   ClearInsertion();
396   controller().OnTapEvent();
397   ChangeInsertion(start_rect, visible);
398   ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
399
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());
408
409   // Reset the insertion.
410   ClearInsertion();
411   controller().OnTapEvent();
412   ChangeInsertion(start_rect, visible);
413   ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
414
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());
421 }
422
423 TEST_F(TouchSelectionControllerTest, InsertionNotResetByRepeatedTapOrPress) {
424   base::TimeTicks event_time = base::TimeTicks::Now();
425   controller().OnTapEvent();
426   controller().OnSelectionEditable(true);
427   SetDraggingEnabled(true);
428
429   gfx::RectF anchor_rect(10, 0, 0, 10);
430   bool visible = true;
431   ChangeInsertion(anchor_rect, visible);
432   EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
433   EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
434
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());
441
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());
446
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());
451
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());
459
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());
464 }
465
466 TEST_F(TouchSelectionControllerTest, SelectionBasic) {
467   gfx::RectF start_rect(5, 5, 0, 10);
468   gfx::RectF end_rect(50, 5, 0, 10);
469   bool visible = true;
470
471   // Selection events are ignored until automatic showing is enabled.
472   ChangeSelection(start_rect, visible, end_rect, visible);
473   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
474
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());
479
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());
484
485   ClearSelection();
486   EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
487   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
488 }
489
490 TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) {
491   gfx::RectF start_rect(5, 5, 0, 10);
492   gfx::RectF end_rect(50, 5, 0, 10);
493   bool visible = true;
494
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());
499
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());
507 }
508
509 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
510   base::TimeTicks event_time = base::TimeTicks::Now();
511   controller().OnLongPressEvent();
512
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));
516
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);
520   bool visible = true;
521   ChangeSelection(start_rect, visible, end_rect, visible);
522   EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
523   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
524
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());
530
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());
544
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());
550
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());
556
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());
561
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));
565 }
566
567 TEST_F(TouchSelectionControllerTest, SelectionDraggedWithOverlap) {
568   base::TimeTicks event_time = base::TimeTicks::Now();
569   controller().OnLongPressEvent();
570
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);
574   bool visible = true;
575   ChangeSelection(start_rect, visible, end_rect, visible);
576   EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
577   EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
578
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());
589
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());
598
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());
603 }
604
605 TEST_F(TouchSelectionControllerTest, Animation) {
606   controller().OnTapEvent();
607   controller().OnSelectionEditable(true);
608
609   gfx::RectF insertion_rect(5, 5, 0, 10);
610
611   bool visible = true;
612   ChangeInsertion(insertion_rect, visible);
613   EXPECT_FALSE(GetAndResetNeedsAnimate());
614
615   visible = false;
616   ChangeInsertion(insertion_rect, visible);
617   EXPECT_TRUE(GetAndResetNeedsAnimate());
618
619   visible = true;
620   ChangeInsertion(insertion_rect, visible);
621   EXPECT_TRUE(GetAndResetNeedsAnimate());
622
623   // If the handles are explicity hidden, no animation should be triggered.
624   controller().HideAndDisallowShowingAutomatically();
625   EXPECT_FALSE(GetAndResetNeedsAnimate());
626
627   // If the client doesn't support animation, no animation should be triggered.
628   SetAnimationEnabled(false);
629   controller().OnTapEvent();
630   visible = true;
631   ChangeInsertion(insertion_rect, visible);
632   EXPECT_FALSE(GetAndResetNeedsAnimate());
633 }
634
635 TEST_F(TouchSelectionControllerTest, TemporarilyHidden) {
636   controller().OnTapEvent();
637   controller().OnSelectionEditable(true);
638
639   gfx::RectF insertion_rect(5, 5, 0, 10);
640
641   bool visible = true;
642   ChangeInsertion(insertion_rect, visible);
643   EXPECT_FALSE(GetAndResetNeedsAnimate());
644
645   controller().SetTemporarilyHidden(true);
646   EXPECT_TRUE(GetAndResetNeedsAnimate());
647
648   visible = false;
649   ChangeInsertion(insertion_rect, visible);
650   EXPECT_FALSE(GetAndResetNeedsAnimate());
651
652   visible = true;
653   ChangeInsertion(insertion_rect, visible);
654   EXPECT_FALSE(GetAndResetNeedsAnimate());
655
656   controller().SetTemporarilyHidden(false);
657   EXPECT_TRUE(GetAndResetNeedsAnimate());
658 }
659
660 TEST_F(TouchSelectionControllerTest, SelectionClearOnTap) {
661   gfx::RectF start_rect(5, 5, 0, 10);
662   gfx::RectF end_rect(50, 5, 0, 10);
663   bool visible = true;
664
665   controller().OnLongPressEvent();
666   ChangeSelection(start_rect, visible, end_rect, visible);
667
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());
672
673   controller().OnTapEvent();
674   ClearSelection();
675   EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
676   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
677 }
678
679 }  // namespace content