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 draft
authorKartikaya Gupta <kgupta@mozilla.com>
Sun, 10 Jul 2016 22:32:44 -0400
changeset 386058 4b4690c6d2961540d7e01a8c4fcba6fc6f2ff22d
parent 385645 383cedd6feb650bb1242f228692f83ca5e213920
child 525027 1ce91c04ee5e122c6abbcb1063e559d897e99caa
push id22610
push userkgupta@mozilla.com
push dateMon, 11 Jul 2016 02:33:12 +0000
reviewerstylin
bugs1255555
milestone50.0a1
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
layout/base/AccessibleCaret.cpp
layout/base/AccessibleCaret.h
layout/base/AccessibleCaretEventHub.cpp
layout/base/AccessibleCaretManager.cpp
layout/base/AccessibleCaretManager.h
--- 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,