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

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: Tweaks to dragging and visibility 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() {
97 ClearSelection();
98 }
99
100 void ChangeInsertion(const gfx::RectF& rect,
101 TouchHandleOrientation orientation,
102 bool visible) {
103 controller_->OnSelectionBoundsChanged(
104 rect, orientation, visible, rect, orientation, visible);
105 }
106
107 void ChangeInsertion(const gfx::RectF& rect, bool visible) {
108 ChangeInsertion(rect, TOUCH_HANDLE_CENTER, visible);
109 }
110
111 void ChangeSelection(const gfx::RectF& anchor_rect,
112 TouchHandleOrientation anchor_orientation,
113 bool anchor_visible,
114 const gfx::RectF& focus_rect,
115 TouchHandleOrientation focus_orientation,
116 bool focus_visible) {
117 controller_->OnSelectionBoundsChanged(anchor_rect,
118 anchor_orientation,
119 anchor_visible,
120 focus_rect,
121 focus_orientation,
122 focus_visible);
123 }
124
125 void ChangeSelection(const gfx::RectF& anchor_rect,
126 bool anchor_visible,
127 const gfx::RectF& focus_rect,
128 bool focus_visible) {
129 ChangeSelection(anchor_rect,
130 TOUCH_HANDLE_LEFT,
131 anchor_visible,
132 focus_rect,
133 TOUCH_HANDLE_RIGHT,
134 focus_visible);
135 }
136
137 void Animate() {
138 base::TimeTicks now = base::TimeTicks::Now();
139 while (needs_animate_) {
140 needs_animate_ = false;
141 controller_->Animate(now);
142 now += base::TimeDelta::FromMilliseconds(16);
143 }
144 }
145
146 bool GetAndResetNeedsAnimate() {
147 bool needs_animate = needs_animate_;
148 Animate();
149 return needs_animate;
150 }
151
152 bool GetAndResetCaretMoved() {
153 bool moved = caret_moved_;
154 caret_moved_ = false;
155 return moved;
156 }
157
158 bool GetAndResetSelectionMoved() {
159 bool moved = selection_moved_;
160 selection_moved_ = false;
161 return moved;
162 }
163
164 const gfx::PointF& GetLastCaretPosition() const { return caret_position_; }
165 const gfx::PointF& GetLastSelectionStart() const { return selection_start_; }
166 const gfx::PointF& GetLastSelectionEnd() const { return selection_end_; }
167 SelectionEventType GetLastEventType() const { return last_event_; }
168 const gfx::PointF& GetLastEventAnchor() const { return last_event_anchor_; }
169
170 TouchSelectionController& controller() { return *controller_; }
171
172 private:
173 gfx::PointF last_event_anchor_;
174 gfx::PointF caret_position_;
175 gfx::PointF selection_start_;
176 gfx::PointF selection_end_;
177 SelectionEventType last_event_;
178 bool caret_moved_;
179 bool selection_moved_;
180 bool needs_animate_;
181 bool animation_enabled_;
182 bool dragging_enabled_;
183 scoped_ptr<TouchSelectionController> controller_;
184 };
185
186 TEST_F(TouchSelectionControllerTest, InsertionBasic) {
187 gfx::RectF insertion_rect(5, 5, 0, 10);
188 bool visible = true;
189
190 // Insertion events are ignored until automatic showing is enabled.
191 ChangeInsertion(insertion_rect, visible);
192 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
193 controller().AllowAutomaticInsertionShowing();
194
195 // Insertion events are ignored until the selection region is marked editable.
196 ChangeInsertion(insertion_rect, visible);
197 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
198 controller().OnSelectionEditable(true);
199
200 ChangeInsertion(insertion_rect, visible);
201 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
202 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
203
204 insertion_rect.Offset(1, 0);
205 ChangeInsertion(insertion_rect, visible);
206 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
207 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
208
209 insertion_rect.Offset(0, 1);
210 ChangeInsertion(insertion_rect, visible);
211 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
212 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
213
214 ClearInsertion();
215 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
216 }
217
218 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
219 gfx::RectF insertion_rect(5, 5, 0, 10);
220 bool visible = true;
221 controller().AllowAutomaticInsertionShowing();
222 controller().OnSelectionEditable(true);
223
224 ChangeInsertion(insertion_rect, visible);
225 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
226 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
227
228 controller().OnSelectionEditable(false);
229 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
230 }
231
232 TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
233 controller().AllowAutomaticSelectionShowing();
234 controller().AllowAutomaticInsertionShowing();
235 controller().OnSelectionEditable(true);
236
237 gfx::RectF anchor_rect(5, 5, 0, 10);
238 gfx::RectF focus_rect(50, 5, 0, 10);
239 bool visible = true;
240
241 ChangeInsertion(anchor_rect, visible);
242 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
243 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
244
245 ChangeSelection(anchor_rect, visible, focus_rect, visible);
246 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
247 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
248
249 ChangeInsertion(focus_rect, visible);
250 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
251 EXPECT_EQ(focus_rect.bottom_left(), GetLastEventAnchor());
252
253 controller().HideAndDisallowAutomaticShowing();
254 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
255
256 controller().AllowAutomaticInsertionShowing();
257 ChangeInsertion(focus_rect, visible);
258 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
259 EXPECT_EQ(focus_rect.bottom_left(), GetLastEventAnchor());
260 }
261
262 TEST_F(TouchSelectionControllerTest, InsertionDragged) {
263 base::TimeTicks event_time = base::TimeTicks::Now();
264 controller().AllowAutomaticInsertionShowing();
265 controller().OnSelectionEditable(true);
266
267 // The touch sequence should not be handled if insertion is not active.
268 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
269 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
270
271 float line_height = 10.f;
272 gfx::RectF anchor_rect(10, 0, 0, line_height);
273 bool visible = true;
274 ChangeInsertion(anchor_rect, visible);
275 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
276 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
277
278 // The touch sequence should be handled only if the drawable reports a hit.
279 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
280 SetDraggingEnabled(true);
281 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
282 EXPECT_FALSE(GetAndResetCaretMoved());
283
284 // The MoveCaret() result should reflect the movement.
285 // The reported position is offset from the center of |anchor_rect|.
286 gfx::PointF anchor_offset = anchor_rect.CenterPoint();
287 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
288 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
289 EXPECT_TRUE(GetAndResetCaretMoved());
290 EXPECT_EQ(anchor_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition());
291
292 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
293 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
294 EXPECT_TRUE(GetAndResetCaretMoved());
295 EXPECT_EQ(anchor_offset + gfx::Vector2dF(5, 5), GetLastCaretPosition());
296
297 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 10);
298 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
299 EXPECT_TRUE(GetAndResetCaretMoved());
300 EXPECT_EQ(anchor_offset + gfx::Vector2dF(10, 10), GetLastCaretPosition());
301
302 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
303 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
304 EXPECT_FALSE(GetAndResetCaretMoved());
305
306 // Once the drag is complete, no more touch events should be consumed until
307 // the next ACTION_DOWN.
308 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
309 }
310
311 TEST_F(TouchSelectionControllerTest, InsertionTapped) {
312 base::TimeTicks event_time = base::TimeTicks::Now();
313 controller().AllowAutomaticInsertionShowing();
314 controller().OnSelectionEditable(true);
315 SetDraggingEnabled(true);
316
317 gfx::RectF anchor_rect(10, 0, 0, 10);
318 bool visible = true;
319 ChangeInsertion(anchor_rect, visible);
320 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
321
322 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
323 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
324 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
325
326 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
327 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
328 EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
329
330 // Reset the insertion.
331 ClearInsertion();
332 controller().AllowAutomaticInsertionShowing();
333 ChangeInsertion(anchor_rect, visible);
334 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
335
336 // No tap should be signalled if the time between DOWN and UP was too long.
337 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
338 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
339 event = MockMotionEvent(MockMotionEvent::ACTION_UP,
340 event_time + base::TimeDelta::FromSeconds(1),
341 0,
342 0);
343 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
344 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
345
346 // Reset the insertion.
347 ClearInsertion();
348 controller().AllowAutomaticInsertionShowing();
349 ChangeInsertion(anchor_rect, visible);
350 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
351
352 // No tap should be signalled if the touch sequence is cancelled.
353 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
354 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
355 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
356 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
357 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
358 }
359
360 TEST_F(TouchSelectionControllerTest, SelectionBasic) {
361 gfx::RectF anchor_rect(5, 5, 0, 10);
362 gfx::RectF focus_rect(50, 5, 0, 10);
363 bool visible = true;
364
365 // Selection events are ignored until automatic showing is enabled.
366 ChangeSelection(anchor_rect, visible, focus_rect, visible);
367 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
368
369 controller().AllowAutomaticSelectionShowing();
370 ChangeSelection(anchor_rect, visible, focus_rect, visible);
371 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
372 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
373
374 anchor_rect.Offset(1, 0);
375 ChangeSelection(anchor_rect, visible, focus_rect, visible);
376 // Selection movement does not currently trigger a separate event.
377 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
378
379 ClearSelection();
380 EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
381 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
382 }
383
384 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
385 base::TimeTicks event_time = base::TimeTicks::Now();
386 controller().AllowAutomaticSelectionShowing();
387
388 // The touch sequence should not be handled if selection is not active.
389 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
390 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
391
392 float line_height = 10.f;
393 gfx::RectF anchor_rect(0, 0, 0, line_height);
394 gfx::RectF focus_rect(50, 0, 0, line_height);
395 bool visible = true;
396 ChangeSelection(anchor_rect, visible, focus_rect, visible);
397 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
398 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
399
400 // The touch sequence should be handled only if the drawable reports a hit.
401 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
402 SetDraggingEnabled(true);
403 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
404 EXPECT_FALSE(GetAndResetSelectionMoved());
405
406 // The SelectBetweenCoordinates() result should reflect the movement. Note
407 // that the start coordinate will always reflect the "fixed" handle's
408 // position, in this case the position from |focus_rect|.
409 // Note that the reported position is offset from the center of the
410 // input rects (i.e., the middle of the corresponding text line).
411 gfx::PointF fixed_offset = focus_rect.CenterPoint();
412 gfx::PointF anchor_offset = anchor_rect.CenterPoint();
413 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
414 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
415 EXPECT_TRUE(GetAndResetSelectionMoved());
416 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
417 EXPECT_EQ(anchor_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
418
419 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
420 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
421 EXPECT_TRUE(GetAndResetSelectionMoved());
422 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
423 EXPECT_EQ(anchor_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd());
424
425 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5);
426 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
427 EXPECT_TRUE(GetAndResetSelectionMoved());
428 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
429 EXPECT_EQ(anchor_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd());
430
431 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
432 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
433 EXPECT_FALSE(GetAndResetSelectionMoved());
434
435 // Once the drag is complete, no more touch events should be consumed until
436 // the next ACTION_DOWN.
437 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
438 }
439
440 TEST_F(TouchSelectionControllerTest, Animation) {
441 controller().AllowAutomaticInsertionShowing();
442 controller().OnSelectionEditable(true);
443
444 gfx::RectF insertion_rect(5, 5, 0, 10);
445
446 bool visible = true;
447 ChangeInsertion(insertion_rect, visible);
448 EXPECT_TRUE(GetAndResetNeedsAnimate());
449
450 visible = false;
451 ChangeInsertion(insertion_rect, visible);
452 EXPECT_TRUE(GetAndResetNeedsAnimate());
453
454 visible = true;
455 ChangeInsertion(insertion_rect, visible);
456 EXPECT_TRUE(GetAndResetNeedsAnimate());
457
458 // If the handles are explicity hidden, no animation should be triggered.
459 controller().HideAndDisallowAutomaticShowing();
460 EXPECT_FALSE(GetAndResetNeedsAnimate());
461
462 // If the client doesn't support animation, no animation should be triggered.
463 SetAnimationEnabled(false);
464 controller().AllowAutomaticInsertionShowing();
465 visible = true;
466 ChangeInsertion(insertion_rect, visible);
467 EXPECT_FALSE(GetAndResetNeedsAnimate());
468 }
469
470 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698