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

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: Clean up paste popup interaction 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 SetOrientation(TouchHandleOrientation orientation) OVERRIDE {}
21 virtual void SetAlpha(float alpha) OVERRIDE {}
22 virtual void SetFocus(const gfx::PointF& position) OVERRIDE {}
23 virtual void SetVisible(bool visible) OVERRIDE {}
24 virtual bool ContainsPoint(const gfx::PointF& point) const OVERRIDE {
25 return *contains_point_;
26 }
27
28 private:
29 bool* contains_point_;
30 };
31
32 } // namespace
33
34 class TouchSelectionControllerTest : public testing::Test,
35 public TouchSelectionControllerClient {
36 public:
37 TouchSelectionControllerTest()
38 : last_event_(SELECTION_CLEARED),
39 caret_moved_(false),
40 selection_moved_(false),
41 needs_animate_(false),
42 dragging_enabled_(false) {}
43
44 virtual ~TouchSelectionControllerTest() {}
45
46 // testing::Test implementation.
47 virtual void SetUp() OVERRIDE {
48 controller_.reset(new TouchSelectionController(this));
49 }
50
51 virtual void TearDown() OVERRIDE { controller_.reset(); }
52
53 // TouchSelectionControllerClient implementation.
54 virtual void SetNeedsAnimate() OVERRIDE { needs_animate_ = true; }
55
56 virtual void MoveCaret(const gfx::PointF& position) OVERRIDE {
57 caret_moved_ = true;
58 caret_position_ = position;
59 }
60
61 virtual void SelectBetweenCoordinates(const gfx::PointF& start,
62 const gfx::PointF& end) OVERRIDE {
63 selection_moved_ = true;
64 selection_start_ = start;
65 selection_end_ = end;
66 }
67
68 virtual void OnSelectionEvent(SelectionEventType event,
69 const gfx::PointF& anchor_position) OVERRIDE {
70 last_event_ = event;
71 last_event_anchor_ = anchor_position;
72 }
73
74 virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() OVERRIDE {
75 return scoped_ptr<TouchHandleDrawable>(
76 new MockTouchHandleDrawable(&dragging_enabled_));
77 }
78
79 void SetDraggingEnabled(bool enabled) { dragging_enabled_ = enabled; }
80
81 void ClearSelection() {
82 controller_->OnSelectionBoundsChanged(gfx::RectF(),
83 TOUCH_HANDLE_ORIENTATION_UNDEFINED,
84 false,
85 gfx::RectF(),
86 TOUCH_HANDLE_ORIENTATION_UNDEFINED,
87 false);
88 }
89
90 void ClearInsertion() {
91 ClearSelection();
92 }
93
94 void ChangeInsertion(const gfx::RectF& rect,
95 TouchHandleOrientation orientation,
96 bool visible) {
97 controller_->OnSelectionBoundsChanged(
98 rect, orientation, visible, rect, orientation, visible);
99 }
100
101 void ChangeInsertion(const gfx::RectF& rect, bool visible) {
102 ChangeInsertion(rect, TOUCH_HANDLE_CENTER, visible);
103 }
104
105 void ChangeSelection(const gfx::RectF& anchor_rect,
106 TouchHandleOrientation anchor_orientation,
107 bool anchor_visible,
108 const gfx::RectF& focus_rect,
109 TouchHandleOrientation focus_orientation,
110 bool focus_visible) {
111 controller_->OnSelectionBoundsChanged(anchor_rect,
112 anchor_orientation,
113 anchor_visible,
114 focus_rect,
115 focus_orientation,
116 focus_visible);
117 }
118
119 void ChangeSelection(const gfx::RectF& anchor_rect,
120 bool anchor_visible,
121 const gfx::RectF& focus_rect,
122 bool focus_visible) {
123 ChangeSelection(anchor_rect,
124 TOUCH_HANDLE_LEFT,
125 anchor_visible,
126 focus_rect,
127 TOUCH_HANDLE_RIGHT,
128 focus_visible);
129 }
130
131 void Animate() {
132 base::TimeTicks now = base::TimeTicks::Now();
133 while (needs_animate_) {
134 needs_animate_ = false;
135 controller_->Animate(now);
136 now += base::TimeDelta::FromMilliseconds(16);
137 }
138 }
139
140 bool GetAndResetNeedsAnimate() {
141 bool needs_animate = needs_animate_;
142 Animate();
143 return needs_animate;
144 }
145
146 bool GetAndResetCaretMoved() {
147 bool moved = caret_moved_;
148 caret_moved_ = false;
149 return moved;
150 }
151
152 bool GetAndResetSelectionMoved() {
153 bool moved = selection_moved_;
154 selection_moved_ = false;
155 return moved;
156 }
157
158 const gfx::PointF& GetLastCaretPosition() const { return caret_position_; }
159 const gfx::PointF& GetLastSelectionStart() const { return selection_start_; }
160 const gfx::PointF& GetLastSelectionEnd() const { return selection_end_; }
161 SelectionEventType GetLastEventType() const { return last_event_; }
162 const gfx::PointF& GetLastEventAnchor() const { return last_event_anchor_; }
163
164 TouchSelectionController& controller() { return *controller_; }
165
166 private:
167 gfx::PointF last_event_anchor_;
168 gfx::PointF caret_position_;
169 gfx::PointF selection_start_;
170 gfx::PointF selection_end_;
171 SelectionEventType last_event_;
172 bool caret_moved_;
173 bool selection_moved_;
174 bool needs_animate_;
175 bool dragging_enabled_;
176 scoped_ptr<TouchSelectionController> controller_;
177 };
178
179 TEST_F(TouchSelectionControllerTest, InsertionBasic) {
180 gfx::RectF insertion_rect(5, 5, 0, 10);
181 bool visible = true;
182
183 // Insertion events are ignored until automatic showing is enabled.
184 ChangeInsertion(insertion_rect, visible);
185 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
186 controller().AllowAutomaticInsertionShowing();
187
188 // Insertion events are ignored until the selection region is marked editable.
189 ChangeInsertion(insertion_rect, visible);
190 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
191 controller().OnSelectionEditable(true);
192
193 ChangeInsertion(insertion_rect, visible);
194 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
195 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
196
197 insertion_rect.Offset(1, 0);
198 ChangeInsertion(insertion_rect, visible);
199 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
200 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
201
202 insertion_rect.Offset(0, 1);
203 ChangeInsertion(insertion_rect, visible);
204 EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
205 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
206
207 ClearInsertion();
208 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
209 }
210
211 TEST_F(TouchSelectionControllerTest, InsertionClearedWhenLongerEditable) {
cjhopman 2014/07/09 22:29:12 s/WhenLonger/WhenNoLonger
jdduke (slow) 2014/07/10 02:08:39 Done.
212 gfx::RectF insertion_rect(5, 5, 0, 10);
213 bool visible = true;
214 controller().AllowAutomaticInsertionShowing();
215 controller().OnSelectionEditable(true);
216
217 ChangeInsertion(insertion_rect, visible);
218 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
219 EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
220
221 controller().OnSelectionEditable(false);
222 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
223 }
224
225 TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
226 controller().AllowAutomaticSelectionShowing();
227 controller().AllowAutomaticInsertionShowing();
228 controller().OnSelectionEditable(true);
229
230 gfx::RectF anchor_rect(5, 5, 0, 10);
231 gfx::RectF focus_rect(50, 5, 0, 10);
232 bool visible = true;
233
234 ChangeInsertion(anchor_rect, visible);
235 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
236 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
237
238 ChangeSelection(anchor_rect, visible, focus_rect, visible);
239 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
240 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
241
242 ChangeInsertion(focus_rect, visible);
243 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
244 EXPECT_EQ(focus_rect.bottom_left(), GetLastEventAnchor());
245
246 controller().HideAndDisallowAutomaticShowing();
247 EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
248
249 controller().AllowAutomaticInsertionShowing();
250 ChangeInsertion(focus_rect, visible);
251 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
252 EXPECT_EQ(focus_rect.bottom_left(), GetLastEventAnchor());
253 }
254
255 TEST_F(TouchSelectionControllerTest, InsertionDragged) {
256 base::TimeTicks event_time = base::TimeTicks::Now();
257 controller().AllowAutomaticInsertionShowing();
258 controller().OnSelectionEditable(true);
259
260 // The touch sequence should not be handled if insertion is not active.
261 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
262 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
263
264 float line_height = 10.f;
265 gfx::RectF anchor_rect(10, 0, 0, line_height);
266 bool visible = true;
267 ChangeInsertion(anchor_rect, visible);
268 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
269 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
270
271 // The touch sequence should be handled only if the drawable reports a hit.
272 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
273 SetDraggingEnabled(true);
274 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
275 EXPECT_FALSE(GetAndResetCaretMoved());
276
277 // The MoveCaret() result should reflect the movement.
278 // The reported position is offset from the center of |anchor_rect|.
279 gfx::PointF anchor_offset = anchor_rect.CenterPoint();
280 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
281 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
282 EXPECT_TRUE(GetAndResetCaretMoved());
283 EXPECT_EQ(anchor_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition());
284
285 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
286 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
287 EXPECT_TRUE(GetAndResetCaretMoved());
288 EXPECT_EQ(anchor_offset + gfx::Vector2dF(5, 5), GetLastCaretPosition());
289
290 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 10);
291 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
292 EXPECT_TRUE(GetAndResetCaretMoved());
293 EXPECT_EQ(anchor_offset + gfx::Vector2dF(10, 10), GetLastCaretPosition());
294
295 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
296 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
297 EXPECT_FALSE(GetAndResetCaretMoved());
298
299 // Once the drag is complete, no more touch events should be consumed until
300 // the next ACTION_DOWN.
301 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
302 }
303
304 TEST_F(TouchSelectionControllerTest, InsertionTapped) {
305 base::TimeTicks event_time = base::TimeTicks::Now();
306 controller().AllowAutomaticInsertionShowing();
307 controller().OnSelectionEditable(true);
308 SetDraggingEnabled(true);
309
310 gfx::RectF anchor_rect(10, 0, 0, 10);
311 bool visible = true;
312 ChangeInsertion(anchor_rect, visible);
313 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
314
315 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
316 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
317 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
318
319 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
320 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
321 EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
322
323 // Reset the insertion.
324 ClearInsertion();
325 controller().AllowAutomaticInsertionShowing();
326 ChangeInsertion(anchor_rect, visible);
327 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
328
329 // No tap should be signalled if the time between DOWN and UP was too long.
330 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
331 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
332 event = MockMotionEvent(MockMotionEvent::ACTION_UP,
333 event_time + base::TimeDelta::FromSeconds(1),
334 0,
335 0);
336 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
337 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
338
339 // Reset the insertion.
340 ClearInsertion();
341 controller().AllowAutomaticInsertionShowing();
342 ChangeInsertion(anchor_rect, visible);
343 ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
344
345 // No tap should be signalled if the touch sequence is cancelled.
346 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
347 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
348 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
349 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
350 EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
351 }
352
353 TEST_F(TouchSelectionControllerTest, SelectionBasic) {
354 gfx::RectF anchor_rect(5, 5, 0, 10);
355 gfx::RectF focus_rect(50, 5, 0, 10);
356 bool visible = true;
357
358 // Selection events are ignored until automatic showing is enabled.
359 ChangeSelection(anchor_rect, visible, focus_rect, visible);
360 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
361
362 controller().AllowAutomaticSelectionShowing();
363 ChangeSelection(anchor_rect, visible, focus_rect, visible);
364 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
365 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
366
367 anchor_rect.Offset(1, 0);
368 ChangeSelection(anchor_rect, visible, focus_rect, visible);
369 // Selection movement does not currently trigger a separate event.
370 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
371
372 ClearSelection();
373 EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
374 EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
375 }
376
377 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
378 base::TimeTicks event_time = base::TimeTicks::Now();
379 controller().AllowAutomaticSelectionShowing();
380
381 // The touch sequence should not be handled if selection is not active.
382 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
383 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
384
385 float line_height = 10.f;
386 gfx::RectF anchor_rect(0, 0, 0, line_height);
387 gfx::RectF focus_rect(50, 0, 0, line_height);
388 bool visible = true;
389 ChangeSelection(anchor_rect, visible, focus_rect, visible);
390 EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
391 EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
392
393 // The touch sequence should be handled only if the drawable reports a hit.
394 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
395 SetDraggingEnabled(true);
396 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
397 EXPECT_FALSE(GetAndResetSelectionMoved());
398
399 // The SelectBetweenCoordinates() result should reflect the movement. Note
400 // that the start coordinate will always reflect the "fixed" handle's
401 // position, in this case the position from |focus_rect|.
402 // Note that the reported position is offset from the center of the
403 // input rects (i.e., the middle of the corresponding text line).
404 gfx::PointF fixed_offset = focus_rect.CenterPoint();
405 gfx::PointF anchor_offset = anchor_rect.CenterPoint();
406 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
407 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
408 EXPECT_TRUE(GetAndResetSelectionMoved());
409 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
410 EXPECT_EQ(anchor_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
411
412 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
413 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
414 EXPECT_TRUE(GetAndResetSelectionMoved());
415 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
416 EXPECT_EQ(anchor_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd());
417
418 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5);
419 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
420 EXPECT_TRUE(GetAndResetSelectionMoved());
421 EXPECT_EQ(fixed_offset, GetLastSelectionStart());
422 EXPECT_EQ(anchor_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd());
423
424 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
425 EXPECT_TRUE(controller().WillHandleTouchEvent(event));
426 EXPECT_FALSE(GetAndResetSelectionMoved());
427
428 // Once the drag is complete, no more touch events should be consumed until
429 // the next ACTION_DOWN.
430 EXPECT_FALSE(controller().WillHandleTouchEvent(event));
431 }
432
433 TEST_F(TouchSelectionControllerTest, Animation) {
434 controller().AllowAutomaticInsertionShowing();
435 controller().OnSelectionEditable(true);
436
437 gfx::RectF insertion_rect(5, 5, 0, 10);
438
439 // Animation should only happen if visibility changes *after* the insertion or
440 // selection is already active.
441 bool visible = true;
442 ChangeInsertion(insertion_rect, visible);
443 EXPECT_FALSE(GetAndResetNeedsAnimate());
444
445 visible = false;
446 ChangeInsertion(insertion_rect, visible);
447 EXPECT_TRUE(GetAndResetNeedsAnimate());
448
449 visible = true;
450 ChangeInsertion(insertion_rect, visible);
451 EXPECT_TRUE(GetAndResetNeedsAnimate());
452
453 // If the handles are explicity hidden, no animation should be triggered.
454 controller().HideAndDisallowAutomaticShowing();
455 EXPECT_FALSE(GetAndResetNeedsAnimate());
456 }
457
458 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698