Bug 1177346 Part 1 - Add setSuppressedEventListener interface, r=smaug.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 03 Jan 2019 06:39:12 -1000
changeset 452649 6fffc01beb9dd5d1bb28576843ab8ce95241a39d
parent 452643 c1eea02ba0c0df7868b43ab4c30e57655938969e
child 452650 bbade19bc70a7c6ea6885c0f9faac6c13cedecdf
push id35322
push useraciure@mozilla.com
push dateSun, 06 Jan 2019 09:50:06 +0000
treeherdermozilla-central@27ef389fd0b9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1177346
milestone66.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 1177346 Part 1 - Add setSuppressedEventListener interface, r=smaug.
dom/base/Document.cpp
dom/base/Document.h
dom/webidl/Document.webidl
layout/base/PresShell.cpp
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -1741,16 +1741,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLinks);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mForms);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScripts);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplets);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommandDispatcher)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuppressedEventListener)
 
   // Traverse all our nsCOMArrays.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
 
   for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
     cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback);
@@ -1832,16 +1833,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Do
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplets);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchors);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommandDispatcher)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentL10n);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFeaturePolicy)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuppressedEventListener)
 
   tmp->mParentDocument = nullptr;
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntersectionObservers)
 
   tmp->ClearAllBoxObjects();
@@ -8487,16 +8489,27 @@ void Document::UnsuppressEventHandlingAn
 }
 
 void Document::AddSuspendedChannelEventQueue(net::ChannelEventQueue* aQueue) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(EventHandlingSuppressed());
   mSuspendedQueues.AppendElement(aQueue);
 }
 
+static bool SetSuppressedEventListenerInSubDocument(Document* aDocument,
+                                                    void* aData) {
+  aDocument->SetSuppressedEventListener(static_cast<EventListener*>(aData));
+  return true;
+}
+
+void Document::SetSuppressedEventListener(EventListener* aListener) {
+  mSuppressedEventListener = aListener;
+  EnumerateSubDocuments(SetSuppressedEventListenerInSubDocument, aListener);
+}
+
 nsISupports* Document::GetCurrentContentSink() {
   return mParser ? mParser->GetContentSink() : nullptr;
 }
 
 Document* Document::GetTemplateContentsOwner() {
   if (!mTemplateContentsOwner) {
     bool hasHadScriptObject = true;
     nsIScriptGlobalObject* scriptObject =
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -2441,16 +2441,22 @@ class Document : public nsINode,
   bool IsVisible() const { return mVisible; }
 
   /**
    * Return whether the document and all its ancestors are visible in the sense
    * of pageshow / hide.
    */
   bool IsVisibleConsideringAncestors() const;
 
+  void SetSuppressedEventListener(EventListener* aListener);
+
+  EventListener* GetSuppressedEventListener() {
+    return mSuppressedEventListener;
+  }
+
   /**
    * Return true when this document is active, i.e., an active document
    * in a content viewer.  Note that this will return true for bfcached
    * documents, so this does NOT match the "active document" concept in
    * the WHATWG spec - see IsCurrentActiveDocument.
    */
   bool IsActive() const { return mDocumentContainer && !mRemovedFromDocShell; }
 
@@ -4132,16 +4138,18 @@ class Document : public nsINode,
   RefPtr<Document> mDisplayDocument;
 
   uint32_t mEventsSuppressed;
 
   // Any XHR ChannelEventQueues that were suspended on this document while
   // events were suppressed.
   nsTArray<RefPtr<mozilla::net::ChannelEventQueue>> mSuspendedQueues;
 
+  RefPtr<EventListener> mSuppressedEventListener;
+
   /**
    * https://html.spec.whatwg.org/#ignore-destructive-writes-counter
    */
   uint32_t mIgnoreDestructiveWritesCounter;
 
   /**
    * The current frame request callback handle
    */
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -500,16 +500,24 @@ partial interface Document {
 
 // Extension to give chrome JS the ability to simulate activate the docuement
 // by user gesture.
 partial interface Document {
   [ChromeOnly]
   void notifyUserGestureActivation();
 };
 
+// Extension to give chrome JS the ability to set an event handler which is
+// called with certain events that happened while events were suppressed in the
+// document or one of its subdocuments.
+partial interface Document {
+  [ChromeOnly]
+  void setSuppressedEventListener(EventListener? aListener);
+};
+
 // Extension to give chrome and XBL JS the ability to determine whether
 // the document is sandboxed without permission to run scripts
 // and whether inline scripts are blocked by the document's CSP.
 partial interface Document {
   [Func="IsChromeOrXBL"] readonly attribute boolean hasScriptsBlockedBySandbox;
   [Func="IsChromeOrXBL"] readonly attribute boolean inlineScriptAllowedByCSP;
 };
 
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6780,16 +6780,38 @@ nsresult PresShell::HandleEvent(nsIFrame
       } else if (!mNoDelayedMouseEvents &&
                  (aEvent->mMessage == eMouseUp ||
                   // contextmenu is triggered after right mouseup on Windows and
                   // right mousedown on other platforms.
                   aEvent->mMessage == eContextMenu)) {
         auto event = MakeUnique<DelayedMouseEvent>(aEvent->AsMouseEvent());
         mDelayedEvents.AppendElement(std::move(event));
       }
+
+      // If there is a suppressed event listener associated with the document,
+      // notify it about the suppressed mouse event. This allows devtools
+      // features to continue receiving mouse events even when the devtools
+      // debugger has paused execution in a page.
+      RefPtr<EventListener> suppressedListener =
+        frame->PresContext()->Document()->GetSuppressedEventListener();
+      if (suppressedListener &&
+          aEvent->AsMouseEvent()->mReason != WidgetMouseEvent::eSynthesized) {
+        nsCOMPtr<nsIContent> targetContent;
+        frame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
+        if (targetContent) {
+          aEvent->mTarget = targetContent;
+        }
+
+        nsCOMPtr<EventTarget> et = aEvent->mTarget;
+        RefPtr<Event> event = EventDispatcher::CreateEvent(
+                et, frame->PresContext(), aEvent, EmptyString());
+
+        suppressedListener->HandleEvent(*event);
+      }
+
       return NS_OK;
     }
 
     if (!frame) {
       NS_WARNING("Nothing to handle this event!");
       return NS_OK;
     }