From 528bbef9b4eeb4d883ca61c0e413a28003dc4d45 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Mon, 13 Mar 2023 20:18:46 +0000 Subject: [PATCH] Bug 1821732 - implement auto popover list, r=emilio Differential Revision: https://phabricator.services.mozilla.com/D172296 --- dom/base/Document.cpp | 50 +++++++++++++++++++++++++++++++++++-------- dom/base/Document.h | 18 ++++++++++++++++ dom/base/Element.cpp | 5 +++++ dom/base/Element.h | 2 ++ 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index fb54b0ebfb2e..df2f11fa7d2c 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -14574,11 +14574,7 @@ void Document::SetFullscreenElement(Element& aElement) { void Document::TopLayerPush(Element& aElement) { const bool modal = aElement.State().HasState(ElementState::MODAL); - auto predictFunc = [&aElement](Element* element) { - return element == &aElement; - }; - TopLayerPop(predictFunc); - + TopLayerPop(aElement); mTopLayer.AppendElement(do_GetWeakReference(&aElement)); NS_ASSERTION(GetTopLayerTop() == &aElement, "Should match"); @@ -14614,10 +14610,7 @@ void Document::AddModalDialog(HTMLDialogElement& aDialogElement) { } void Document::RemoveModalDialog(HTMLDialogElement& aDialogElement) { - auto predicate = [&aDialogElement](Element* element) -> bool { - return element == &aDialogElement; - }; - DebugOnly removedElement = TopLayerPop(predicate); + DebugOnly removedElement = TopLayerPop(aDialogElement); MOZ_ASSERT(removedElement == &aDialogElement); aDialogElement.RemoveStates(ElementState::MODAL); } @@ -14685,6 +14678,13 @@ Element* Document::TopLayerPop(FunctionRef aPredicate) { return removedElement; } +Element* Document::TopLayerPop(Element& aElement) { + auto predictFunc = [&aElement](Element* element) { + return element == &aElement; + }; + return TopLayerPop(predictFunc); +} + void Document::GetWireframe(bool aIncludeNodes, Nullable& aWireframe) { FlushPendingNotifications(FlushType::Layout); @@ -14826,6 +14826,38 @@ nsTArray Document::GetTopLayer() const { return elements; } +nsTArray Document::AutoPopoverList() const { + nsTArray elements; + for (const nsWeakPtr& ptr : mTopLayer) { + if (nsCOMPtr element = do_QueryReferent(ptr)) { + if (element && element->IsAutoPopover()) { + elements.AppendElement(element); + } + } + } + return elements; +} + +Element* Document::GetTopmostAutoPopover() const { + for (const nsWeakPtr& weakPtr : Reversed(mTopLayer)) { + nsCOMPtr element(do_QueryReferent(weakPtr)); + if (element && element->IsAutoPopover()) { + return element; + } + } + return nullptr; +} + +void Document::AddToAutoPopoverList(Element& aElement) { + MOZ_ASSERT(aElement.IsAutoPopover()); + TopLayerPush(aElement); +} + +void Document::RemoveFromAutoPopoverList(Element& aElement) { + MOZ_ASSERT(aElement.IsAutoPopover()); + TopLayerPop(aElement); +} + // Returns true if aDoc is in the focused tab in the active window. bool IsInActiveTab(Document* aDoc) { BrowsingContext* bc = aDoc->GetBrowsingContext(); diff --git a/dom/base/Document.h b/dom/base/Document.h index 5cee4a31e29a..bb006091cac5 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -1927,6 +1927,10 @@ class Document : public nsINode, // layer. The removed element, if any, is returned. Element* TopLayerPop(FunctionRef aPredicate); + // Removes the given element from the top layer. The removed element, if any, + // is returned. + Element* TopLayerPop(Element&); + MOZ_CAN_RUN_SCRIPT bool TryAutoFocusCandidate(Element& aElement); public: @@ -3449,6 +3453,20 @@ class Document : public nsINode, MOZ_CAN_RUN_SCRIPT void GetWireframe(bool aIncludeNodes, Nullable&); + // Returns a list of all the elements in the Document's top layer whose + // popover attribute is in the auto state. + // See https://html.spec.whatwg.org/multipage/popover.html#auto-popover-list + nsTArray AutoPopoverList() const; + + // Teturn document's auto popover list's last element. + // See + // https://html.spec.whatwg.org/multipage/popover.html#topmost-auto-popover + Element* GetTopmostAutoPopover() const; + + // Adds/removes an element to/from the auto popover list. + void AddToAutoPopoverList(Element&); + void RemoveFromAutoPopoverList(Element&); + Element* GetTopLayerTop(); // Return the fullscreen element in the top layer Element* GetUnretargetedFullscreenElement() const; diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 85f8a7e3eac4..2ae949a4cdf5 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -4205,6 +4205,11 @@ void Element::ClearServoData(Document* aDoc) { } } +bool Element::IsAutoPopover() const { + const auto* htmlElement = nsGenericHTMLElement::FromNode(this); + return htmlElement && htmlElement->GetPopoverState() == PopoverState::Auto; +} + ElementAnimationData& Element::CreateAnimationData() { MOZ_ASSERT(!GetAnimationData()); SetMayHaveAnimations(); diff --git a/dom/base/Element.h b/dom/base/Element.h index 964815ef1fa4..04c809be90c5 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -580,6 +580,8 @@ class Element : public FragmentOrElement { return CreatePopoverData(); } + bool IsAutoPopover() const; + ElementAnimationData* GetAnimationData() const { if (!MayHaveAnimations()) { return nullptr;