Coverage Report

Created: 2018-09-25 14:53

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