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

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

Powered by Google App Engine
This is Rietveld 408576698