diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 1b4225ea881..2f2f347d004 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -11631,7 +11631,84 @@ FullscreenRequest::~FullscreenRequest() // of nsDocument because in the majority of time, there would be at most // one document requesting fullscreen. We shouldn't waste the space to // hold for it in every document. -static LinkedList sPendingFullscreenRequests; +class PendingFullscreenRequestList +{ +public: + static void Add(UniquePtr&& aRequest) + { + sList.insertBack(aRequest.release()); + } + + static const FullscreenRequest* GetLast() + { + return sList.getLast(); + } + + class Iterator + { + public: + explicit Iterator(nsIDocument* aDoc) + : mCurrent(PendingFullscreenRequestList::sList.getFirst()) + { + if (mCurrent) { + mRootShell = GetRootShell(aDoc); + SkipToNextMatch(); + } + } + + void DeleteAndNext() + { + DeleteAndNextInternal(); + SkipToNextMatch(); + } + bool AtEnd() const { return mCurrent == nullptr; } + const FullscreenRequest& Get() const { return *mCurrent; } + + private: + already_AddRefed GetRootShell(nsIDocument* aDoc) + { + if (nsIDocShellTreeItem* shell = aDoc->GetDocShell()) { + nsCOMPtr rootShell; + shell->GetRootTreeItem(getter_AddRefs(rootShell)); + return rootShell.forget(); + } + return nullptr; + } + + void DeleteAndNextInternal() + { + FullscreenRequest* thisRequest = mCurrent; + mCurrent = mCurrent->getNext(); + delete thisRequest; + } + void SkipToNextMatch() + { + while (mCurrent) { + nsCOMPtr + rootShell = GetRootShell(mCurrent->GetDocument()); + if (!rootShell) { + // Always automatically drop documents which has been + // detached from the doc shell. + DeleteAndNextInternal(); + } else if (rootShell != mRootShell) { + mCurrent = mCurrent->getNext(); + } else { + break; + } + } + } + + FullscreenRequest* mCurrent; + nsCOMPtr mRootShell; + }; + +private: + PendingFullscreenRequestList() = delete; + + static LinkedList sList; +}; + +/* static */ LinkedList PendingFullscreenRequestList::sList; static nsCOMPtr GetRootWindow(nsIDocument* aDoc) @@ -11669,7 +11746,7 @@ nsDocument::RequestFullScreen(UniquePtr&& aRequest) return; } - sPendingFullscreenRequests.insertBack(aRequest.release()); + PendingFullscreenRequestList::Add(Move(aRequest)); if (XRE_GetProcessType() == GeckoProcessType_Content) { // If we are not the top level process, dispatch an event to make // our parent process go fullscreen first. @@ -11678,58 +11755,24 @@ nsDocument::RequestFullScreen(UniquePtr&& aRequest) /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr); } else { // Make the window fullscreen. - FullscreenRequest* lastRequest = sPendingFullscreenRequests.getLast(); + const FullscreenRequest* + lastRequest = PendingFullscreenRequestList::GetLast(); rootWin->SetFullscreenInternal(nsPIDOMWindow::eForFullscreenAPI, true, lastRequest->mVRHMDDevice); } } -/* static */ bool -nsIDocument::HandlePendingFullscreenRequest(const FullscreenRequest& aRequest, - nsIDocShellTreeItem* aRootShell, - bool* aHandled) -{ - nsDocument* doc = aRequest.GetDocument(); - nsIDocShellTreeItem* shell = doc->GetDocShell(); - if (!shell) { - return true; - } - nsCOMPtr rootShell; - shell->GetRootTreeItem(getter_AddRefs(rootShell)); - if (rootShell != aRootShell) { - return false; - } - - if (doc->ApplyFullscreen(aRequest)) { - *aHandled = true; - } - return true; -} - /* static */ bool nsIDocument::HandlePendingFullscreenRequests(nsIDocument* aDoc) { - if (sPendingFullscreenRequests.isEmpty()) { - return false; - } - bool handled = false; - nsIDocShellTreeItem* shell = aDoc->GetDocShell(); - nsCOMPtr rootShell; - if (shell) { - shell->GetRootTreeItem(getter_AddRefs(rootShell)); - } - FullscreenRequest* request = sPendingFullscreenRequests.getFirst(); - while (request) { - if (HandlePendingFullscreenRequest(*request, rootShell, &handled)) { - // Drop requests, which either have been detached from document/ - // document shell, or are handled by HandleFullscreenRequest. - FullscreenRequest* thisRequest = request; - request = request->getNext(); - delete thisRequest; - } else { - request = request->getNext(); + PendingFullscreenRequestList::Iterator iter(aDoc); + while (!iter.AtEnd()) { + const FullscreenRequest& request = iter.Get(); + if (request.GetDocument()->ApplyFullscreen(request)) { + handled = true; } + iter.DeleteAndNext(); } return handled; } @@ -11737,29 +11780,9 @@ nsIDocument::HandlePendingFullscreenRequests(nsIDocument* aDoc) static void ClearPendingFullscreenRequests(nsIDocument* aDoc) { - nsIDocShellTreeItem* shell = aDoc->GetDocShell(); - if (!shell) { - return; - } - - FullscreenRequest* request = sPendingFullscreenRequests.getFirst(); - while (request) { - nsIDocument* doc = request->GetDocument(); - bool shouldRemove = false; - for (nsCOMPtr docShell = doc->GetDocShell(); - docShell; docShell->GetParent(getter_AddRefs(docShell))) { - if (docShell == shell) { - shouldRemove = true; - break; - } - } - if (shouldRemove) { - FullscreenRequest* thisRequest = request; - request = request->getNext(); - delete thisRequest; - } else { - request = request->getNext(); - } + PendingFullscreenRequestList::Iterator iter(aDoc); + while (!iter.AtEnd()) { + iter.DeleteAndNext(); } } diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 8a9a1365b5a..e69b9b0c81c 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -100,6 +100,7 @@ class CallbackFunction; struct FullscreenRequest : public LinkedListElement { explicit FullscreenRequest(Element* aElement); + FullscreenRequest(const FullscreenRequest&) = delete; ~FullscreenRequest(); Element* GetElement() const { return mElement; } diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index 5f2acac137a..8e0ce8b95f2 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -1184,15 +1184,6 @@ public: */ static void AsyncExitFullscreen(nsIDocument* aDocument); - /** - * Handles one single fullscreen request, updates `aHandled` if the request - * is handled, and returns whether this request should be removed from the - * request queue. - */ - static bool HandlePendingFullscreenRequest(const FullscreenRequest& aRequest, - nsIDocShellTreeItem* aRootShell, - bool* aHandled); - /** * Handles any pending fullscreen in aDocument or its subdocuments. *