Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: content/browser/renderer_host/input/touch_selection_controller_unittest.cc

Issue 335943002: [Android] Composited selection handle rendering (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@input_native_handles_final
Patch Set: Fix animation tests Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 : contains_point_(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 ContainsPoint(const gfx::PointF& point) const OVERRIDE {
26 return *contains_point_;
27 }
28
29 private:
30 bool* contains_point_;
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& anchor_position) OVERRIDE {
75 last_event_ = event;
76 last_event_anchor_ = anchor_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& anchor_rect,
110 TouchHandleOrientation anchor_orientation,
111 bool anchor_visible,
112 const gfx::RectF& focus_rect,
113 TouchHandleOrientation focus_orientation,
114 bool focus_visible) {
115 controller_->OnSelectionBoundsChanged(anchor_rect,
116 anchor_orientation,
117 anchor_visible,
118 focus_rect,
119 focus_orientation,
120 focus_visible);
121 }
122
123 void ChangeSelection(const gfx::RectF& anchor_rect,
124 bool anchor_visible,
125 const gfx::RectF& focus_rect,
126 bool focus_visible) {
127 ChangeSelection(anchor_rect,
128 TOUCH_HANDLE_LEFT,
129 anchor_visible,
130 focus_rect,
131 TOUCH_HANDLE_RIGHT,
132 focus_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_anchor_; }
166
167 TouchSelectionController& controller() { return *controller_; }
168
169 private:
170 gfx::PointF last_event_anchor_;
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().ShowInsertionHandleAutomatically();
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 controller().OnSelectionEditable(true);
196
197 ChangeInsertion(insertion_rect, visible);
198 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
199 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
200
201 insertion_rect.Offset(1, 0);
202 ChangeInsertion(insertion_rect, visible);
203 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
204 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
205
206 insertion_rect.Offset(0, 1);
207 ChangeInsertion(insertion_rect, visible);
208 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
209 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
210
211 ClearInsertion();
212 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
213 }
214
215 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
216 gfx::RectF insertion_rect(5, 5, 0, 10);
217 bool visible = true;
218 controller().ShowInsertionHandleAutomatically();
219 controller().OnSelectionEditable(true);
220
221 ChangeInsertion(insertion_rect, visible);
222 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
223 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
224
225 controller().OnSelectionEditable(false);
226 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
227 }
228
229 TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
230 controller().ShowSelectionHandlesAutomatically();
231 controller().ShowInsertionHandleAutomatically();
232 controller().OnSelectionEditable(true);
233
234 gfx::RectF anchor_rect(5, 5, 0, 10);
235 gfx::RectF focus_rect(50, 5, 0, 10);
236 bool visible = true;
237
238 ChangeInsertion(anchor_rect, visible);
239 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
240 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
241
242 ChangeSelection(anchor_rect, visible, focus_rect, visible);
243 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
244 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
245
246 ChangeInsertion(focus_rect, visible);
247 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
248 EXPECT_EQ(focus_rect.bottom_left(), GetLastEventAnchor());
249
250 controller().HideAndDisallowAutomaticShowing();
251 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
252
253 controller().ShowInsertionHandleAutomatically();
254 ChangeInsertion(focus_rect, visible);
255 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
256 EXPECT_EQ(focus_rect.bottom_left(), GetLastEventAnchor());
257 }
258
259 TEST_F(TouchSelectionControllerTest, InsertionDragged) {
260 base::TimeTicks event_time = base::TimeTicks::Now();
261 controller().ShowInsertionHandleAutomatically();
262 controller().OnSelectionEditable(true);
263
264 // The touch sequence should not be handled if insertion is not active.
265 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
266 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
267
268 float line_height = 10.f;
269 gfx::RectF anchor_rect(10, 0, 0, line_height);
270 bool visible = true;
271 ChangeInsertion(anchor_rect, visible);
272 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
273 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
274
275 // The touch sequence should be handled only if the drawable reports a hit.
276 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
277 SetDraggingEnabled(true);
278 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
279 EXPECT_FALSE(GetAndResetCaretMoved());
280
281 // The MoveCaret() result should reflect the movement.
282 // The reported position is offset from the center of |anchor_rect|.
283 gfx::PointF anchor_offset = anchor_rect.CenterPoint();
284 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
285 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
286 EXPECT_TRUE(GetAndResetCaretMoved());
287 EXPECT_EQ(anchor_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition());
288
289 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
290 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
291 EXPECT_TRUE(GetAndResetCaretMoved());
292 EXPECT_EQ(anchor_offset + gfx::Vector2dF(5, 5), GetLastCaretPosition());
293
294 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 10);
295 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
296 EXPECT_TRUE(GetAndResetCaretMoved());
297 EXPECT_EQ(anchor_offset + gfx::Vector2dF(10, 10), GetLastCaretPosition());
298
299 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
300 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
301 EXPECT_FALSE(GetAndResetCaretMoved());
302
303 // Once the drag is complete, no more touch events should be consumed until
304 // the next ACTION_DOWN.
305 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
306 }
307
308 TEST_F(TouchSelectionControllerTest, InsertionTapped) {
309 base::TimeTicks event_time = base::TimeTicks::Now();
310 controller().ShowInsertionHandleAutomatically();
311 controller().OnSelectionEditable(true);
312 SetDraggingEnabled(true);
313
314 gfx::RectF anchor_rect(10, 0, 0, 10);
315 bool visible = true;
316 ChangeInsertion(anchor_rect, visible);
317 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
318
319 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
320 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
321 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
322
323 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
324 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
325 EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
326
327 // Reset the insertion.
328 ClearInsertion();
329 controller().ShowInsertionHandleAutomatically();
330 ChangeInsertion(anchor_rect, visible);
331 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
332
333 // No tap should be signalled if the time between DOWN and UP was too long.
334 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
335 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
336 event = MockMotionEvent(MockMotionEvent::ACTION_UP,
337 event_time + base::TimeDelta::FromSeconds(1),
338 0,
339 0);
340 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
341 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
342
343 // Reset the insertion.
344 ClearInsertion();
345 controller().ShowInsertionHandleAutomatically();
346 ChangeInsertion(anchor_rect, visible);
347 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
348
349 // No tap should be signalled if the touch sequence is cancelled.
350 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
351 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
352 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
353 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
354 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
355 }
356
357 TEST_F(TouchSelectionControllerTest, SelectionBasic) {
358 gfx::RectF anchor_rect(5, 5, 0, 10);
359 gfx::RectF focus_rect(50, 5, 0, 10);
360 bool visible = true;
361
362 // Selection events are ignored until automatic showing is enabled.
363 ChangeSelection(anchor_rect, visible, focus_rect, visible);
364 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
365
366 controller().ShowSelectionHandlesAutomatically();
367 ChangeSelection(anchor_rect, visible, focus_rect, visible);
368 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
369 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
370
371 anchor_rect.Offset(1, 0);
372 ChangeSelection(anchor_rect, visible, focus_rect, visible);
373 // Selection movement does not currently trigger a separate event.
374 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
375
376 ClearSelection();
377 EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
378 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
379 }
380
381 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
382 base::TimeTicks event_time = base::TimeTicks::Now();
383 controller().ShowSelectionHandlesAutomatically();
384
385 // The touch sequence should not be handled if selection is not active.
386 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
387 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
388
389 float line_height = 10.f;
390 gfx::RectF anchor_rect(0, 0, 0, line_height);
391 gfx::RectF focus_rect(50, 0, 0, line_height);
392 bool visible = true;
393 ChangeSelection(anchor_rect, visible, focus_rect, visible);
394 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
395 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
396
397 // The touch sequence should be handled only if the drawable reports a hit.
398 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
399 SetDraggingEnabled(true);
400 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
401 EXPECT_FALSE(GetAndResetSelectionMoved());
402
403 // The SelectBetweenCoordinates() result should reflect the movement. Note
404 // that the start coordinate will always reflect the "fixed" handle's
405 // position, in this case the position from |focus_rect|.
406 // Note that the reported position is offset from the center of the
407 // input rects (i.e., the middle of the corresponding text line).
408 gfx::PointF fixed_offset = focus_rect.CenterPoint();
409 gfx::PointF anchor_offset = anchor_rect.CenterPoint();
410 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
411 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
412 EXPECT_TRUE(GetAndResetSelectionMoved());
413 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
414 EXPECT_EQ(anchor_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
415
416 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
417 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
418 EXPECT_TRUE(GetAndResetSelectionMoved());
419 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
420 EXPECT_EQ(anchor_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd());
421
422 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5);
423 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
424 EXPECT_TRUE(GetAndResetSelectionMoved());
425 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
426 EXPECT_EQ(anchor_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd());
427
428 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
429 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
430 EXPECT_FALSE(GetAndResetSelectionMoved());
431
432 // Once the drag is complete, no more touch events should be consumed until
433 // the next ACTION_DOWN.
434 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
435 }
436
437 TEST_F(TouchSelectionControllerTest, Animation) {
438 controller().ShowInsertionHandleAutomatically();
439 controller().OnSelectionEditable(true);
440
441 gfx::RectF insertion_rect(5, 5, 0, 10);
442
443 bool visible = true;
444 ChangeInsertion(insertion_rect, visible);
445 EXPECT_FALSE(GetAndResetNeedsAnimate());
446
447 visible = false;
448 ChangeInsertion(insertion_rect, visible);
449 EXPECT_TRUE(GetAndResetNeedsAnimate());
450
451 visible = true;
452 ChangeInsertion(insertion_rect, visible);
453 EXPECT_TRUE(GetAndResetNeedsAnimate());
454
455 // If the handles are explicity hidden, no animation should be triggered.
456 controller().HideAndDisallowAutomaticShowing();
457 EXPECT_FALSE(GetAndResetNeedsAnimate());
458
459 // If the client doesn't support animation, no animation should be triggered.
460 SetAnimationEnabled(false);
461 controller().ShowInsertionHandleAutomatically();
462 visible = true;
463 ChangeInsertion(insertion_rect, visible);
464 EXPECT_FALSE(GetAndResetNeedsAnimate());
465 }
466
467 TEST_F(TouchSelectionControllerTest, TemporarilyHidden) {
468 controller().ShowInsertionHandleAutomatically();
469 controller().OnSelectionEditable(true);
470
471 gfx::RectF insertion_rect(5, 5, 0, 10);
472
473 bool visible = true;
474 ChangeInsertion(insertion_rect, visible);
475 EXPECT_FALSE(GetAndResetNeedsAnimate());
476
477 controller().SetTemporarilyHidden(true);
478 EXPECT_TRUE(GetAndResetNeedsAnimate());
479
480 visible = false;
481 ChangeInsertion(insertion_rect, visible);
482 EXPECT_FALSE(GetAndResetNeedsAnimate());
483
484 visible = true;
485 ChangeInsertion(insertion_rect, visible);
486 EXPECT_FALSE(GetAndResetNeedsAnimate());
487
488 controller().SetTemporarilyHidden(false);
489 EXPECT_TRUE(GetAndResetNeedsAnimate());
490 }
491
492 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698