Bug 1322939 - Introduce pending dialog stack. r=smaug draft
authorTim Nguyen <ntim.bugs@gmail.com>
Sat, 14 Jan 2017 01:08:50 +0000
changeset 460904 0b39b63a63a3f1ccad0b66bfbdd8de3f6bc758f3
parent 460721 e8ae38b46276774d445d7ac72e06d72aed75189b
child 460905 2d1d4d14bfa2fc0f439bc679ad6ece29ad8c897e
push id41522
push userbmo:ntim.bugs@gmail.com
push dateSat, 14 Jan 2017 01:50:59 +0000
reviewerssmaug
bugs1322939
milestone53.0a1
Bug 1322939 - Introduce pending dialog stack. r=smaug MozReview-Commit-ID: 8QUR0XsLBDu
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsIDocument.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -10981,16 +10981,71 @@ nsDocument::GetFullscreenStack() const
     if (nsCOMPtr<Element> elem = do_QueryReferent(ptr)) {
       MOZ_ASSERT(elem->State().HasState(NS_EVENT_STATE_FULL_SCREEN));
       elements.AppendElement(elem);
     }
   }
   return elements;
 }
 
+// Pending dialog stack
+bool
+nsDocument::PendingDialogStackPush(Element* aElement)
+{
+  NS_ASSERTION(aElement, "Must pass non-null to PendingDialogStackPush()");
+  Element* top = PendingDialogStackTop();
+  if (top == aElement || !aElement) {
+    return false;
+  }
+  mPendingDialogStack.AppendElement(do_GetWeakReference(aElement));
+  return true;
+}
+
+Element*
+nsDocument::PendingDialogStackTop()
+{
+  if (mPendingDialogStack.IsEmpty()) {
+    return nullptr;
+  }
+  uint32_t last = mPendingDialogStack.Length() - 1;
+  nsCOMPtr<Element> element(do_QueryReferent(mPendingDialogStack[last]));
+  NS_ASSERTION(element, "Should have pending dialog!");
+  NS_ASSERTION(element->IsInUncomposedDoc(), "Pending dialog should be in doc");
+  NS_ASSERTION(element->OwnerDoc() == this, "Pending dialog should be in this doc");
+  return element;
+}
+
+void
+nsDocument::RemoveDialogFromPendingStack(Element* aDialog) {
+  NS_ASSERTION(dialog, "Should have pending dialog!");
+  NS_ASSERTION(dialog->IsInUncomposedDoc(), "Pending dialog should be in doc");
+  NS_ASSERTION(dialog->OwnerDoc() == this, "Pending dialog should be in this doc");
+  uint32_t i = mPendingDialogStack.Length();
+  while (i > 0) {
+    --i;
+    if (nsCOMPtr<Element> elem = do_QueryReferent(mPendingDialogStack[i])) {
+      if (elem == aDialog) {
+        mPendingDialogStack.RemoveElementAt(i);
+      }
+    }
+  }
+}
+
+/* virtual */ nsTArray<Element*>
+nsDocument::GetPendingDialogStack() const
+{
+  nsTArray<Element*> elements;
+  for (const nsWeakPtr& ptr : mPendingDialogStack) {
+    if (nsCOMPtr<Element> elem = do_QueryReferent(ptr)) {
+      elements.AppendElement(elem);
+    }
+  }
+  return elements;
+}
+
 // Returns true if aDoc is in the focused tab in the active window.
 static bool
 IsInActiveTab(nsIDocument* aDoc)
 {
   nsCOMPtr<nsIDocShell> docshell = aDoc->GetDocShell();
   if (!docshell) {
     return false;
   }
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1021,16 +1021,18 @@ public:
 
   virtual nsresult GetStateObject(nsIVariant** aResult) override;
 
   virtual nsDOMNavigationTiming* GetNavigationTiming() const override;
   virtual nsresult SetNavigationTiming(nsDOMNavigationTiming* aTiming) override;
 
   virtual Element* FindImageMap(const nsAString& aNormalizedMapName) override;
 
+  virtual nsTArray<Element*> GetPendingDialogStack() const override;
+
   virtual nsTArray<Element*> GetFullscreenStack() const override;
   virtual void AsyncRequestFullScreen(
     mozilla::UniquePtr<FullscreenRequest>&& aRequest) override;
   virtual void RestorePreviousFullScreenState() override;
   virtual bool IsFullscreenLeaf() override;
   virtual nsresult
     RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement) override;
 
@@ -1061,16 +1063,21 @@ public:
   // This array contains nodes that have been blocked to prevent
   // user tracking. They most likely have had their nsIChannel
   // canceled by the URL classifier (Safebrowsing).
   //
   already_AddRefed<nsSimpleContentList> BlockedTrackingNodes() const;
 
   static bool IsUnprefixedFullscreenEnabled(JSContext* aCx, JSObject* aObject);
 
+  // Pending dialog stack functions
+  Element* PendingDialogStackTop();
+  bool PendingDialogStackPush(Element* aElement);
+  void RemoveDialogFromPendingStack(Element* aDialog);
+
   // Do the "fullscreen element ready check" from the fullscreen spec.
   // It returns true if the given element is allowed to go into fullscreen.
   bool FullscreenElementReadyCheck(Element* aElement, bool aWasCallerChrome);
 
   // This is called asynchronously by nsIDocument::AsyncRequestFullScreen()
   // to move this document into full-screen mode if allowed.
   void RequestFullScreen(mozilla::UniquePtr<FullscreenRequest>&& aRequest);
 
@@ -1355,16 +1362,20 @@ protected:
   // nullptr until GetOrCreatePendingAnimationTracker is called.
   RefPtr<mozilla::PendingAnimationTracker> mPendingAnimationTracker;
 
   // Weak reference to the scope object (aka the script global object)
   // that, unlike mScriptGlobalObject, is never unset once set. This
   // is a weak reference to avoid leaks due to circular references.
   nsWeakPtr mScopeObject;
 
+  // Stack of pending dialogs. When a modal dialog is opened, it gets pushed onto
+  // stack, it is closed, it gets popped from the stack.
+  nsTArray<nsWeakPtr> mPendingDialogStack;
+
   // Stack of full-screen elements. When we request full-screen we push the
   // full-screen element onto this stack, and when we cancel full-screen we
   // pop one off this stack, restoring the previous full-screen state
   nsTArray<nsWeakPtr> mFullScreenStack;
 
   // The root of the doc tree in which this document is in. This is only
   // non-null when this document is in fullscreen mode.
   nsWeakPtr mFullscreenRoot;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1344,16 +1344,21 @@ public:
    * Add/Remove an element to the document's id and name hashes
    */
   virtual void AddToIdTable(Element* aElement, nsIAtom* aId) = 0;
   virtual void RemoveFromIdTable(Element* aElement, nsIAtom* aId) = 0;
   virtual void AddToNameTable(Element* aElement, nsIAtom* aName) = 0;
   virtual void RemoveFromNameTable(Element* aElement, nsIAtom* aName) = 0;
 
   /**
+   * Returns all elements in the pending dialog stack in the insertion order.
+   */
+  virtual nsTArray<Element*> GetPendingDialogStack() const = 0;
+
+  /**
    * Returns all elements in the fullscreen stack in the insertion order.
    */
   virtual nsTArray<Element*> GetFullscreenStack() const = 0;
 
   /**
    * Asynchronously requests that the document make aElement the fullscreen
    * element, and move into fullscreen mode. The current fullscreen element
    * (if any) is pushed onto the fullscreen element stack, and it can be