Bug 1255555 - When a frame reconstruction triggers caret elements to be cloned, ensure the dummy touch listeners are re-registered on the clones. r?tylin
MozReview-Commit-ID: 9PVXO90Cbc4
--- a/layout/base/AccessibleCaret.cpp
+++ b/layout/base/AccessibleCaret.cpp
@@ -183,30 +183,41 @@ AccessibleCaret::Contains(const nsPoint&
nsRect rect =
nsLayoutUtils::GetRectRelativeToFrame(CaretImageElement(), RootFrame());
return rect.Contains(aPoint);
}
void
+AccessibleCaret::EnsureApzAware()
+{
+ // If the caret element was cloned, the listener might have been lost. So
+ // if that's the case we register a dummy listener if there isn't one on
+ // the element already.
+ if (!CaretElement()->IsApzAware()) {
+ CaretElement()->AddEventListener(NS_LITERAL_STRING("touchstart"),
+ mDummyTouchListener, false);
+ }
+}
+
+void
AccessibleCaret::InjectCaretElement(nsIDocument* aDocument)
{
ErrorResult rv;
nsCOMPtr<Element> element = CreateCaretElement(aDocument);
mCaretElementHolder = aDocument->InsertAnonymousContent(*element, rv);
MOZ_ASSERT(!rv.Failed(), "Insert anonymous content should not fail!");
MOZ_ASSERT(mCaretElementHolder.get(), "We must have anonymous content!");
// InsertAnonymousContent will clone the element to make an AnonymousContent.
// Since event listeners are not being cloned when cloning a node, we need to
// add the listener here.
- CaretElement()->AddEventListener(NS_LITERAL_STRING("touchstart"),
- mDummyTouchListener, false);
+ EnsureApzAware();
}
already_AddRefed<Element>
AccessibleCaret::CreateCaretElement(nsIDocument* aDocument) const
{
// Content structure of AccessibleCaret
// <div class="moz-accessiblecaret"> <- CaretElement()
// <div class="image"> <- CaretImageElement()
--- a/layout/base/AccessibleCaret.h
+++ b/layout/base/AccessibleCaret.h
@@ -131,16 +131,20 @@ public:
}
// Element for 'Intersects' test. Container of image and bar elements.
dom::Element* CaretElement() const
{
return mCaretElementHolder->GetContentNode();
}
+ // Ensures that the caret element is made "APZ aware" so that the APZ code
+ // doesn't scroll the page when the user is trying to drag the caret.
+ void EnsureApzAware();
+
protected:
// Argument aRect should be relative to CustomContentContainerFrame().
void SetCaretElementStyle(const nsRect& aRect, float aZoomLevel);
void SetSelectionBarElementStyle(const nsRect& aRect, float aZoomLevel);
// Get current zoom level.
float GetZoomLevel();
--- a/layout/base/AccessibleCaretEventHub.cpp
+++ b/layout/base/AccessibleCaretEventHub.cpp
@@ -396,16 +396,20 @@ AccessibleCaretEventHub::AccessibleCaret
AccessibleCaretEventHub::~AccessibleCaretEventHub()
{
}
void
AccessibleCaretEventHub::Init()
{
+ if (mInitialized && mManager) {
+ mManager->OnFrameReconstruction();
+ }
+
if (mInitialized || !mPresShell || !mPresShell->GetCanvasFrame() ||
!mPresShell->GetCanvasFrame()->GetCustomContentContainer()) {
return;
}
// Without nsAutoScriptBlocker, the script might be run after constructing
// mFirstCaret in AccessibleCaretManager's constructor, which might destructs
// the whole frame tree. Therefore we'll fail to construct mSecondCaret
--- a/layout/base/AccessibleCaretManager.cpp
+++ b/layout/base/AccessibleCaretManager.cpp
@@ -692,16 +692,23 @@ void
AccessibleCaretManager::OnKeyboardEvent()
{
if (GetCaretMode() == CaretMode::Cursor) {
AC_LOG("%s: HideCarets()", __FUNCTION__);
HideCarets();
}
}
+void
+AccessibleCaretManager::OnFrameReconstruction()
+{
+ mFirstCaret->EnsureApzAware();
+ mSecondCaret->EnsureApzAware();
+}
+
Selection*
AccessibleCaretManager::GetSelection() const
{
RefPtr<nsFrameSelection> fs = GetFrameSelection();
if (!fs) {
return nullptr;
}
return fs->GetSelection(SelectionType::eNormal);
--- a/layout/base/AccessibleCaretManager.h
+++ b/layout/base/AccessibleCaretManager.h
@@ -93,16 +93,20 @@ public:
// Handle NotifySelectionChanged event from nsISelectionListener.
virtual nsresult OnSelectionChanged(nsIDOMDocument* aDoc,
nsISelection* aSel,
int16_t aReason);
// Handle key event.
virtual void OnKeyboardEvent();
+ // The canvas frame holding the accessible caret anonymous content elements
+ // was reconstructed, resulting in the content elements getting cloned.
+ virtual void OnFrameReconstruction();
+
protected:
// This enum representing the number of AccessibleCarets on the screen.
enum class CaretMode : uint8_t {
// No caret on the screen.
None,
// One caret, i.e. the selection is collapsed.
Cursor,