Bug 1322939 - Introduce pending dialog stack. r=smaug
MozReview-Commit-ID: 8QUR0XsLBDu
--- 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