Bug 1466208 - part 30: Create PresShell::EventHandler::AutoCurrentEventInfoSetter class r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 04 Mar 2019 06:12:22 +0000
changeset 520179 29a17314e008b518935a689a125ff767b34752d5
parent 520178 ade393862e9dddf6a3acce62453db19e29596688
child 520180 1cc8b60d8a6bcbcca357e2e32c047669fb50d12e
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1466208
milestone67.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 1466208 - part 30: Create PresShell::EventHandler::AutoCurrentEventInfoSetter class r=smaug With splitting `HandleEvent()` a lot, it becomes more difficult to keep managing each set of calling `PushCurrentEventInfo()` and `PopCurrentEventInfo()`. So, `EventHandler` should have a helper class to push and pop current event info into/from the stack. Differential Revision: https://phabricator.services.mozilla.com/D21198
layout/base/PresShell.cpp
layout/base/PresShell.h
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6537,60 +6537,57 @@ nsresult PresShell::EventHandler::Handle
       return RetargetEventToParent(aGUIEvent, aEventStatus);
     }
 
     return NS_OK;
   }
 
   nsresult rv = NS_OK;
 
-  PushCurrentEventInfo(nullptr, nullptr);
+  AutoCurrentEventInfoSetter eventInfoSetter(*this);
 
   if (aGUIEvent->IsTargetedAtFocusedContent()) {
     mPresShell->mCurrentEventContent = nullptr;
 
     RefPtr<Element> eventTargetElement =
         ComputeFocusedEventTargetElement(aGUIEvent);
 
     mPresShell->mCurrentEventFrame = nullptr;
     Document* targetDoc =
         eventTargetElement ? eventTargetElement->OwnerDoc() : nullptr;
     if (targetDoc && targetDoc != GetDocument()) {
-      PopCurrentEventInfo();
       nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
       if (shell) {
         rv = static_cast<PresShell*>(shell.get())
                  ->HandleRetargetedEvent(aGUIEvent, aEventStatus,
                                          eventTargetElement);
       }
       return rv;
     } else {
       mPresShell->mCurrentEventContent = eventTargetElement;
     }
 
     if (!mPresShell->GetCurrentEventContent() ||
         !mPresShell->GetCurrentEventFrame() ||
         InZombieDocument(mPresShell->mCurrentEventContent)) {
       rv = RetargetEventToParent(aGUIEvent, aEventStatus);
-      PopCurrentEventInfo();
       return rv;
     }
   } else {
     mPresShell->mCurrentEventFrame = aFrame;
   }
   if (mPresShell->GetCurrentEventFrame()) {
     nsCOMPtr<nsIContent> overrideClickTarget;  // Required due to bug  1506439
     rv =
         HandleEventInternal(aGUIEvent, aEventStatus, true, overrideClickTarget);
   }
 
 #ifdef DEBUG
   mPresShell->ShowEventTargetDebug();
 #endif
-  PopCurrentEventInfo();
 
   return rv;
 }
 
 nsresult PresShell::EventHandler::HandleEventUsingCoordinates(
     nsIFrame* aFrameForPresShell, WidgetGUIEvent* aGUIEvent,
     nsEventStatus* aEventStatus, bool aDontRetargetEvents) {
   MOZ_ASSERT(aGUIEvent);
@@ -6744,25 +6741,23 @@ nsresult PresShell::EventHandler::Handle
   //     UpdateTouchEventTarget()?
   eventTargetData.UpdateTouchEventTarget(aGUIEvent);
 
   // 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.
-  eventTargetData.mPresShell->PushCurrentEventInfo(eventTargetData.mFrame,
-                                                   eventTargetData.mContent);
   EventHandler eventHandler(*eventTargetData.mPresShell);
+  AutoCurrentEventInfoSetter eventInfoSetter(eventHandler, eventTargetData);
   nsresult rv = eventHandler.HandleEventInternal(
       aGUIEvent, aEventStatus, true, eventTargetData.mOverrideClickTarget);
 #ifdef DEBUG
   eventTargetData.mPresShell->ShowEventTargetDebug();
 #endif
-  eventTargetData.mPresShell->PopCurrentEventInfo();
   return rv;
 }
 
 bool PresShell::EventHandler::MaybeFlushPendingNotifications(
     WidgetGUIEvent* aGUIEvent) {
   MOZ_ASSERT(aGUIEvent);
 
   switch (aGUIEvent->mMessage) {
@@ -7572,20 +7567,20 @@ nsresult PresShell::EventHandler::Handle
     // NOTE: We don't require that the document still have a PresShell.
     // See bug 1375940.
   }
 #endif
   NS_ENSURE_STATE(!aNewEventContent ||
                   aNewEventContent->GetComposedDoc() == GetDocument());
   AutoPointerEventTargetUpdater updater(mPresShell, aEvent, aNewEventFrame,
                                         aTargetContent);
-  PushCurrentEventInfo(aNewEventFrame, aNewEventContent);
+  AutoCurrentEventInfoSetter eventInfoSetter(*this, aNewEventFrame,
+                                             aNewEventContent);
   nsresult rv =
       HandleEventInternal(aEvent, aEventStatus, false, aOverrideClickTarget);
-  PopCurrentEventInfo();
   return rv;
 }
 
 nsresult PresShell::EventHandler::HandleEventInternal(
     WidgetEvent* aEvent, nsEventStatus* aEventStatus,
     bool aIsHandlingNativeEvent, nsIContent* aOverrideClickTarget) {
   RefPtr<EventStateManager> manager = GetPresContext()->EventStateManager();
   nsresult rv = NS_OK;
@@ -8131,16 +8126,19 @@ void PresShell::EventHandler::DispatchTo
         //         even though event target is something else.
         contentPresShell->PushCurrentEventInfo(content->GetPrimaryFrame(),
                                                content);
       }
     }
 
     nsPresContext* context = doc->GetPresContext();
     if (!context) {
+      if (contentPresShell) {
+        contentPresShell->PopCurrentEventInfo();
+      }
       continue;
     }
 
     tmpStatus = nsEventStatus_eIgnore;
     EventDispatcher::Dispatch(targetPtr, context, &newEvent, nullptr,
                               &tmpStatus, aEventCB);
     if (nsEventStatus_eConsumeNoDefault == tmpStatus ||
         newEvent.mFlags.mMultipleActionsPrevented) {
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -495,19 +495,20 @@ class PresShell final : public nsIPresSh
 
   /**
    * EventHandler is implementation of nsIPresShell::HandleEvent().
    */
   class MOZ_STACK_CLASS EventHandler final {
    public:
     EventHandler() = delete;
     EventHandler(const EventHandler& aOther) = delete;
-    explicit EventHandler(PresShell& aPresShell) : mPresShell(aPresShell) {}
+    explicit EventHandler(PresShell& aPresShell)
+        : mPresShell(aPresShell), mCurrentEventInfoSetter(nullptr) {}
     explicit EventHandler(RefPtr<PresShell>&& aPresShell)
-        : mPresShell(aPresShell.forget()) {}
+        : mPresShell(aPresShell.forget()), mCurrentEventInfoSetter(nullptr) {}
 
     /**
      * HandleEvent() may dispatch aGUIEvent.  This may redirect the event to
      * another PresShell, or the event may be handled by other classes like
      * AccessibleCaretEventHub, or discarded.
      *
      * @param aFrame                    aFrame of nsIPresShell::HandleEvent().
      *                                  (Perhaps, should be root frame of
@@ -531,26 +532,23 @@ class PresShell final : public nsIPresSh
      * @param aGUIEvent         Event to be dispatched.
      * @param aEventStatus      [in/out] EventStatus of aGUIEvent.
      * @param aTarget           The final target of aGUIEvent.
      */
     MOZ_CAN_RUN_SCRIPT
     nsresult HandleRetargetedEvent(WidgetGUIEvent* aGUIEvent,
                                    nsEventStatus* aEventStatus,
                                    nsIContent* aTarget) {
-      mPresShell->PushCurrentEventInfo(nullptr, nullptr);
-      mPresShell->mCurrentEventContent = aTarget;
-      nsresult rv = NS_OK;
-      if (mPresShell->GetCurrentEventFrame()) {
-        nsCOMPtr<nsIContent> overrideClickTarget;
-        rv = HandleEventInternal(aGUIEvent, aEventStatus, true,
+      AutoCurrentEventInfoSetter eventInfoSetter(*this, nullptr, aTarget);
+      if (!mPresShell->GetCurrentEventFrame()) {
+        return NS_OK;
+      }
+      nsCOMPtr<nsIContent> overrideClickTarget;
+      return HandleEventInternal(aGUIEvent, aEventStatus, true,
                                  overrideClickTarget);
-      }
-      mPresShell->PopCurrentEventInfo();
-      return rv;
     }
 
     /**
      * HandleEventWithTarget() tries to dispatch aEvent on aContent after
      * setting current event target content to aNewEventContent and current
      * event frame to aNewEventFrame temporarily.  Note that this supports
      * WidgetEvent, not WidgetGUIEvent.  So, you can dispatch a simple event
      * with this.
@@ -1062,40 +1060,72 @@ class PresShell final : public nsIPresSh
      *                          event becomes cancelable.
      */
     void DispatchTouchEventToDOM(WidgetEvent* aEvent,
                                  nsEventStatus* aEventStatus,
                                  nsPresShellEventCB* aEventCB,
                                  bool aTouchIsNew);
 
     /**
+     * AutoCurrentEventInfoSetter() pushes and pops current event info of
+     * aEventHandler.mPresShell.
+     */
+    struct MOZ_STACK_CLASS AutoCurrentEventInfoSetter final {
+      explicit AutoCurrentEventInfoSetter(EventHandler& aEventHandler)
+          : mEventHandler(aEventHandler) {
+        MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter);
+        mEventHandler.mCurrentEventInfoSetter = this;
+        mEventHandler.mPresShell->PushCurrentEventInfo(nullptr, nullptr);
+      }
+      AutoCurrentEventInfoSetter(EventHandler& aEventHandler, nsIFrame* aFrame,
+                                 nsIContent* aContent)
+          : mEventHandler(aEventHandler) {
+        MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter);
+        mEventHandler.mCurrentEventInfoSetter = this;
+        mEventHandler.mPresShell->PushCurrentEventInfo(aFrame, aContent);
+      }
+      AutoCurrentEventInfoSetter(EventHandler& aEventHandler,
+                                 EventTargetData& aEventTargetData)
+          : mEventHandler(aEventHandler) {
+        MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter);
+        mEventHandler.mCurrentEventInfoSetter = this;
+        mEventHandler.mPresShell->PushCurrentEventInfo(
+            aEventTargetData.mFrame, aEventTargetData.mContent);
+      }
+      ~AutoCurrentEventInfoSetter() {
+        mEventHandler.mPresShell->PopCurrentEventInfo();
+        mEventHandler.mCurrentEventInfoSetter = nullptr;
+      }
+
+     private:
+      EventHandler& mEventHandler;
+    };
+
+    /**
      * Wrapper methods to access methods of mPresShell.
      */
     nsPresContext* GetPresContext() const {
       return mPresShell->GetPresContext();
     }
     Document* GetDocument() const { return mPresShell->GetDocument(); }
-    void PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent) {
-      mPresShell->PushCurrentEventInfo(aFrame, aContent);
-    }
     nsCSSFrameConstructor* FrameConstructor() const {
       return mPresShell->FrameConstructor();
     }
-    void PopCurrentEventInfo() { mPresShell->PopCurrentEventInfo(); }
     already_AddRefed<nsPIDOMWindowOuter> GetFocusedDOMWindowInOurWindow() {
       return mPresShell->GetFocusedDOMWindowInOurWindow();
     }
     already_AddRefed<nsIPresShell> GetParentPresShellForEventHandling() {
       return mPresShell->GetParentPresShellForEventHandling();
     }
     void PushDelayedEventIntoQueue(UniquePtr<DelayedEvent>&& aDelayedEvent) {
       mPresShell->mDelayedEvents.AppendElement(std::move(aDelayedEvent));
     }
 
     OwningNonNull<PresShell> mPresShell;
+    AutoCurrentEventInfoSetter* mCurrentEventInfoSetter;
     static TimeStamp sLastInputCreated;
     static TimeStamp sLastInputProcessed;
     static StaticRefPtr<Element> sLastKeyDownEventTargetElement;
   };
 
   /**
    * Helper method of EventHandler::HandleEvent().  This is called when the
    * event is dispatched without ref-point and dispatched by