forked from mirrors/gecko-dev
		
	 28844e8f80
			
		
	
	
		28844e8f80
		
	
	
	
	
		
			
			To support magnifying glass on GeckoView, I would like to add `dragcaret` event and, clientX and clientX in CaretStateChangedEvent chrome event. Actually, accessible caret fires `presscaret` and `releasecaret` when accessbile caret is pressed or released. But when dragging this caret, no chrome event is fired. Since magnifying glass listens to moving this caret, I would like `dargcaret` for GeckoView. Also, Users' dragging point is necessary to set better position of magnifying glass windows. So I also want client point of dragging point on `presscaret` and `dragcaret` event. This event and properties are on layout.accessiblecaret.magnifier.enabled=true, So this can be only for GeckoView. Differential Revision: https://phabricator.services.mozilla.com/D137965
		
			
				
	
	
		
			848 lines
		
	
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			848 lines
		
	
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "gtest/gtest.h"
 | |
| #include "gmock/gmock.h"
 | |
| 
 | |
| #include <string>
 | |
| 
 | |
| #include "AccessibleCaret.h"
 | |
| #include "AccessibleCaretManager.h"
 | |
| #include "mozilla/Preferences.h"
 | |
| 
 | |
| using ::testing::_;
 | |
| using ::testing::DefaultValue;
 | |
| using ::testing::Eq;
 | |
| using ::testing::InSequence;
 | |
| using ::testing::MockFunction;
 | |
| using ::testing::Return;
 | |
| 
 | |
| // -----------------------------------------------------------------------------
 | |
| // This file tests CaretStateChanged events and the appearance of the two
 | |
| // AccessibleCarets manipulated by AccessibleCaretManager.
 | |
| 
 | |
| namespace mozilla {
 | |
| using dom::CaretChangedReason;
 | |
| 
 | |
| class MOZ_RAII AutoRestoreBoolPref final {
 | |
|  public:
 | |
|   AutoRestoreBoolPref(const char* aPref, bool aValue) : mPref(aPref) {
 | |
|     Preferences::GetBool(mPref, &mOldValue);
 | |
|     Preferences::SetBool(mPref, aValue);
 | |
|   }
 | |
| 
 | |
|   ~AutoRestoreBoolPref() { Preferences::SetBool(mPref, mOldValue); }
 | |
| 
 | |
|  private:
 | |
|   const char* mPref = nullptr;
 | |
|   bool mOldValue = false;
 | |
| };
 | |
| 
 | |
| class AccessibleCaretManagerTester : public ::testing::Test {
 | |
|  public:
 | |
|   class MockAccessibleCaret : public AccessibleCaret {
 | |
|    public:
 | |
|     MockAccessibleCaret() : AccessibleCaret(nullptr) {}
 | |
| 
 | |
|     void SetAppearance(Appearance aAppearance) override {
 | |
|       // A simplified version without touching CaretElement().
 | |
|       mAppearance = aAppearance;
 | |
|     }
 | |
| 
 | |
|     MOCK_METHOD2(SetPosition,
 | |
|                  PositionChangedResult(nsIFrame* aFrame, int32_t aOffset));
 | |
| 
 | |
|   };  // class MockAccessibleCaret
 | |
| 
 | |
|   class MockAccessibleCaretManager : public AccessibleCaretManager {
 | |
|    public:
 | |
|     using CaretMode = AccessibleCaretManager::CaretMode;
 | |
|     using AccessibleCaretManager::HideCaretsAndDispatchCaretStateChangedEvent;
 | |
|     using AccessibleCaretManager::UpdateCarets;
 | |
| 
 | |
|     MockAccessibleCaretManager()
 | |
|         : AccessibleCaretManager(nullptr,
 | |
|                                  Carets{MakeUnique<MockAccessibleCaret>(),
 | |
|                                         MakeUnique<MockAccessibleCaret>()}) {}
 | |
| 
 | |
|     MockAccessibleCaret& FirstCaret() {
 | |
|       return static_cast<MockAccessibleCaret&>(*mCarets.GetFirst());
 | |
|     }
 | |
| 
 | |
|     MockAccessibleCaret& SecondCaret() {
 | |
|       return static_cast<MockAccessibleCaret&>(*mCarets.GetSecond());
 | |
|     }
 | |
| 
 | |
|     bool CompareTreePosition(nsIFrame* aStartFrame,
 | |
|                              nsIFrame* aEndFrame) const override {
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     bool IsCaretDisplayableInCursorMode(
 | |
|         nsIFrame** aOutFrame = nullptr,
 | |
|         int32_t* aOutOffset = nullptr) const override {
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     bool UpdateCaretsForOverlappingTilt() override { return true; }
 | |
| 
 | |
|     void UpdateCaretsForAlwaysTilt(const nsIFrame* aStartFrame,
 | |
|                                    const nsIFrame* aEndFrame) override {
 | |
|       if (mCarets.GetFirst()->IsVisuallyVisible()) {
 | |
|         mCarets.GetFirst()->SetAppearance(Appearance::Left);
 | |
|       }
 | |
|       if (mCarets.GetSecond()->IsVisuallyVisible()) {
 | |
|         mCarets.GetSecond()->SetAppearance(Appearance::Right);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Terminated IsTerminated() const override { return Terminated::No; }
 | |
|     bool IsScrollStarted() const { return mIsScrollStarted; }
 | |
| 
 | |
|     Terminated MaybeFlushLayout() override { return Terminated::No; }
 | |
| 
 | |
|     MOCK_CONST_METHOD0(GetCaretMode, CaretMode());
 | |
|     MOCK_METHOD2(DispatchCaretStateChangedEvent,
 | |
|                  void(CaretChangedReason aReason, const nsPoint* aPoint));
 | |
|     MOCK_CONST_METHOD1(HasNonEmptyTextContent, bool(nsINode* aNode));
 | |
| 
 | |
|   };  // class MockAccessibleCaretManager
 | |
| 
 | |
|   using Appearance = AccessibleCaret::Appearance;
 | |
|   using PositionChangedResult = AccessibleCaret::PositionChangedResult;
 | |
|   using CaretMode = MockAccessibleCaretManager::CaretMode;
 | |
| 
 | |
|   AccessibleCaretManagerTester() {
 | |
|     DefaultValue<CaretMode>::Set(CaretMode::None);
 | |
|     DefaultValue<PositionChangedResult>::Set(PositionChangedResult::NotChanged);
 | |
| 
 | |
|     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
 | |
|         .WillRepeatedly(Return(PositionChangedResult::Position));
 | |
| 
 | |
|     EXPECT_CALL(mManager.SecondCaret(), SetPosition(_, _))
 | |
|         .WillRepeatedly(Return(PositionChangedResult::Position));
 | |
|   }
 | |
| 
 | |
|   AccessibleCaret::Appearance FirstCaretAppearance() {
 | |
|     return mManager.FirstCaret().GetAppearance();
 | |
|   }
 | |
| 
 | |
|   AccessibleCaret::Appearance SecondCaretAppearance() {
 | |
|     return mManager.SecondCaret().GetAppearance();
 | |
|   }
 | |
| 
 | |
|   // Member variables
 | |
|   MockAccessibleCaretManager mManager;
 | |
| 
 | |
| };  // class AccessibleCaretManagerTester
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester, TestUpdatesInSelectionMode)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   // Set default preference.
 | |
|   AutoRestoreBoolPref savedPref("layout.accessiblecaret.always_tilt", false);
 | |
| 
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Selection));
 | |
| 
 | |
|   EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                             CaretChangedReason::Updateposition, nullptr))
 | |
|       .Times(3);
 | |
| 
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
 | |
| 
 | |
|   mManager.OnReflow();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
 | |
| 
 | |
|   mManager.OnScrollPositionChanged();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
 | |
| }
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester, TestSingleTapOnNonEmptyInput)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Cursor));
 | |
| 
 | |
|   EXPECT_CALL(mManager, HasNonEmptyTextContent(_)).WillRepeatedly(Return(true));
 | |
| 
 | |
|   MockFunction<void(std::string aCheckPointName)> check;
 | |
|   {
 | |
|     InSequence dummy;
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("update"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Visibilitychange, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("mouse down"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_, nullptr)).Times(0);
 | |
|     EXPECT_CALL(check, Call("reflow"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_, nullptr)).Times(0);
 | |
|     EXPECT_CALL(check, Call("blur"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("mouse up"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("reflow2"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|   }
 | |
| 
 | |
|   // Simulate a single tap on a non-empty input.
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("update");
 | |
| 
 | |
|   mManager.OnSelectionChanged(nullptr, nullptr,
 | |
|                               nsISelectionListener::DRAG_REASON |
 | |
|                                   nsISelectionListener::MOUSEDOWN_REASON);
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("mouse down");
 | |
| 
 | |
|   mManager.OnReflow();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("reflow");
 | |
| 
 | |
|   mManager.OnBlur();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("blur");
 | |
| 
 | |
|   mManager.OnSelectionChanged(nullptr, nullptr,
 | |
|                               nsISelectionListener::MOUSEUP_REASON);
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("mouse up");
 | |
| 
 | |
|   mManager.OnReflow();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("reflow2");
 | |
| 
 | |
|   mManager.OnScrollPositionChanged();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
| }
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester, TestSingleTapOnEmptyInput)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   // Set default preference.
 | |
|   AutoRestoreBoolPref savedPref(
 | |
|       "layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content",
 | |
|       false);
 | |
| 
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Cursor));
 | |
| 
 | |
|   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
 | |
|       .WillRepeatedly(Return(false));
 | |
| 
 | |
|   MockFunction<void(std::string aCheckPointName)> check;
 | |
|   {
 | |
|     InSequence dummy;
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("update"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Visibilitychange, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("mouse down"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_, nullptr)).Times(0);
 | |
|     EXPECT_CALL(check, Call("reflow"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_, nullptr)).Times(0);
 | |
|     EXPECT_CALL(check, Call("blur"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("mouse up"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("reflow2"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|   }
 | |
| 
 | |
|   // Simulate a single tap on an empty input.
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("update");
 | |
| 
 | |
|   mManager.OnSelectionChanged(nullptr, nullptr,
 | |
|                               nsISelectionListener::DRAG_REASON |
 | |
|                                   nsISelectionListener::MOUSEDOWN_REASON);
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("mouse down");
 | |
| 
 | |
|   mManager.OnReflow();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("reflow");
 | |
| 
 | |
|   mManager.OnBlur();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("blur");
 | |
| 
 | |
|   mManager.OnSelectionChanged(nullptr, nullptr,
 | |
|                               nsISelectionListener::MOUSEUP_REASON);
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("mouse up");
 | |
| 
 | |
|   mManager.OnReflow();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("reflow2");
 | |
| 
 | |
|   mManager.OnScrollPositionChanged();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
| }
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester, TestTypingAtEndOfInput)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Cursor));
 | |
| 
 | |
|   EXPECT_CALL(mManager, HasNonEmptyTextContent(_)).WillRepeatedly(Return(true));
 | |
| 
 | |
|   MockFunction<void(std::string aCheckPointName)> check;
 | |
|   {
 | |
|     InSequence dummy;
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("update"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Visibilitychange, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("keyboard"));
 | |
| 
 | |
|     // No CaretStateChanged events should be dispatched since the caret has
 | |
|     // being hidden in cursor mode.
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_, nullptr)).Times(0);
 | |
|   }
 | |
| 
 | |
|   // Simulate typing the end of the input.
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("update");
 | |
| 
 | |
|   mManager.OnKeyboardEvent();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("keyboard");
 | |
| 
 | |
|   mManager.OnSelectionChanged(nullptr, nullptr,
 | |
|                               nsISelectionListener::NO_REASON);
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
| 
 | |
|   mManager.OnScrollPositionChanged();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
| }
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionMode)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   // Set default preference.
 | |
|   AutoRestoreBoolPref savedPref("layout.accessiblecaret.always_tilt", false);
 | |
| 
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Selection));
 | |
| 
 | |
|   MockFunction<void(std::string aCheckPointName)> check;
 | |
|   {
 | |
|     InSequence dummy;
 | |
| 
 | |
|     // Initially, first caret is out of scrollport, and second caret is visible.
 | |
|     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
 | |
|         .WillOnce(Return(PositionChangedResult::Invisible));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("updatecarets"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollstart1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("reflow1"));
 | |
| 
 | |
|     // After scroll ended, first caret is visible and second caret is out of
 | |
|     // scroll port.
 | |
|     EXPECT_CALL(mManager.SecondCaret(), SetPosition(_, _))
 | |
|         .WillOnce(Return(PositionChangedResult::Invisible));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollend1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollstart2"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("reflow2"));
 | |
| 
 | |
|     // After the scroll ended, both carets are visible.
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollend2"));
 | |
|   }
 | |
| 
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("updatecarets");
 | |
| 
 | |
|   mManager.OnScrollStart();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("scrollstart1");
 | |
| 
 | |
|   mManager.OnReflow();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("reflow1");
 | |
| 
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollend1");
 | |
| 
 | |
|   mManager.OnScrollStart();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollstart2");
 | |
| 
 | |
|   mManager.OnReflow();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("reflow2");
 | |
| 
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("scrollend2");
 | |
| }
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester,
 | |
|        TestScrollInSelectionModeWithAlwaysTiltPref)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   // Simulate Firefox Android preference.
 | |
|   AutoRestoreBoolPref savedPref("layout.accessiblecaret.always_tilt", true);
 | |
| 
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Selection));
 | |
| 
 | |
|   MockFunction<void(std::string aCheckPointName)> check;
 | |
|   {
 | |
|     InSequence dummy;
 | |
| 
 | |
|     // Initially, first caret is out of scrollport, and second caret is visible.
 | |
|     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
 | |
|         .WillOnce(Return(PositionChangedResult::Invisible));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("updatecarets"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollstart1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_, nullptr)).Times(0);
 | |
|     EXPECT_CALL(check, Call("scrollPositionChanged1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("reflow1"));
 | |
| 
 | |
|     // After scroll ended, first caret is visible and second caret is out of
 | |
|     // scroll port.
 | |
|     EXPECT_CALL(mManager.SecondCaret(), SetPosition(_, _))
 | |
|         .WillOnce(Return(PositionChangedResult::Invisible));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollend1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollstart2"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_, nullptr)).Times(0);
 | |
|     EXPECT_CALL(check, Call("scrollPositionChanged2"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("reflow2"));
 | |
| 
 | |
|     // After the scroll ended, both carets are visible.
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollend2"));
 | |
|   }
 | |
| 
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
 | |
|   check.Call("updatecarets");
 | |
| 
 | |
|   mManager.OnScrollStart();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
 | |
|   check.Call("scrollstart1");
 | |
| 
 | |
|   mManager.OnScrollPositionChanged();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
 | |
|   check.Call("scrollPositionChanged1");
 | |
| 
 | |
|   mManager.OnReflow();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
 | |
|   check.Call("reflow1");
 | |
| 
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollend1");
 | |
| 
 | |
|   mManager.OnScrollStart();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollstart2");
 | |
| 
 | |
|   mManager.OnScrollPositionChanged();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollPositionChanged2");
 | |
| 
 | |
|   mManager.OnReflow();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("reflow2");
 | |
| 
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
 | |
|   EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
 | |
|   check.Call("scrollend2");
 | |
| }
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenLogicallyVisible)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Cursor));
 | |
| 
 | |
|   EXPECT_CALL(mManager, HasNonEmptyTextContent(_)).WillRepeatedly(Return(true));
 | |
| 
 | |
|   MockFunction<void(std::string aCheckPointName)> check;
 | |
|   {
 | |
|     InSequence dummy;
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("updatecarets"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("scrollstart1"));
 | |
| 
 | |
|     // After scroll ended, the caret is out of scroll port.
 | |
|     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
 | |
|         .WillRepeatedly(Return(PositionChangedResult::Invisible));
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("scrollend1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("scrollstart2"));
 | |
| 
 | |
|     // After scroll ended, the caret is visible again.
 | |
|     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
 | |
|         .WillRepeatedly(Return(PositionChangedResult::Position));
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("scrollend2"));
 | |
|   }
 | |
| 
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("updatecarets");
 | |
| 
 | |
|   mManager.OnScrollStart();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("scrollstart1");
 | |
| 
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollend1");
 | |
| 
 | |
|   mManager.OnScrollStart();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollstart2");
 | |
| 
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("scrollend2");
 | |
| }
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenHidden)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Cursor));
 | |
| 
 | |
|   EXPECT_CALL(mManager, HasNonEmptyTextContent(_)).WillRepeatedly(Return(true));
 | |
| 
 | |
|   MockFunction<void(std::string aCheckPointName)> check;
 | |
|   {
 | |
|     InSequence dummy;
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("updatecarets"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Visibilitychange, nullptr))
 | |
|         .Times(1);
 | |
|     EXPECT_CALL(check, Call("hidecarets"));
 | |
| 
 | |
|     // After scroll ended, the caret is out of scroll port.
 | |
|     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
 | |
|         .WillRepeatedly(Return(PositionChangedResult::Invisible));
 | |
|     EXPECT_CALL(check, Call("scrollend1"));
 | |
| 
 | |
|     // After scroll ended, the caret is visible again.
 | |
|     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
 | |
|         .WillRepeatedly(Return(PositionChangedResult::Position));
 | |
|     EXPECT_CALL(check, Call("scrollend2"));
 | |
|   }
 | |
| 
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("updatecarets");
 | |
| 
 | |
|   mManager.HideCaretsAndDispatchCaretStateChangedEvent();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("hidecarets");
 | |
| 
 | |
|   mManager.OnScrollStart();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
| 
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("scrollend1");
 | |
| 
 | |
|   mManager.OnScrollStart();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
| 
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("scrollend2");
 | |
| }
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeOnEmptyContent)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   // Set default preference.
 | |
|   AutoRestoreBoolPref savedPref(
 | |
|       "layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content",
 | |
|       false);
 | |
| 
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Cursor));
 | |
| 
 | |
|   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
 | |
|       .WillRepeatedly(Return(false));
 | |
| 
 | |
|   MockFunction<void(std::string aCheckPointName)> check;
 | |
|   {
 | |
|     InSequence dummy;
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("updatecarets"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollstart1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
 | |
|         .WillOnce(Return(PositionChangedResult::Invisible));
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollend1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollstart2"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollend2"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollstart3"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("scrollend3"));
 | |
|   }
 | |
| 
 | |
|   // Simulate a pinch-zoom operation before tapping on an empty content.
 | |
|   mManager.OnScrollStart();
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(mManager.IsScrollStarted(), false);
 | |
| 
 | |
|   // Simulate a single tap on an empty content.
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("updatecarets");
 | |
| 
 | |
|   // Scroll the caret to be out of the viewport.
 | |
|   mManager.OnScrollStart();
 | |
|   check.Call("scrollstart1");
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollend1");
 | |
| 
 | |
|   // Scroll the caret into the viewport.
 | |
|   mManager.OnScrollStart();
 | |
|   check.Call("scrollstart2");
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollend2");
 | |
| 
 | |
|   // Scroll the caret within the viewport.
 | |
|   mManager.OnScrollStart();
 | |
|   check.Call("scrollstart3");
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("scrollend3");
 | |
| }
 | |
| 
 | |
| TEST_F(AccessibleCaretManagerTester,
 | |
|        TestScrollInCursorModeWithCaretShownWhenLongTappingOnEmptyContentPref)
 | |
| MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
 | |
|   // Simulate Firefox Android preference.
 | |
|   AutoRestoreBoolPref savedPref(
 | |
|       "layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content",
 | |
|       true);
 | |
| 
 | |
|   EXPECT_CALL(mManager, GetCaretMode())
 | |
|       .WillRepeatedly(Return(CaretMode::Cursor));
 | |
| 
 | |
|   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
 | |
|       .WillRepeatedly(Return(false));
 | |
| 
 | |
|   MockFunction<void(std::string aCheckPointName)> check;
 | |
|   {
 | |
|     InSequence dummy;
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("singletap updatecarets"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("longtap updatecarets"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("longtap scrollstart1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
 | |
|         .WillOnce(Return(PositionChangedResult::Invisible));
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("longtap scrollend1"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("longtap scrollstart2"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("longtap scrollend2"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Scroll, nullptr));
 | |
|     EXPECT_CALL(check, Call("longtap scrollstart3"));
 | |
| 
 | |
|     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
 | |
|                               CaretChangedReason::Updateposition, nullptr));
 | |
|     EXPECT_CALL(check, Call("longtap scrollend3"));
 | |
|   }
 | |
| 
 | |
|   // Simulate a single tap on an empty input.
 | |
|   mManager.FirstCaret().SetAppearance(Appearance::None);
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
|   check.Call("singletap updatecarets");
 | |
| 
 | |
|   // Scroll the caret within the viewport.
 | |
|   mManager.OnScrollStart();
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 | |
| 
 | |
|   // Simulate a long tap on an empty input.
 | |
|   mManager.FirstCaret().SetAppearance(Appearance::Normal);
 | |
|   mManager.UpdateCarets();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("longtap updatecarets");
 | |
| 
 | |
|   // Scroll the caret to be out of the viewport.
 | |
|   mManager.OnScrollStart();
 | |
|   check.Call("longtap scrollstart1");
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 | |
|   check.Call("longtap scrollend1");
 | |
| 
 | |
|   // Scroll the caret into the viewport.
 | |
|   mManager.OnScrollStart();
 | |
|   check.Call("longtap scrollstart2");
 | |
|   mManager.OnScrollPositionChanged();
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("longtap scrollend2");
 | |
| 
 | |
|   // Scroll the caret within the viewport.
 | |
|   mManager.OnScrollStart();
 | |
|   check.Call("longtap scrollstart3");
 | |
|   mManager.OnScrollPositionChanged();
 | |
|   mManager.OnScrollEnd();
 | |
|   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 | |
|   check.Call("longtap scrollend3");
 | |
| }
 | |
| 
 | |
| }  // namespace mozilla
 |