1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "gtest/gtest.h"
8 #include "gmock/gmock.h"
9
10 #include <string>
11
12 #include "AccessibleCaret.h"
13 #include "AccessibleCaretManager.h"
14 #include "mozilla/Preferences.h"
15
16 using ::testing::_;
17 using ::testing::DefaultValue;
18 using ::testing::Eq;
19 using ::testing::InSequence;
20 using ::testing::MockFunction;
21 using ::testing::Return;
22
23 // -----------------------------------------------------------------------------
24 // This file tests CaretStateChanged events and the appearance of the two
25 // AccessibleCarets manipulated by AccessibleCaretManager.
26
27 namespace mozilla {
28 using dom::CaretChangedReason;
29
30 class MOZ_RAII AutoRestoreBoolPref final {
31 public:
AutoRestoreBoolPref(const char * aPref,bool aValue)32 AutoRestoreBoolPref(const char* aPref, bool aValue) : mPref(aPref) {
33 Preferences::GetBool(mPref, &mOldValue);
34 Preferences::SetBool(mPref, aValue);
35 }
36
~AutoRestoreBoolPref()37 ~AutoRestoreBoolPref() { Preferences::SetBool(mPref, mOldValue); }
38
39 private:
40 const char* mPref = nullptr;
41 bool mOldValue = false;
42 };
43
44 class AccessibleCaretManagerTester : public ::testing::Test {
45 public:
46 class MockAccessibleCaret : public AccessibleCaret {
47 public:
MockAccessibleCaret()48 MockAccessibleCaret() : AccessibleCaret(nullptr) {}
49
SetAppearance(Appearance aAppearance)50 void SetAppearance(Appearance aAppearance) override {
51 // A simplified version without touching CaretElement().
52 mAppearance = aAppearance;
53 }
54
55 MOCK_METHOD2(SetPosition,
56 PositionChangedResult(nsIFrame* aFrame, int32_t aOffset));
57
58 }; // class MockAccessibleCaret
59
60 class MockAccessibleCaretManager : public AccessibleCaretManager {
61 public:
62 using CaretMode = AccessibleCaretManager::CaretMode;
63 using AccessibleCaretManager::HideCarets;
64 using AccessibleCaretManager::UpdateCarets;
65
MockAccessibleCaretManager()66 MockAccessibleCaretManager() : AccessibleCaretManager(nullptr) {
67 mFirstCaret = MakeUnique<MockAccessibleCaret>();
68 mSecondCaret = MakeUnique<MockAccessibleCaret>();
69 }
70
FirstCaret()71 MockAccessibleCaret& FirstCaret() {
72 return static_cast<MockAccessibleCaret&>(*mFirstCaret);
73 }
74
SecondCaret()75 MockAccessibleCaret& SecondCaret() {
76 return static_cast<MockAccessibleCaret&>(*mSecondCaret);
77 }
78
CompareTreePosition(nsIFrame * aStartFrame,nsIFrame * aEndFrame) const79 bool CompareTreePosition(nsIFrame* aStartFrame,
80 nsIFrame* aEndFrame) const override {
81 return true;
82 }
83
IsCaretDisplayableInCursorMode(nsIFrame ** aOutFrame=nullptr,int32_t * aOutOffset=nullptr) const84 bool IsCaretDisplayableInCursorMode(
85 nsIFrame** aOutFrame = nullptr,
86 int32_t* aOutOffset = nullptr) const override {
87 return true;
88 }
89
UpdateCaretsForOverlappingTilt()90 bool UpdateCaretsForOverlappingTilt() override { return true; }
91
UpdateCaretsForAlwaysTilt(nsIFrame * aStartFrame,nsIFrame * aEndFrame)92 void UpdateCaretsForAlwaysTilt(nsIFrame* aStartFrame,
93 nsIFrame* aEndFrame) override {
94 if (mFirstCaret->IsVisuallyVisible()) {
95 mFirstCaret->SetAppearance(Appearance::Left);
96 }
97 if (mSecondCaret->IsVisuallyVisible()) {
98 mSecondCaret->SetAppearance(Appearance::Right);
99 }
100 }
101
IsTerminated() const102 bool IsTerminated() const override { return false; }
103
104 MOCK_CONST_METHOD0(GetCaretMode, CaretMode());
105 MOCK_METHOD1(DispatchCaretStateChangedEvent,
106 void(CaretChangedReason aReason));
107 MOCK_CONST_METHOD1(HasNonEmptyTextContent, bool(nsINode* aNode));
108
109 }; // class MockAccessibleCaretManager
110
111 using Appearance = AccessibleCaret::Appearance;
112 using PositionChangedResult = AccessibleCaret::PositionChangedResult;
113 using CaretMode = MockAccessibleCaretManager::CaretMode;
114
AccessibleCaretManagerTester()115 AccessibleCaretManagerTester() {
116 DefaultValue<CaretMode>::Set(CaretMode::None);
117 DefaultValue<PositionChangedResult>::Set(PositionChangedResult::NotChanged);
118
119 EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
120 .WillRepeatedly(Return(PositionChangedResult::Position));
121
122 EXPECT_CALL(mManager.SecondCaret(), SetPosition(_, _))
123 .WillRepeatedly(Return(PositionChangedResult::Position));
124 }
125
FirstCaretAppearance()126 AccessibleCaret::Appearance FirstCaretAppearance() {
127 return mManager.FirstCaret().GetAppearance();
128 }
129
SecondCaretAppearance()130 AccessibleCaret::Appearance SecondCaretAppearance() {
131 return mManager.SecondCaret().GetAppearance();
132 }
133
134 // Member variables
135 MockAccessibleCaretManager mManager;
136
137 }; // class AccessibleCaretManagerTester
138
TEST_F(AccessibleCaretManagerTester,TestUpdatesInSelectionMode)139 TEST_F(AccessibleCaretManagerTester, TestUpdatesInSelectionMode)
140 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
141 // Set default preference.
142 AutoRestoreBoolPref savedPref("layout.accessiblecaret.always_tilt", false);
143
144 EXPECT_CALL(mManager, GetCaretMode())
145 .WillRepeatedly(Return(CaretMode::Selection));
146
147 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
148 CaretChangedReason::Updateposition))
149 .Times(3);
150
151 mManager.UpdateCarets();
152 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
153 EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
154
155 mManager.OnReflow();
156 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
157 EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
158
159 mManager.OnScrollPositionChanged();
160 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
161 EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
162 }
163
TEST_F(AccessibleCaretManagerTester,TestSingleTapOnNonEmptyInput)164 TEST_F(AccessibleCaretManagerTester, TestSingleTapOnNonEmptyInput)
165 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
166 EXPECT_CALL(mManager, GetCaretMode())
167 .WillRepeatedly(Return(CaretMode::Cursor));
168
169 EXPECT_CALL(mManager, HasNonEmptyTextContent(_)).WillRepeatedly(Return(true));
170
171 MockFunction<void(std::string aCheckPointName)> check;
172 {
173 InSequence dummy;
174
175 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
176 CaretChangedReason::Updateposition))
177 .Times(1);
178 EXPECT_CALL(check, Call("update"));
179
180 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
181 CaretChangedReason::Visibilitychange))
182 .Times(1);
183 EXPECT_CALL(check, Call("mouse down"));
184
185 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
186 EXPECT_CALL(check, Call("reflow"));
187
188 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
189 EXPECT_CALL(check, Call("blur"));
190
191 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
192 CaretChangedReason::Updateposition))
193 .Times(1);
194 EXPECT_CALL(check, Call("mouse up"));
195
196 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
197 CaretChangedReason::Updateposition))
198 .Times(1);
199 EXPECT_CALL(check, Call("reflow2"));
200
201 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
202 CaretChangedReason::Updateposition))
203 .Times(1);
204 }
205
206 // Simulate a single tap on a non-empty input.
207 mManager.UpdateCarets();
208 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
209 check.Call("update");
210
211 mManager.OnSelectionChanged(nullptr, nullptr,
212 nsISelectionListener::DRAG_REASON |
213 nsISelectionListener::MOUSEDOWN_REASON);
214 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
215 check.Call("mouse down");
216
217 mManager.OnReflow();
218 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
219 check.Call("reflow");
220
221 mManager.OnBlur();
222 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
223 check.Call("blur");
224
225 mManager.OnSelectionChanged(nullptr, nullptr,
226 nsISelectionListener::MOUSEUP_REASON);
227 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
228 check.Call("mouse up");
229
230 mManager.OnReflow();
231 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
232 check.Call("reflow2");
233
234 mManager.OnScrollPositionChanged();
235 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
236 }
237
TEST_F(AccessibleCaretManagerTester,TestSingleTapOnEmptyInput)238 TEST_F(AccessibleCaretManagerTester, TestSingleTapOnEmptyInput)
239 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
240 // Set default preference.
241 AutoRestoreBoolPref savedPref(
242 "layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content",
243 false);
244
245 EXPECT_CALL(mManager, GetCaretMode())
246 .WillRepeatedly(Return(CaretMode::Cursor));
247
248 EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
249 .WillRepeatedly(Return(false));
250
251 MockFunction<void(std::string aCheckPointName)> check;
252 {
253 InSequence dummy;
254
255 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
256 CaretChangedReason::Updateposition))
257 .Times(1);
258 EXPECT_CALL(check, Call("update"));
259
260 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
261 CaretChangedReason::Visibilitychange))
262 .Times(1);
263 EXPECT_CALL(check, Call("mouse down"));
264
265 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
266 EXPECT_CALL(check, Call("reflow"));
267
268 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
269 EXPECT_CALL(check, Call("blur"));
270
271 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
272 CaretChangedReason::Updateposition))
273 .Times(1);
274 EXPECT_CALL(check, Call("mouse up"));
275
276 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
277 CaretChangedReason::Updateposition))
278 .Times(1);
279 EXPECT_CALL(check, Call("reflow2"));
280
281 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
282 CaretChangedReason::Updateposition))
283 .Times(1);
284 }
285
286 // Simulate a single tap on an empty input.
287 mManager.UpdateCarets();
288 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
289 check.Call("update");
290
291 mManager.OnSelectionChanged(nullptr, nullptr,
292 nsISelectionListener::DRAG_REASON |
293 nsISelectionListener::MOUSEDOWN_REASON);
294 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
295 check.Call("mouse down");
296
297 mManager.OnReflow();
298 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
299 check.Call("reflow");
300
301 mManager.OnBlur();
302 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
303 check.Call("blur");
304
305 mManager.OnSelectionChanged(nullptr, nullptr,
306 nsISelectionListener::MOUSEUP_REASON);
307 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
308 check.Call("mouse up");
309
310 mManager.OnReflow();
311 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
312 check.Call("reflow2");
313
314 mManager.OnScrollPositionChanged();
315 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
316 }
317
TEST_F(AccessibleCaretManagerTester,TestTypingAtEndOfInput)318 TEST_F(AccessibleCaretManagerTester, TestTypingAtEndOfInput)
319 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
320 EXPECT_CALL(mManager, GetCaretMode())
321 .WillRepeatedly(Return(CaretMode::Cursor));
322
323 EXPECT_CALL(mManager, HasNonEmptyTextContent(_)).WillRepeatedly(Return(true));
324
325 MockFunction<void(std::string aCheckPointName)> check;
326 {
327 InSequence dummy;
328
329 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
330 CaretChangedReason::Updateposition))
331 .Times(1);
332 EXPECT_CALL(check, Call("update"));
333
334 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
335 CaretChangedReason::Visibilitychange))
336 .Times(1);
337 EXPECT_CALL(check, Call("keyboard"));
338
339 // No CaretStateChanged events should be dispatched since the caret has
340 // being hidden in cursor mode.
341 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
342 }
343
344 // Simulate typing the end of the input.
345 mManager.UpdateCarets();
346 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
347 check.Call("update");
348
349 mManager.OnKeyboardEvent();
350 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
351 check.Call("keyboard");
352
353 mManager.OnSelectionChanged(nullptr, nullptr,
354 nsISelectionListener::NO_REASON);
355 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
356
357 mManager.OnScrollPositionChanged();
358 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
359 }
360
TEST_F(AccessibleCaretManagerTester,TestScrollInSelectionMode)361 TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionMode)
362 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
363 // Set default preference.
364 AutoRestoreBoolPref savedPref("layout.accessiblecaret.always_tilt", false);
365
366 EXPECT_CALL(mManager, GetCaretMode())
367 .WillRepeatedly(Return(CaretMode::Selection));
368
369 MockFunction<void(std::string aCheckPointName)> check;
370 {
371 InSequence dummy;
372
373 // Initially, first caret is out of scrollport, and second caret is visible.
374 EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
375 .WillOnce(Return(PositionChangedResult::Invisible));
376
377 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
378 CaretChangedReason::Updateposition));
379 EXPECT_CALL(check, Call("updatecarets"));
380
381 EXPECT_CALL(mManager,
382 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
383 EXPECT_CALL(check, Call("scrollstart1"));
384
385 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
386 CaretChangedReason::Updateposition));
387 EXPECT_CALL(check, Call("reflow1"));
388
389 // After scroll ended, first caret is visible and second caret is out of
390 // scroll port.
391 EXPECT_CALL(mManager.SecondCaret(), SetPosition(_, _))
392 .WillOnce(Return(PositionChangedResult::Invisible));
393
394 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
395 CaretChangedReason::Updateposition));
396 EXPECT_CALL(check, Call("scrollend1"));
397
398 EXPECT_CALL(mManager,
399 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
400 EXPECT_CALL(check, Call("scrollstart2"));
401
402 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
403 CaretChangedReason::Updateposition));
404 EXPECT_CALL(check, Call("reflow2"));
405
406 // After the scroll ended, both carets are visible.
407 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
408 CaretChangedReason::Updateposition));
409 EXPECT_CALL(check, Call("scrollend2"));
410 }
411
412 mManager.UpdateCarets();
413 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
414 EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
415 check.Call("updatecarets");
416
417 mManager.OnScrollStart();
418 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
419 EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
420 check.Call("scrollstart1");
421
422 mManager.OnReflow();
423 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
424 EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
425 check.Call("reflow1");
426
427 mManager.OnScrollEnd();
428 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
429 EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
430 check.Call("scrollend1");
431
432 mManager.OnScrollStart();
433 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
434 EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
435 check.Call("scrollstart2");
436
437 mManager.OnReflow();
438 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
439 EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
440 check.Call("reflow2");
441
442 mManager.OnScrollEnd();
443 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
444 EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
445 check.Call("scrollend2");
446 }
447
TEST_F(AccessibleCaretManagerTester,TestScrollInSelectionModeWithAlwaysTiltPref)448 TEST_F(AccessibleCaretManagerTester,
449 TestScrollInSelectionModeWithAlwaysTiltPref)
450 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
451 // Simulate Firefox Android preference.
452 AutoRestoreBoolPref savedPref("layout.accessiblecaret.always_tilt", true);
453
454 EXPECT_CALL(mManager, GetCaretMode())
455 .WillRepeatedly(Return(CaretMode::Selection));
456
457 MockFunction<void(std::string aCheckPointName)> check;
458 {
459 InSequence dummy;
460
461 // Initially, first caret is out of scrollport, and second caret is visible.
462 EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
463 .WillOnce(Return(PositionChangedResult::Invisible));
464
465 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
466 CaretChangedReason::Updateposition));
467 EXPECT_CALL(check, Call("updatecarets"));
468
469 EXPECT_CALL(mManager,
470 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
471 EXPECT_CALL(check, Call("scrollstart1"));
472
473 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
474 EXPECT_CALL(check, Call("scrollPositionChanged1"));
475
476 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
477 CaretChangedReason::Updateposition));
478 EXPECT_CALL(check, Call("reflow1"));
479
480 // After scroll ended, first caret is visible and second caret is out of
481 // scroll port.
482 EXPECT_CALL(mManager.SecondCaret(), SetPosition(_, _))
483 .WillOnce(Return(PositionChangedResult::Invisible));
484
485 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
486 CaretChangedReason::Updateposition));
487 EXPECT_CALL(check, Call("scrollend1"));
488
489 EXPECT_CALL(mManager,
490 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
491 EXPECT_CALL(check, Call("scrollstart2"));
492
493 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
494 EXPECT_CALL(check, Call("scrollPositionChanged2"));
495
496 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
497 CaretChangedReason::Updateposition));
498 EXPECT_CALL(check, Call("reflow2"));
499
500 // After the scroll ended, both carets are visible.
501 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
502 CaretChangedReason::Updateposition));
503 EXPECT_CALL(check, Call("scrollend2"));
504 }
505
506 mManager.UpdateCarets();
507 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
508 EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
509 check.Call("updatecarets");
510
511 mManager.OnScrollStart();
512 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
513 EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
514 check.Call("scrollstart1");
515
516 mManager.OnScrollPositionChanged();
517 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
518 EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
519 check.Call("scrollPositionChanged1");
520
521 mManager.OnReflow();
522 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
523 EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
524 check.Call("reflow1");
525
526 mManager.OnScrollEnd();
527 EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
528 EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
529 check.Call("scrollend1");
530
531 mManager.OnScrollStart();
532 EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
533 EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
534 check.Call("scrollstart2");
535
536 mManager.OnScrollPositionChanged();
537 EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
538 EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
539 check.Call("scrollPositionChanged2");
540
541 mManager.OnReflow();
542 EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
543 EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
544 check.Call("reflow2");
545
546 mManager.OnScrollEnd();
547 EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
548 EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
549 check.Call("scrollend2");
550 }
551
TEST_F(AccessibleCaretManagerTester,TestScrollInCursorModeWhenLogicallyVisible)552 TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenLogicallyVisible)
553 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
554 EXPECT_CALL(mManager, GetCaretMode())
555 .WillRepeatedly(Return(CaretMode::Cursor));
556
557 EXPECT_CALL(mManager, HasNonEmptyTextContent(_)).WillRepeatedly(Return(true));
558
559 MockFunction<void(std::string aCheckPointName)> check;
560 {
561 InSequence dummy;
562
563 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
564 CaretChangedReason::Updateposition))
565 .Times(1);
566 EXPECT_CALL(check, Call("updatecarets"));
567
568 EXPECT_CALL(mManager,
569 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll))
570 .Times(1);
571 EXPECT_CALL(check, Call("scrollstart1"));
572
573 // After scroll ended, the caret is out of scroll port.
574 EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
575 .WillRepeatedly(Return(PositionChangedResult::Invisible));
576 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
577 CaretChangedReason::Updateposition))
578 .Times(1);
579 EXPECT_CALL(check, Call("scrollend1"));
580
581 EXPECT_CALL(mManager,
582 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll))
583 .Times(1);
584 EXPECT_CALL(check, Call("scrollstart2"));
585
586 // After scroll ended, the caret is visible again.
587 EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
588 .WillRepeatedly(Return(PositionChangedResult::Position));
589 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
590 CaretChangedReason::Updateposition))
591 .Times(1);
592 EXPECT_CALL(check, Call("scrollend2"));
593 }
594
595 mManager.UpdateCarets();
596 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
597 check.Call("updatecarets");
598
599 mManager.OnScrollStart();
600 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
601 check.Call("scrollstart1");
602
603 mManager.OnScrollEnd();
604 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
605 check.Call("scrollend1");
606
607 mManager.OnScrollStart();
608 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
609 check.Call("scrollstart2");
610
611 mManager.OnScrollEnd();
612 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
613 check.Call("scrollend2");
614 }
615
TEST_F(AccessibleCaretManagerTester,TestScrollInCursorModeWhenHidden)616 TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenHidden)
617 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
618 EXPECT_CALL(mManager, GetCaretMode())
619 .WillRepeatedly(Return(CaretMode::Cursor));
620
621 EXPECT_CALL(mManager, HasNonEmptyTextContent(_)).WillRepeatedly(Return(true));
622
623 MockFunction<void(std::string aCheckPointName)> check;
624 {
625 InSequence dummy;
626
627 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
628 CaretChangedReason::Updateposition))
629 .Times(1);
630 EXPECT_CALL(check, Call("updatecarets"));
631
632 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
633 CaretChangedReason::Visibilitychange))
634 .Times(1);
635 EXPECT_CALL(check, Call("hidecarets"));
636
637 // After scroll ended, the caret is out of scroll port.
638 EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
639 .WillRepeatedly(Return(PositionChangedResult::Invisible));
640 EXPECT_CALL(check, Call("scrollend1"));
641
642 // After scroll ended, the caret is visible again.
643 EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
644 .WillRepeatedly(Return(PositionChangedResult::Position));
645 EXPECT_CALL(check, Call("scrollend2"));
646 }
647
648 mManager.UpdateCarets();
649 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
650 check.Call("updatecarets");
651
652 mManager.HideCarets();
653 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
654 check.Call("hidecarets");
655
656 mManager.OnScrollStart();
657 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
658
659 mManager.OnScrollEnd();
660 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
661 check.Call("scrollend1");
662
663 mManager.OnScrollStart();
664 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
665
666 mManager.OnScrollEnd();
667 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
668 check.Call("scrollend2");
669 }
670
TEST_F(AccessibleCaretManagerTester,TestScrollInCursorModeOnEmptyContent)671 TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeOnEmptyContent)
672 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
673 // Set default preference.
674 AutoRestoreBoolPref savedPref(
675 "layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content",
676 false);
677
678 EXPECT_CALL(mManager, GetCaretMode())
679 .WillRepeatedly(Return(CaretMode::Cursor));
680
681 EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
682 .WillRepeatedly(Return(false));
683
684 MockFunction<void(std::string aCheckPointName)> check;
685 {
686 InSequence dummy;
687
688 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
689 CaretChangedReason::Updateposition));
690 EXPECT_CALL(check, Call("updatecarets"));
691
692 EXPECT_CALL(mManager,
693 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
694 EXPECT_CALL(check, Call("scrollstart1"));
695
696 EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
697 .WillOnce(Return(PositionChangedResult::Invisible));
698 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
699 CaretChangedReason::Updateposition));
700 EXPECT_CALL(check, Call("scrollend1"));
701
702 EXPECT_CALL(mManager,
703 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
704 EXPECT_CALL(check, Call("scrollstart2"));
705
706 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
707 CaretChangedReason::Updateposition));
708 EXPECT_CALL(check, Call("scrollend2"));
709
710 EXPECT_CALL(mManager,
711 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
712 EXPECT_CALL(check, Call("scrollstart3"));
713
714 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
715 CaretChangedReason::Updateposition));
716 EXPECT_CALL(check, Call("scrollend3"));
717 }
718
719 // Simulate a single tap on an empty content.
720 mManager.UpdateCarets();
721 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
722 check.Call("updatecarets");
723
724 // Scroll the caret to be out of the viewport.
725 mManager.OnScrollStart();
726 check.Call("scrollstart1");
727 mManager.OnScrollEnd();
728 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
729 check.Call("scrollend1");
730
731 // Scroll the caret into the viewport.
732 mManager.OnScrollStart();
733 check.Call("scrollstart2");
734 mManager.OnScrollEnd();
735 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
736 check.Call("scrollend2");
737
738 // Scroll the caret within the viewport.
739 mManager.OnScrollStart();
740 check.Call("scrollstart3");
741 mManager.OnScrollEnd();
742 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
743 check.Call("scrollend3");
744 }
745
TEST_F(AccessibleCaretManagerTester,TestScrollInCursorModeWithCaretShownWhenLongTappingOnEmptyContentPref)746 TEST_F(AccessibleCaretManagerTester,
747 TestScrollInCursorModeWithCaretShownWhenLongTappingOnEmptyContentPref)
748 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
749 // Simulate Firefox Android preference.
750 AutoRestoreBoolPref savedPref(
751 "layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content",
752 true);
753
754 EXPECT_CALL(mManager, GetCaretMode())
755 .WillRepeatedly(Return(CaretMode::Cursor));
756
757 EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
758 .WillRepeatedly(Return(false));
759
760 MockFunction<void(std::string aCheckPointName)> check;
761 {
762 InSequence dummy;
763
764 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
765 CaretChangedReason::Updateposition));
766 EXPECT_CALL(check, Call("singletap updatecarets"));
767
768 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
769 CaretChangedReason::Updateposition));
770 EXPECT_CALL(check, Call("longtap updatecarets"));
771
772 EXPECT_CALL(mManager,
773 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
774 EXPECT_CALL(check, Call("longtap scrollstart1"));
775
776 EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
777 .WillOnce(Return(PositionChangedResult::Invisible));
778 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
779 CaretChangedReason::Updateposition));
780 EXPECT_CALL(check, Call("longtap scrollend1"));
781
782 EXPECT_CALL(mManager,
783 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
784 EXPECT_CALL(check, Call("longtap scrollstart2"));
785
786 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
787 CaretChangedReason::Updateposition));
788 EXPECT_CALL(check, Call("longtap scrollend2"));
789
790 EXPECT_CALL(mManager,
791 DispatchCaretStateChangedEvent(CaretChangedReason::Scroll));
792 EXPECT_CALL(check, Call("longtap scrollstart3"));
793
794 EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
795 CaretChangedReason::Updateposition));
796 EXPECT_CALL(check, Call("longtap scrollend3"));
797 }
798
799 // Simulate a single tap on an empty input.
800 mManager.FirstCaret().SetAppearance(Appearance::None);
801 mManager.UpdateCarets();
802 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
803 check.Call("singletap updatecarets");
804
805 // Scroll the caret within the viewport.
806 mManager.OnScrollStart();
807 mManager.OnScrollEnd();
808 EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
809
810 // Simulate a long tap on an empty input.
811 mManager.FirstCaret().SetAppearance(Appearance::Normal);
812 mManager.UpdateCarets();
813 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
814 check.Call("longtap updatecarets");
815
816 // Scroll the caret to be out of the viewport.
817 mManager.OnScrollStart();
818 check.Call("longtap scrollstart1");
819 mManager.OnScrollEnd();
820 EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
821 check.Call("longtap scrollend1");
822
823 // Scroll the caret into the viewport.
824 mManager.OnScrollStart();
825 check.Call("longtap scrollstart2");
826 mManager.OnScrollPositionChanged();
827 mManager.OnScrollEnd();
828 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
829 check.Call("longtap scrollend2");
830
831 // Scroll the caret within the viewport.
832 mManager.OnScrollStart();
833 check.Call("longtap scrollstart3");
834 mManager.OnScrollPositionChanged();
835 mManager.OnScrollEnd();
836 EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
837 check.Call("longtap scrollend3");
838 }
839
840 } // namespace mozilla
841