Bug 1420589 Part2: Define a helper class to store the target of pointer events. r=smaug.
authorStone Shih <sshih@mozilla.com>
Sun, 26 Nov 2017 21:38:55 +0800
changeset 448720 ce9b2476de5da58a3b3e24efc23e7cf9532efe83
parent 448719 16a0ca0a2afaaa322fb3d885b2760ee0d6ff04e0
child 448721 f9f606cef4077c22e8d32e0e0362761e69b7b705
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1420589
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1420589 Part2: Define a helper class to store the target of pointer events. r=smaug. MozReview-Commit-ID: IS5MM3gXpC4
layout/base/PresShell.cpp
layout/base/PresShell.h
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -540,16 +540,57 @@ public:
     }
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIDocument> mDocument;
 };
 
+// This is a helper class to track whether the targeted frame is destroyed after
+// dispatching pointer events. In that case, we need the original targeted
+// content so that we can dispatch the mouse events to it.
+class MOZ_STACK_CLASS AutoPointerEventTargetUpdater final
+{
+public:
+  AutoPointerEventTargetUpdater(PresShell* aShell,
+                                WidgetGUIEvent* aEvent,
+                                nsIFrame* aFrame,
+                                nsIContent** aTargetContent)
+  {
+    MOZ_ASSERT(aShell);
+    MOZ_ASSERT(aEvent);
+    MOZ_ASSERT(aFrame);
+    if (!aTargetContent || aEvent->mClass != ePointerEventClass) {
+      return;
+    }
+    MOZ_ASSERT(!aFrame->GetContent() ||
+               aShell->GetDocument() == aFrame->GetContent()->OwnerDoc());
+
+    MOZ_ASSERT(PointerEventHandler::IsPointerEventEnabled());
+    mShell = aShell;
+    mWeakFrame = aFrame;
+    mTargetContent = aTargetContent;
+    aShell->mPointerEventTarget = aFrame->GetContent();
+  }
+
+  ~AutoPointerEventTargetUpdater()
+  {
+    if (!mTargetContent || !mShell || mWeakFrame.IsAlive()) {
+      return;
+    }
+    mShell->mPointerEventTarget.swap(*mTargetContent);
+  }
+
+private:
+  RefPtr<PresShell> mShell;
+  AutoWeakFrame mWeakFrame;
+  nsIContent** mTargetContent;
+};
+
 bool PresShell::sDisableNonTestMouseEvents = false;
 
 mozilla::LazyLogModule PresShell::gLog("PresShell");
 
 mozilla::TimeStamp PresShell::sLastInputCreated;
 mozilla::TimeStamp PresShell::sLastInputProcessed;
 
 bool PresShell::sProcessInteractable = false;
@@ -7229,51 +7270,31 @@ PresShell::HandleEvent(nsIFrame* aFrame,
                 shell = static_cast<PresShell*>(activeShell);
                 frame = shell->GetRootFrame();
               }
             }
           }
         }
       }
     }
-
-    // Before HandlePositionedEvent we should save mPointerEventTarget in some
-    // cases
-    AutoWeakFrame weakFrame;
-    if (aTargetContent && ePointerEventClass == aEvent->mClass) {
-      MOZ_ASSERT(PointerEventHandler::IsPointerEventEnabled());
-      weakFrame = frame;
-      shell->mPointerEventTarget = frame->GetContent();
-      MOZ_ASSERT(!frame->GetContent() ||
-                 shell->GetDocument() == frame->GetContent()->OwnerDoc());
-    }
-
     // Prevent deletion until we're done with event handling (bug 336582) and
     // swap mPointerEventTarget to *aTargetContent
     nsCOMPtr<nsIPresShell> kungFuDeathGrip(shell);
     nsresult rv;
+    AutoPointerEventTargetUpdater updater(shell, aEvent, frame, aTargetContent);
     if (shell != this) {
       // Handle the event in the correct shell.
       // We pass the subshell's root frame as the frame to start from. This is
       // the only correct alternative; if the event was captured then it
       // must have been captured by us or some ancestor shell and we
       // now ask the subshell to dispatch it normally.
       rv = shell->HandlePositionedEvent(frame, aEvent, aEventStatus);
     } else {
       rv = HandlePositionedEvent(frame, aEvent, aEventStatus);
     }
-
-    // After HandlePositionedEvent we should reestablish
-    // content (which still live in tree) in some cases
-    if (aTargetContent && ePointerEventClass == aEvent->mClass) {
-      if (!weakFrame.IsAlive()) {
-        shell->mPointerEventTarget.swap(*aTargetContent);
-      }
-    }
-
     return rv;
   }
 
   nsresult rv = NS_OK;
 
   if (frame) {
     PushCurrentEventInfo(nullptr, nullptr);
 
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -37,16 +37,17 @@ class nsRange;
 struct RangePaintInfo;
 struct nsCallbackEventRequest;
 #ifdef MOZ_REFLOW_PERF
 class ReflowCountMgr;
 #endif
 
 class nsPresShellEventCB;
 class nsAutoCauseReflowNotifier;
+class AutoPointerEventTargetUpdater;
 
 namespace mozilla {
 
 namespace dom {
 class Element;
 class Selection;
 }  // namespace dom
 
@@ -422,16 +423,17 @@ protected:
   void UnsuppressAndInvalidate();
 
   void WillCauseReflow() {
     nsContentUtils::AddScriptBlocker();
     ++mChangeNestCount;
   }
   nsresult DidCauseReflow();
   friend class ::nsAutoCauseReflowNotifier;
+  friend class ::AutoPointerEventTargetUpdater;
 
   nsresult DispatchEventToDOM(mozilla::WidgetEvent* aEvent,
                               nsEventStatus* aStatus,
                               nsPresShellEventCB* aEventCB);
   void DispatchTouchEventToDOM(mozilla::WidgetEvent* aEvent,
                                nsEventStatus* aStatus,
                                nsPresShellEventCB* aEventCB,
                                bool aTouchIsNew);