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