commit 45879990e9f1aa6481a9c973491bf8c418cbb21d parent adc5a7fa4ebb6efe9789ecbf0d057cf663b71174 Author: Emilio Cobos Álvarez <emilio@crisal.io> Date: Wed, 17 Dec 2025 19:40:38 +0000 Bug 1725177 - Make ::backdrop a real generated content pseudo-element. r=layout-reviewers,firefox-style-system-reviewers,dshin This allows animating ::backdrop and addresses long-standing animation issues. Differential Revision: https://phabricator.services.mozilla.com/D276755 Diffstat:
43 files changed, 382 insertions(+), 669 deletions(-)
diff --git a/dom/animation/AnimationUtils.cpp b/dom/animation/AnimationUtils.cpp @@ -117,6 +117,11 @@ AnimationUtils::GetElementPseudoPair(const Element* aElementOrPseudo) { PseudoStyleRequest::Marker()}; } + if (aElementOrPseudo->IsGeneratedContentContainerForBackdrop()) { + return {aElementOrPseudo->GetParent()->AsElement(), + PseudoStyleRequest::Backdrop()}; + } + const PseudoStyleType type = aElementOrPseudo->GetPseudoElementType(); if (PseudoStyle::IsViewTransitionPseudoElement(type)) { // Note: ::view-transition doesn't have a name, so we check if it has a name diff --git a/dom/animation/AnimationUtils.h b/dom/animation/AnimationUtils.h @@ -85,6 +85,13 @@ class AnimationUtils { const PseudoStyleRequest& aPseudoRequest = PseudoStyleRequest::NotPseudo()); + static bool StoresAnimationsInParent(PseudoStyleType aType) { + return aType == PseudoStyleType::before || + aType == PseudoStyleType::after || + aType == PseudoStyleType::marker || + aType == PseudoStyleType::backdrop; + } + /** * Returns true if this pseudo style type is supported by animations. * Note: This doesn't include PseudoStyleType::NotPseudo. @@ -92,8 +99,7 @@ class AnimationUtils { static bool IsSupportedPseudoForAnimations(PseudoStyleType aType) { // FIXME: Bug 1615469: Support first-line and first-letter for Animation. return PseudoStyle::IsViewTransitionPseudoElement(aType) || - aType == PseudoStyleType::before || - aType == PseudoStyleType::after || aType == PseudoStyleType::marker; + StoresAnimationsInParent(aType); } static bool IsSupportedPseudoForAnimations( const PseudoStyleRequest& aRequest) { diff --git a/dom/animation/EffectCompositor.cpp b/dom/animation/EffectCompositor.cpp @@ -566,7 +566,8 @@ EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame) { switch (request.mType) { case PseudoStyleType::before: case PseudoStyleType::after: - case PseudoStyleType::marker: { + case PseudoStyleType::marker: + case PseudoStyleType::backdrop: { nsIContent* parent = element->GetParent(); if (!parent || !parent->IsElement()) { return result; @@ -790,6 +791,7 @@ bool EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags, // element in mElementsToRestyle is the parent of the pseudo. if (aRoot && (aRoot->IsGeneratedContentContainerForBefore() || aRoot->IsGeneratedContentContainerForAfter() || + aRoot->IsGeneratedContentContainerForBackdrop() || aRoot->IsGeneratedContentContainerForMarker())) { aRoot = aRoot->GetParentElement(); } diff --git a/dom/animation/ElementAnimationData.cpp b/dom/animation/ElementAnimationData.cpp @@ -7,6 +7,7 @@ #include "ElementAnimationData.h" #include "mozilla/AnimationCollection.h" +#include "mozilla/AnimationUtils.h" #include "mozilla/EffectSet.h" #include "mozilla/TimelineCollection.h" #include "mozilla/dom/CSSAnimation.h" @@ -19,6 +20,7 @@ namespace mozilla { const ElementAnimationData::PerElementOrPseudoData* ElementAnimationData::GetPseudoData(const PseudoStyleRequest& aRequest) const { MOZ_ASSERT(!aRequest.IsNotPseudo(), "Only for pseudo-elements"); + MOZ_ASSERT(AnimationUtils::IsSupportedPseudoForAnimations(aRequest.mType)); auto entry = mPseudoData.Lookup(aRequest); if (!entry) { @@ -32,6 +34,7 @@ ElementAnimationData::PerElementOrPseudoData& ElementAnimationData::GetOrCreatePseudoData( const PseudoStyleRequest& aRequest) { MOZ_ASSERT(!aRequest.IsNotPseudo(), "Only for pseudo-elements"); + MOZ_ASSERT(AnimationUtils::IsSupportedPseudoForAnimations(aRequest.mType)); UniquePtr<PerElementOrPseudoData>& data = mPseudoData.LookupOrInsertWith( aRequest, [&] { return MakeUnique<PerElementOrPseudoData>(); }); diff --git a/dom/animation/ElementAnimationData.h b/dom/animation/ElementAnimationData.h @@ -86,47 +86,15 @@ class ElementAnimationData { const PerElementOrPseudoData* GetData( const PseudoStyleRequest& aRequest) const { - switch (aRequest.mType) { - case PseudoStyleType::NotPseudo: - return &mElementData; - case PseudoStyleType::before: - case PseudoStyleType::after: - case PseudoStyleType::marker: - case PseudoStyleType::viewTransition: - case PseudoStyleType::viewTransitionGroup: - case PseudoStyleType::viewTransitionImagePair: - case PseudoStyleType::viewTransitionOld: - case PseudoStyleType::viewTransitionNew: - return GetPseudoData(aRequest); - default: - MOZ_ASSERT_UNREACHABLE( - "Should not try to get animation effects for " - "a pseudo other that :before, :after, ::marker, or view transition " - "pseudo-elements"); - break; + if (aRequest.mType != PseudoStyleType::NotPseudo) { + return GetPseudoData(aRequest); } - return nullptr; + return &mElementData; } PerElementOrPseudoData& GetOrCreateData(const PseudoStyleRequest& aRequest) { - switch (aRequest.mType) { - case PseudoStyleType::NotPseudo: - break; - case PseudoStyleType::before: - case PseudoStyleType::after: - case PseudoStyleType::marker: - case PseudoStyleType::viewTransition: - case PseudoStyleType::viewTransitionGroup: - case PseudoStyleType::viewTransitionImagePair: - case PseudoStyleType::viewTransitionOld: - case PseudoStyleType::viewTransitionNew: - return GetOrCreatePseudoData(aRequest); - default: - MOZ_ASSERT_UNREACHABLE( - "Should not try to get animation effects for " - "a pseudo other that :before, :after, ::marker, or view transition " - "pseudo-elements"); - break; + if (aRequest.mType != PseudoStyleType::NotPseudo) { + return GetOrCreatePseudoData(aRequest); } return mElementData; } diff --git a/dom/animation/KeyframeEffect.cpp b/dom/animation/KeyframeEffect.cpp @@ -1568,6 +1568,9 @@ nsIFrame* KeyframeEffect::GetPrimaryFrame() const { case PseudoStyleType::marker: frame = nsLayoutUtils::GetMarkerFrame(mTarget.mElement); break; + case PseudoStyleType::backdrop: + frame = nsLayoutUtils::GetBackdropFrame(mTarget.mElement); + break; case PseudoStyleType::viewTransition: case PseudoStyleType::viewTransitionGroup: case PseudoStyleType::viewTransitionImagePair: diff --git a/dom/base/ChildIterator.cpp b/dom/base/ChildIterator.cpp @@ -158,28 +158,35 @@ nsIContent* FlattenedChildIterator::GetPreviousChild() { } nsIContent* AllChildrenIterator::Get() const { + using enum Phase; switch (mPhase) { - case eAtMarkerKid: { + case AtBackdropKid: { + Element* backdrop = nsLayoutUtils::GetBackdropPseudo(Parent()); + MOZ_ASSERT(backdrop, "No content marker frame at AtBackdropKid phase"); + return backdrop; + } + + case AtMarkerKid: { Element* marker = nsLayoutUtils::GetMarkerPseudo(Parent()); - MOZ_ASSERT(marker, "No content marker frame at eAtMarkerKid phase"); + MOZ_ASSERT(marker, "No content marker frame at AtMarkerKid phase"); return marker; } - case eAtBeforeKid: { + case AtBeforeKid: { Element* before = nsLayoutUtils::GetBeforePseudo(Parent()); - MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase"); + MOZ_ASSERT(before, "No content before frame at AtBeforeKid phase"); return before; } - case eAtFlatTreeKids: + case AtFlatTreeKids: return FlattenedChildIterator::Get(); - case eAtAnonKids: + case AtAnonKids: return mAnonKids[mAnonKidsIdx]; - case eAtAfterKid: { + case AtAfterKid: { Element* after = nsLayoutUtils::GetAfterPseudo(Parent()); - MOZ_ASSERT(after, "No content after frame at eAtAfterKid phase"); + MOZ_ASSERT(after, "No content after frame at AtAfterKid phase"); return after; } @@ -189,35 +196,19 @@ nsIContent* AllChildrenIterator::Get() const { } bool AllChildrenIterator::Seek(const nsIContent* aChildToFind) { - if (mPhase == eAtBegin || mPhase == eAtMarkerKid) { - Element* markerPseudo = nsLayoutUtils::GetMarkerPseudo(Parent()); - if (markerPseudo && markerPseudo == aChildToFind) { - mPhase = eAtMarkerKid; - return true; - } - mPhase = eAtBeforeKid; - } - if (mPhase == eAtBeforeKid) { - Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(Parent()); - if (beforePseudo && beforePseudo == aChildToFind) { - return true; + using enum Phase; + while (mPhase != AtEnd) { + if (mPhase == AtFlatTreeKids) { + if (FlattenedChildIterator::Seek(aChildToFind)) { + return true; + } + mPhase = AtAnonKids; } - mPhase = eAtFlatTreeKids; - } - - if (mPhase == eAtFlatTreeKids) { - if (FlattenedChildIterator::Seek(aChildToFind)) { + if (GetNextChild() == aChildToFind) { return true; } - mPhase = eAtAnonKids; } - - nsIContent* child = nullptr; - do { - child = GetNextChild(); - } while (child && child != aChildToFind); - - return child == aChildToFind; + return false; } void AllChildrenIterator::AppendNativeAnonymousChildren() { @@ -225,110 +216,116 @@ void AllChildrenIterator::AppendNativeAnonymousChildren() { } nsIContent* AllChildrenIterator::GetNextChild() { - if (mPhase == eAtBegin) { - mPhase = eAtMarkerKid; - if (Element* markerContent = nsLayoutUtils::GetMarkerPseudo(Parent())) { - return markerContent; - } - } - - if (mPhase == eAtMarkerKid) { - mPhase = eAtBeforeKid; - if (Element* beforeContent = nsLayoutUtils::GetBeforePseudo(Parent())) { - return beforeContent; - } - } - - if (mPhase == eAtBeforeKid) { - // Advance into our explicit kids. - mPhase = eAtFlatTreeKids; - } - - if (mPhase == eAtFlatTreeKids) { - if (nsIContent* kid = FlattenedChildIterator::GetNextChild()) { - return kid; - } - mPhase = eAtAnonKids; - } - - if (mPhase == eAtAnonKids) { - if (mAnonKids.IsEmpty()) { - MOZ_ASSERT(mAnonKidsIdx == UINT32_MAX); - AppendNativeAnonymousChildren(); - mAnonKidsIdx = 0; - } else { - if (mAnonKidsIdx == UINT32_MAX) { + using enum Phase; + switch (mPhase) { + case AtBegin: + if (Element* backdropPseudo = + nsLayoutUtils::GetBackdropPseudo(Parent())) { + mPhase = AtBackdropKid; + return backdropPseudo; + } + [[fallthrough]]; + case AtBackdropKid: + if (Element* markerContent = nsLayoutUtils::GetMarkerPseudo(Parent())) { + mPhase = AtMarkerKid; + return markerContent; + } + [[fallthrough]]; + case AtMarkerKid: + if (Element* beforeContent = nsLayoutUtils::GetBeforePseudo(Parent())) { + mPhase = AtBeforeKid; + return beforeContent; + } + [[fallthrough]]; + case AtBeforeKid: + [[fallthrough]]; + case AtFlatTreeKids: + if (nsIContent* kid = FlattenedChildIterator::GetNextChild()) { + mPhase = AtFlatTreeKids; + return kid; + } + [[fallthrough]]; + case AtAnonKids: + if (mAnonKids.IsEmpty()) { + MOZ_ASSERT(mAnonKidsIdx == UINT32_MAX); + AppendNativeAnonymousChildren(); + mAnonKidsIdx = 0; + } else if (mAnonKidsIdx == UINT32_MAX) { mAnonKidsIdx = 0; } else { mAnonKidsIdx++; } - } - - if (mAnonKidsIdx < mAnonKids.Length()) { - return mAnonKids[mAnonKidsIdx]; - } - - mPhase = eAtAfterKid; - if (Element* afterContent = nsLayoutUtils::GetAfterPseudo(Parent())) { - return afterContent; - } + if (mAnonKidsIdx < mAnonKids.Length()) { + mPhase = AtAnonKids; + return mAnonKids[mAnonKidsIdx]; + } + if (Element* afterContent = nsLayoutUtils::GetAfterPseudo(Parent())) { + mPhase = AtAfterKid; + return afterContent; + } + [[fallthrough]]; + case AtAfterKid: + case AtEnd: + break; } - mPhase = eAtEnd; + mPhase = AtEnd; return nullptr; } nsIContent* AllChildrenIterator::GetPreviousChild() { - if (mPhase == eAtEnd) { - MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length()); - mPhase = eAtAnonKids; - Element* afterContent = nsLayoutUtils::GetAfterPseudo(Parent()); - if (afterContent) { - mPhase = eAtAfterKid; - return afterContent; - } - } - - if (mPhase == eAtAfterKid) { - mPhase = eAtAnonKids; - } - - if (mPhase == eAtAnonKids) { - if (mAnonKids.IsEmpty()) { - AppendNativeAnonymousChildren(); - mAnonKidsIdx = mAnonKids.Length(); - } - - // If 0 then it turns into UINT32_MAX, which indicates the iterator is - // before the anonymous children. - --mAnonKidsIdx; - if (mAnonKidsIdx < mAnonKids.Length()) { - return mAnonKids[mAnonKidsIdx]; - } - mPhase = eAtFlatTreeKids; - } - - if (mPhase == eAtFlatTreeKids) { - if (nsIContent* kid = FlattenedChildIterator::GetPreviousChild()) { - return kid; - } - - Element* beforeContent = nsLayoutUtils::GetBeforePseudo(Parent()); - if (beforeContent) { - mPhase = eAtBeforeKid; - return beforeContent; - } - } - - if (mPhase == eAtFlatTreeKids || mPhase == eAtBeforeKid) { - Element* markerContent = nsLayoutUtils::GetMarkerPseudo(Parent()); - if (markerContent) { - mPhase = eAtMarkerKid; - return markerContent; - } + using enum Phase; + switch (mPhase) { + case AtEnd: + if (Element* afterContent = nsLayoutUtils::GetAfterPseudo(Parent())) { + mPhase = AtAfterKid; + return afterContent; + } + [[fallthrough]]; + case AtAfterKid: + MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length()); + [[fallthrough]]; + case AtAnonKids: + if (mAnonKids.IsEmpty()) { + AppendNativeAnonymousChildren(); + mAnonKidsIdx = mAnonKids.Length(); + } + // If 0 then it turns into UINT32_MAX, which indicates the iterator is + // before the anonymous children. + --mAnonKidsIdx; + if (mAnonKidsIdx < mAnonKids.Length()) { + mPhase = AtAnonKids; + return mAnonKids[mAnonKidsIdx]; + } + [[fallthrough]]; + case AtFlatTreeKids: + if (nsIContent* kid = FlattenedChildIterator::GetPreviousChild()) { + mPhase = AtFlatTreeKids; + return kid; + } + if (Element* beforeContent = nsLayoutUtils::GetBeforePseudo(Parent())) { + mPhase = AtBeforeKid; + return beforeContent; + } + [[fallthrough]]; + case AtBeforeKid: + if (Element* markerContent = nsLayoutUtils::GetMarkerPseudo(Parent())) { + mPhase = AtMarkerKid; + return markerContent; + } + [[fallthrough]]; + case AtMarkerKid: + if (Element* backdrop = nsLayoutUtils::GetBackdropPseudo(Parent())) { + mPhase = AtBackdropKid; + return backdrop; + } + [[fallthrough]]; + case AtBackdropKid: + case AtBegin: + break; } - mPhase = eAtBegin; + mPhase = AtBegin; return nullptr; } diff --git a/dom/base/ChildIterator.h b/dom/base/ChildIterator.h @@ -92,7 +92,7 @@ class AllChildrenIterator : private FlattenedChildIterator { : FlattenedChildIterator(aNode, aStartAtBeginning), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0), mFlags(aFlags), - mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) {} + mPhase(aStartAtBeginning ? Phase::AtBegin : Phase::AtEnd) {} #ifdef DEBUG AllChildrenIterator(AllChildrenIterator&&) = default; @@ -120,18 +120,18 @@ class AllChildrenIterator : private FlattenedChildIterator { nsIContent* GetNextChild(); nsIContent* GetPreviousChild(); - enum IteratorPhase { - eAtBegin, - eAtMarkerKid, - eAtBeforeKid, - eAtFlatTreeKids, - eAtAnonKids, - eAtAfterKid, - eAtEnd + private: + enum class Phase : uint8_t { + AtBegin, + AtBackdropKid, + AtMarkerKid, + AtBeforeKid, + AtFlatTreeKids, + AtAnonKids, + AtAfterKid, + AtEnd }; - IteratorPhase Phase() const { return mPhase; } - private: // Helpers. void AppendNativeAnonymousChildren(); @@ -145,7 +145,7 @@ class AllChildrenIterator : private FlattenedChildIterator { uint32_t mAnonKidsIdx; uint32_t mFlags; - IteratorPhase mPhase; + Phase mPhase; #ifdef DEBUG // XXX we should really assert there are no frame tree changes as well, but // there's no easy way to do that. diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp @@ -4417,6 +4417,8 @@ static void GetAnimationsUnsortedForSubtree( GetAnimationsUnsorted(element, PseudoStyleRequest::Before(), aAnimations); GetAnimationsUnsorted(element, PseudoStyleRequest::After(), aAnimations); GetAnimationsUnsorted(element, PseudoStyleRequest::Marker(), aAnimations); + GetAnimationsUnsorted(element, PseudoStyleRequest::Backdrop(), + aAnimations); } } @@ -4477,6 +4479,9 @@ void Element::GetAnimationsWithoutFlush( } else if (IsGeneratedContentContainerForMarker()) { elem = GetParentElement(); pseudoRequest.mType = PseudoStyleType::marker; + } else if (IsGeneratedContentContainerForBackdrop()) { + elem = GetParentElement(); + pseudoRequest.mType = PseudoStyleType::backdrop; } if (!elem) { @@ -4486,6 +4491,7 @@ void Element::GetAnimationsWithoutFlush( // FIXME: Bug 1935557. Rewrite this to support pseudoElement option. if (!aOptions.mSubtree || (pseudoRequest.mType == PseudoStyleType::before || pseudoRequest.mType == PseudoStyleType::after || + pseudoRequest.mType == PseudoStyleType::backdrop || pseudoRequest.mType == PseudoStyleType::marker)) { // Case 1: Non-subtree, or |this| is ::before, ::after, or ::marker. // @@ -4506,12 +4512,13 @@ void Element::CloneAnimationsFrom(const Element& aOther) { MOZ_ASSERT(timeline, "Timeline has not been set on the document yet"); // Iterate through all pseudo types and copy the effects from each of the // other element's effect sets into this element's effect set. - // FIXME: Bug 1929470. This funciton is for printing, and it may be tricky to + // FIXME: Bug 1929470. This function is for printing, and it may be tricky to // support view transitions. We have to revisit here after we support view // transitions to make sure we clone the animations properly. for (PseudoStyleType pseudoType : {PseudoStyleType::NotPseudo, PseudoStyleType::before, - PseudoStyleType::after, PseudoStyleType::marker}) { + PseudoStyleType::after, PseudoStyleType::marker, + PseudoStyleType::backdrop}) { // If the element has an effect set for this pseudo type (or not pseudo) // then copy the effects and animation properties. const PseudoStyleRequest request(pseudoType); @@ -4915,6 +4922,8 @@ Element* Element::GetPseudoElement(const PseudoStyleRequest& aRequest) const { return nsLayoutUtils::GetAfterPseudo(this); case PseudoStyleType::marker: return nsLayoutUtils::GetMarkerPseudo(this); + case PseudoStyleType::backdrop: + return nsLayoutUtils::GetBackdropPseudo(this); case PseudoStyleType::viewTransition: case PseudoStyleType::viewTransitionGroup: case PseudoStyleType::viewTransitionImagePair: diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp @@ -12472,6 +12472,10 @@ Maybe<int32_t> nsContentUtils::GetIndexInParent(const nsINode* aParent, return Nothing(); } + if (aNode->IsGeneratedContentContainerForBackdrop()) { + return Some(-4); + } + if (aNode->IsGeneratedContentContainerForMarker()) { return Some(-3); } diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h @@ -1714,6 +1714,12 @@ class nsINode : public mozilla::dom::EventTarget { mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentmarker; } + /** Whether this is the container of a ::backdrop pseudo-element. */ + bool IsGeneratedContentContainerForBackdrop() const { + return IsRootOfNativeAnonymousSubtree() && + mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentbackdrop; + } + /** * Returns true if |this| node is the closest common inclusive ancestor * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of the diff --git a/dom/xml/nsXMLElement.cpp b/dom/xml/nsXMLElement.cpp @@ -36,6 +36,9 @@ void nsXMLElement::UnbindFromTree(UnbindContext& aContext) { case PseudoStyleType::after: property = nsGkAtoms::afterPseudoProperty; break; + case PseudoStyleType::backdrop: + property = nsGkAtoms::backdropPseudoProperty; + break; default: property = nullptr; } diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp @@ -54,7 +54,6 @@ #include "mozilla/intl/LocaleService.h" #include "nsAtom.h" #include "nsAutoLayoutPhase.h" -#include "nsBackdropFrame.h" #include "nsBlockFrame.h" #include "nsCRT.h" #include "nsCSSAnonBoxes.h" @@ -774,8 +773,6 @@ class MOZ_STACK_CLASS nsFrameConstructorState { bool aCanBePositioned, bool aCanBeFloated, nsFrameState* aPlaceholderType); - - void ConstructBackdropFrameFor(nsIContent* aContent, nsIFrame* aFrame); }; nsFrameConstructorState::nsFrameConstructorState( @@ -1062,49 +1059,6 @@ AbsoluteFrameList* nsFrameConstructorState::GetOutOfFlowFrameList( return nullptr; } -void nsFrameConstructorState::ConstructBackdropFrameFor(nsIContent* aContent, - nsIFrame* aFrame) { - MOZ_ASSERT(aFrame->StyleDisplay()->mTopLayer == StyleTopLayer::Auto); - nsContainerFrame* frame = do_QueryFrame(aFrame); - if (!frame) { - NS_WARNING("Cannot create backdrop frame for non-container frame"); - return; - } - - ComputedStyle* parentStyle = nsLayoutUtils::GetStyleFrame(aFrame)->Style(); - if (parentStyle->GetPseudoType() != PseudoStyleType::NotPseudo) { - // ::backdrop only applies to actual elements in the top layer, for now at - // least. Prevent creating it for internal pseudos like - // ::-moz-snapshot-containing-block. - // https://drafts.csswg.org/css-position-4/#backdrop - return; - } - - RefPtr<ComputedStyle> style = - mPresShell->StyleSet()->ResolvePseudoElementStyle( - *aContent->AsElement(), PseudoStyleType::backdrop, nullptr, - parentStyle); - MOZ_ASSERT(style->StyleDisplay()->mTopLayer == StyleTopLayer::Auto); - nsContainerFrame* parentFrame = - GetGeometricParent(*style->StyleDisplay(), nullptr); - - nsBackdropFrame* backdropFrame = - new (mPresShell) nsBackdropFrame(style, mPresShell->GetPresContext()); - backdropFrame->Init(aContent, parentFrame, nullptr); - - nsFrameState placeholderType; - AbsoluteFrameList* frameList = - GetOutOfFlowFrameList(backdropFrame, true, true, &placeholderType); - MOZ_ASSERT(placeholderType & PLACEHOLDER_FOR_TOPLAYER); - - nsIFrame* placeholder = nsCSSFrameConstructor::CreatePlaceholderFrameFor( - mPresShell, aContent, backdropFrame, frame, nullptr, placeholderType); - frame->SetInitialChildList(FrameChildListID::Backdrop, - nsFrameList(placeholder, placeholder)); - - frameList->AppendFrame(nullptr, backdropFrame); -} - void nsFrameConstructorState::AddChild( nsIFrame* aNewFrame, nsFrameList& aFrameList, nsIContent* aContent, nsContainerFrame* aParentFrame, bool aCanBePositioned, bool aCanBeFloated, @@ -1139,10 +1093,6 @@ void nsFrameConstructorState::AddChild( placeholderFrame->AddStateBits(mAdditionalStateBits); // Add the placeholder frame to the flow aFrameList.AppendFrame(nullptr, placeholderFrame); - - if (placeholderType & PLACEHOLDER_FOR_TOPLAYER) { - ConstructBackdropFrameFor(aContent, aNewFrame); - } } #ifdef DEBUG else { @@ -1828,11 +1778,14 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem( ItemFlags aExtraFlags) { MOZ_ASSERT(aPseudoElement == PseudoStyleType::before || aPseudoElement == PseudoStyleType::after || - aPseudoElement == PseudoStyleType::marker, + aPseudoElement == PseudoStyleType::marker || + aPseudoElement == PseudoStyleType::backdrop, "unexpected aPseudoElement"); - if (HasUAWidget(aOriginatingElement) && + if (aPseudoElement != PseudoStyleType::backdrop && + HasUAWidget(aOriginatingElement) && !aOriginatingElement.IsHTMLElement(nsGkAtoms::details)) { + // ::before / ::after / ::marker shouldn't work on <video> / <input>. return; } @@ -1864,6 +1817,10 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem( elemName = nsGkAtoms::mozgeneratedcontentmarker; property = nsGkAtoms::markerPseudoProperty; break; + case PseudoStyleType::backdrop: + elemName = nsGkAtoms::mozgeneratedcontentbackdrop; + property = nsGkAtoms::backdropPseudoProperty; + break; default: MOZ_ASSERT_UNREACHABLE("unexpected aPseudoElement"); } @@ -1913,30 +1870,31 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem( mPresShell->StyleSet()->StyleNewSubtree(container); pseudoStyle = ServoStyleSet::ResolveServoStyle(*container); } - - auto AppendChild = [&container, this](nsIContent* aChild) { - // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE - // here; it would get set under AppendChildTo. But AppendChildTo might - // think that we're going from not being anonymous to being anonymous and - // do some extra work; setting the flag here avoids that. - aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE); - container->AppendChildTo(aChild, false, IgnoreErrors()); - if (auto* childElement = Element::FromNode(aChild)) { - // If we created any children elements, Servo needs to traverse them, but - // the root is already set up. - mPresShell->StyleSet()->StyleNewSubtree(childElement); + if (aPseudoElement != PseudoStyleType::backdrop) { + auto AppendChild = [&container, this](nsIContent* aChild) { + // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE + // here; it would get set under AppendChildTo. But AppendChildTo might + // think that we're going from not being anonymous to being anonymous and + // do some extra work; setting the flag here avoids that. + aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE); + container->AppendChildTo(aChild, false, IgnoreErrors()); + if (auto* childElement = Element::FromNode(aChild)) { + // If we created any children elements, Servo needs to traverse them, + // but the root is already set up. + mPresShell->StyleSet()->StyleNewSubtree(childElement); + } + }; + auto items = pseudoStyle->StyleContent()->NonAltContentItems(); + size_t index = 0; + for (const auto& item : items) { + CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle, item, + index++, AppendChild); + } + // If a ::marker has no 'content' then generate it from its 'list-style-*'. + if (index == 0 && aPseudoElement == PseudoStyleType::marker) { + CreateGeneratedContentFromListStyle(aState, aOriginatingElement, + *pseudoStyle, AppendChild); } - }; - auto items = pseudoStyle->StyleContent()->NonAltContentItems(); - size_t index = 0; - for (const auto& item : items) { - CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle, item, - index++, AppendChild); - } - // If a ::marker has no 'content' then generate it from its 'list-style-*'. - if (index == 0 && aPseudoElement == PseudoStyleType::marker) { - CreateGeneratedContentFromListStyle(aState, aOriginatingElement, - *pseudoStyle, AppendChild); } auto flags = ItemFlags{ItemFlag::IsGeneratedContent} + aExtraFlags; AddFrameConstructionItemsInternal(aState, container, aParentFrame, true, @@ -3322,7 +3280,8 @@ static nsIFrame* FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame) { "should not have exited generated content"); auto pseudo = f->Style()->GetPseudoType(); if (pseudo == PseudoStyleType::before || pseudo == PseudoStyleType::after || - pseudo == PseudoStyleType::marker) { + pseudo == PseudoStyleType::marker || + pseudo == PseudoStyleType::backdrop) { return f; } } @@ -5798,6 +5757,9 @@ nsIFrame* nsCSSFrameConstructor::FindSiblingInternal( auto getNearPseudo = [&](const nsIContent* aContent) -> nsIFrame* { if (aDirection == SiblingDirection::Forward) { + if (auto* backdrop = nsLayoutUtils::GetBackdropFrame(aContent)) { + return backdrop; + } if (auto* marker = getInsideMarkerFrame(aContent)) { return marker; } @@ -5813,7 +5775,10 @@ nsIFrame* nsCSSFrameConstructor::FindSiblingInternal( if (auto* before = nsLayoutUtils::GetBeforeFrame(aContent)) { return before; } - return getInsideMarkerFrame(aContent); + if (auto* marker = getInsideMarkerFrame(aContent)) { + return marker; + } + return nsLayoutUtils::GetBackdropFrame(aContent); }; while (nsIContent* sibling = nextDomSibling(aIter)) { @@ -9682,43 +9647,49 @@ void nsCSSFrameConstructor::ProcessChildren( AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems; GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems); #ifdef DEBUG - for (uint32_t i = 0; i < anonymousItems.Length(); ++i) { - MOZ_ASSERT(anonymousItems[i].mContent->IsRootOfNativeAnonymousSubtree(), + for (auto& item : anonymousItems) { + MOZ_ASSERT(item.mContent->IsRootOfNativeAnonymousSubtree(), "Content should know it's an anonymous subtree"); } #endif AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems, itemsToConstruct, pageNameTracker); + // Generated content content should have the same style parent as normal kids. + // + // Note that we don't use this style for looking up things like special + // block styles because in some cases involving table pseudo-frames it has + // nothing to do with the parent frame's desired behavior. + auto* styleParentFrame = + nsIFrame::CorrectStyleParentFrame(aFrame, PseudoStyleType::NotPseudo); + ComputedStyle* parentStyle = styleParentFrame->Style(); + if (parentStyle->StyleDisplay()->mTopLayer == StyleTopLayer::Auto && + !aContent->IsInNativeAnonymousSubtree()) { + CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(), + *parentStyle, PseudoStyleType::backdrop, + itemsToConstruct); + } + nsBlockFrame* listItem = nullptr; bool isOutsideMarker = false; if (!aPossiblyLeafFrame->IsLeaf()) { - // :before/:after content should have the same style parent as normal kids. - // - // Note that we don't use this style for looking up things like special - // block styles because in some cases involving table pseudo-frames it has - // nothing to do with the parent frame's desired behavior. - auto* styleParentFrame = - nsIFrame::CorrectStyleParentFrame(aFrame, PseudoStyleType::NotPseudo); - ComputedStyle* computedStyle = styleParentFrame->Style(); - if (aCanHaveGeneratedContent) { - if (computedStyle->StyleDisplay()->IsListItem() && + if (parentStyle->StyleDisplay()->IsListItem() && (listItem = do_QueryFrame(aFrame)) && !styleParentFrame->IsFieldSetFrame()) { - isOutsideMarker = computedStyle->StyleList()->mListStylePosition == + isOutsideMarker = parentStyle->StyleList()->mListStylePosition == StyleListStylePosition::Outside; ItemFlags extraFlags; if (isOutsideMarker) { extraFlags += ItemFlag::IsForOutsideMarker; } CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(), - *computedStyle, PseudoStyleType::marker, + *parentStyle, PseudoStyleType::marker, itemsToConstruct, extraFlags); } // Probe for generated content before CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(), - *computedStyle, PseudoStyleType::before, + *parentStyle, PseudoStyleType::before, itemsToConstruct); } @@ -9735,7 +9706,7 @@ void nsCSSFrameConstructor::ProcessChildren( "GetInsertionPoint should agree with us"); if (addChildItems) { AddFrameConstructionItems(aState, child, iter.ShadowDOMInvolved(), - *computedStyle, insertion, itemsToConstruct); + *parentStyle, insertion, itemsToConstruct); } else { ClearLazyBits(child, child->GetNextSibling()); } @@ -9745,7 +9716,7 @@ void nsCSSFrameConstructor::ProcessChildren( if (aCanHaveGeneratedContent) { // Probe for generated content after CreateGeneratedContentItem(aState, aFrame, *aContent->AsElement(), - *computedStyle, PseudoStyleType::after, + *parentStyle, PseudoStyleType::after, itemsToConstruct); } } else { @@ -11164,18 +11135,18 @@ void nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState, void nsCSSFrameConstructor::BuildInlineChildItems( nsFrameConstructorState& aState, FrameConstructionItem& aParentItem, bool aItemIsWithinSVGText, bool aItemAllowsTextPathChild) { - ComputedStyle* const parentComputedStyle = aParentItem.mComputedStyle; + ComputedStyle* const parentStyle = aParentItem.mComputedStyle; nsIContent* const parentContent = aParentItem.mContent; if (!aItemIsWithinSVGText) { - if (parentComputedStyle->StyleDisplay()->IsListItem()) { + if (parentStyle->StyleDisplay()->IsListItem()) { CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(), - *parentComputedStyle, PseudoStyleType::marker, + *parentStyle, PseudoStyleType::marker, aParentItem.mChildItems); } // Probe for generated content before CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(), - *parentComputedStyle, PseudoStyleType::before, + *parentStyle, PseudoStyleType::before, aParentItem.mChildItems); } @@ -11192,14 +11163,14 @@ void nsCSSFrameConstructor::BuildInlineChildItems( for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) { AddFrameConstructionItems(aState, content, iter.ShadowDOMInvolved(), - *parentComputedStyle, InsertionPoint(), + *parentStyle, InsertionPoint(), aParentItem.mChildItems, flags); } if (!aItemIsWithinSVGText) { // Probe for generated content after CreateGeneratedContentItem(aState, nullptr, *parentContent->AsElement(), - *parentComputedStyle, PseudoStyleType::after, + *parentStyle, PseudoStyleType::after, aParentItem.mChildItems); } diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp @@ -842,7 +842,8 @@ FrameChildListID nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame) { static Element* GetPseudo(const nsIContent* aContent, nsAtom* aPseudoProperty) { MOZ_ASSERT(aPseudoProperty == nsGkAtoms::beforePseudoProperty || aPseudoProperty == nsGkAtoms::afterPseudoProperty || - aPseudoProperty == nsGkAtoms::markerPseudoProperty); + aPseudoProperty == nsGkAtoms::markerPseudoProperty || + aPseudoProperty == nsGkAtoms::backdropPseudoProperty); if (!aContent->MayHaveAnonymousChildren()) { return nullptr; } @@ -882,6 +883,15 @@ nsIFrame* nsLayoutUtils::GetMarkerFrame(const nsIContent* aContent) { return pseudo ? pseudo->GetPrimaryFrame() : nullptr; } +Element* nsLayoutUtils::GetBackdropPseudo(const nsIContent* aContent) { + return GetPseudo(aContent, nsGkAtoms::backdropPseudoProperty); +} + +nsIFrame* nsLayoutUtils::GetBackdropFrame(const nsIContent* aContent) { + Element* pseudo = GetBackdropPseudo(aContent); + return pseudo ? pseudo->GetPrimaryFrame() : nullptr; +} + #ifdef ACCESSIBILITY void nsLayoutUtils::GetMarkerSpokenText(const nsIContent* aContent, nsAString& aText) { diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h @@ -293,6 +293,12 @@ class nsLayoutUtils { */ static nsIFrame* GetMarkerFrame(const nsIContent* aContent); + /** + * Returns the ::backdrop pseudo-element for aContent, if any. + */ + static mozilla::dom::Element* GetBackdropPseudo(const nsIContent* aContent); + static nsIFrame* GetBackdropFrame(const nsIContent* aContent); + #ifdef ACCESSIBILITY /** * Set aText to the spoken text for the given ::marker content (aContent) diff --git a/layout/forms/nsProgressFrame.cpp b/layout/forms/nsProgressFrame.cpp @@ -101,12 +101,7 @@ void nsProgressFrame::Reflow(nsPresContext* aPresContext, MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsProgressFrame"); MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); - - NS_ASSERTION(mBarDiv, "Progress bar div must exist!"); - NS_ASSERTION( - PrincipalChildList().GetLength() == 1 && - PrincipalChildList().FirstChild() == mBarDiv->GetPrimaryFrame(), - "unexpected child frames"); + MOZ_ASSERT(mBarDiv, "Progress bar div must exist!"); NS_ASSERTION(!GetPrevContinuation(), "nsProgressFrame should not have continuations; if it does we " "need to call RegUnregAccessKey only for the first."); @@ -135,6 +130,8 @@ void nsProgressFrame::ReflowChildFrame(nsIFrame* aChild, const ReflowInput& aReflowInput, const LogicalSize& aParentContentBoxSize, nsReflowStatus& aStatus) { + MOZ_ASSERT(aChild == mBarDiv->GetPrimaryFrame() || + aChild->IsPlaceholderFrame()); bool vertical = ResolvedOrientationIsVertical(); const WritingMode wm = aChild->GetWritingMode(); const LogicalSize parentSizeInChildWM = diff --git a/layout/generic/FrameClasses.py b/layout/generic/FrameClasses.py @@ -48,7 +48,6 @@ TEXT = COMMON | LINE_PARTICIPANT | {"Replaced"} | LEAF FRAME_CLASSES = [ Frame("BRFrame", "Br", REPLACED | LINE_PARTICIPANT | LEAF), Frame("nsBCTableCellFrame", "TableCell", TABLE_CELL), - Frame("nsBackdropFrame", "Backdrop", COMMON | LEAF), Frame("nsBlockFrame", "Block", BLOCK), Frame("nsCanvasFrame", "Canvas", BLOCK), Frame("nsCheckboxRadioFrame", "CheckboxRadio", REPLACED | LEAF), diff --git a/layout/generic/ViewportFrame.cpp b/layout/generic/ViewportFrame.cpp @@ -259,15 +259,8 @@ nsDisplayWrapList* ViewportFrame::BuildDisplayListForContentTopLayer( "layer"); continue; } - if (nsIFrame* backdropPh = - frame->GetChildList(FrameChildListID::Backdrop).FirstChild()) { - MOZ_ASSERT(!backdropPh->GetNextSibling(), "more than one ::backdrop?"); - MOZ_ASSERT(backdropPh->HasAnyStateBits(NS_FRAME_FIRST_REFLOW), - "did you intend to reflow ::backdrop placeholders?"); - nsIFrame* backdropFrame = - nsPlaceholderFrame::GetRealFrameForPlaceholder(backdropPh); + if (auto* backdropFrame = nsLayoutUtils::GetBackdropFrame(elem)) { BuildDisplayListForTopLayerFrame(aBuilder, backdropFrame, &topLayerList); - if (aIsOpaque) { *aIsOpaque = BackdropListIsOpaque(this, aBuilder, &topLayerList); } diff --git a/layout/generic/moz.build b/layout/generic/moz.build @@ -177,7 +177,6 @@ UNIFIED_SOURCES += [ "CSSOrderAwareFrameIterator.cpp", "MathMLTextRunFactory.cpp", "MiddleCroppingBlockFrame.cpp", - "nsBackdropFrame.cpp", "nsBlockFrame.cpp", "nsBlockReflowContext.cpp", "nsCanvasFrame.cpp", diff --git a/layout/generic/nsBackdropFrame.cpp b/layout/generic/nsBackdropFrame.cpp @@ -1,87 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* rendering object for CSS "::backdrop" */ - -#include "nsBackdropFrame.h" - -#include "mozilla/PresShell.h" -#include "nsDisplayList.h" - -using namespace mozilla; - -NS_IMPL_FRAMEARENA_HELPERS(nsBackdropFrame) - -#ifdef DEBUG_FRAME_DUMP -nsresult nsBackdropFrame::GetFrameName(nsAString& aResult) const { - return MakeFrameName(u"Backdrop"_ns, aResult); -} -#endif - -/* virtual */ -ComputedStyle* nsBackdropFrame::GetParentComputedStyle( - nsIFrame** aProviderFrame) const { - // Style context of backdrop pseudo-element does not inherit from - // any element, per the Fullscreen API spec. - *aProviderFrame = nullptr; - return nullptr; -} - -/* virtual */ -void nsBackdropFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists) { - DO_GLOBAL_REFLOW_COUNT_DSP("nsBackdropFrame"); - // We want this frame to always be there even if its display value is - // none or contents so that we can respond to style change on it. To - // support those values, we skip painting ourselves in those cases. - auto display = StyleDisplay()->mDisplay; - if (display == mozilla::StyleDisplay::None || - display == mozilla::StyleDisplay::Contents) { - return; - } - - DisplayBorderBackgroundOutline(aBuilder, aLists); -} - -/* virtual */ -LogicalSize nsBackdropFrame::ComputeAutoSize( - const SizeComputationInput& aSizingInput, WritingMode aWM, - const LogicalSize& aCBSize, nscoord aAvailableISize, - const LogicalSize& aMargin, const LogicalSize& aBorderPadding, - const StyleSizeOverrides& aSizeOverrides, ComputeSizeFlags aFlags) { - if (IsAbsolutelyPositionedWithDefiniteContainingBlock()) { - // Absolutely-positioned backdrop sizes to viewport - i.e. Given a situation - // where such backdrop will shown, scrolling the main window will cause - // the backdrop to scroll out. - return ComputeAbsolutePosAutoSize(aSizingInput, aWM, aCBSize, - aAvailableISize, aMargin, aBorderPadding, - aSizeOverrides, aFlags); - } - - // Note that this frame is a child of the viewport frame. - LogicalSize result(aWM, 0xdeadbeef, NS_UNCONSTRAINEDSIZE); - if (aFlags.contains(ComputeSizeFlag::ShrinkWrap)) { - result.ISize(aWM) = 0; - } else { - result.ISize(aWM) = - aAvailableISize - aMargin.ISize(aWM) - aBorderPadding.ISize(aWM); - } - return result; -} - -/* virtual */ -void nsBackdropFrame::Reflow(nsPresContext* aPresContext, - ReflowOutput& aDesiredSize, - const ReflowInput& aReflowInput, - nsReflowStatus& aStatus) { - MarkInReflow(); - DO_GLOBAL_REFLOW_COUNT("nsBackdropFrame"); - MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); - - // Note that this frame is a child of the viewport frame. - WritingMode wm = aReflowInput.GetWritingMode(); - aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm)); -} diff --git a/layout/generic/nsBackdropFrame.h b/layout/generic/nsBackdropFrame.h @@ -1,40 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* rendering object for CSS "::backdrop" */ - -#ifndef nsBackdropFrame_h___ -#define nsBackdropFrame_h___ - -#include "nsIFrame.h" - -class nsBackdropFrame final : public nsIFrame { - public: - NS_DECL_FRAMEARENA_HELPERS(nsBackdropFrame) - - explicit nsBackdropFrame(ComputedStyle* aStyle, nsPresContext* aPresContext) - : nsIFrame(aStyle, aPresContext, kClassID) {} - -#ifdef DEBUG_FRAME_DUMP - virtual nsresult GetFrameName(nsAString& aResult) const override; -#endif - virtual ComputedStyle* GetParentComputedStyle( - nsIFrame** aProviderFrame) const override; - virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists) override; - mozilla::LogicalSize ComputeAutoSize( - const SizeComputationInput& aSizingInput, mozilla::WritingMode aWM, - const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize, - const mozilla::LogicalSize& aMargin, - const mozilla::LogicalSize& aBorderPadding, - const mozilla::StyleSizeOverrides& aSizeOverrides, - mozilla::ComputeSizeFlags aFlags) override; - virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, - const ReflowInput& aReflowInput, - nsReflowStatus& aStatus) override; -}; - -#endif // nsBackdropFrame_h___ diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp @@ -74,27 +74,6 @@ void nsContainerFrame::SetInitialChildList(ChildListID aListID, MOZ_ASSERT(mFrames.IsEmpty(), "unexpected second call to SetInitialChildList"); mFrames = std::move(aChildList); - } else if (aListID == FrameChildListID::Backdrop) { - MOZ_ASSERT(StyleDisplay()->mTopLayer != StyleTopLayer::None, - "Only top layer frames should have backdrop"); - MOZ_ASSERT(HasAnyStateBits(NS_FRAME_OUT_OF_FLOW), - "Top layer frames should be out-of-flow"); - MOZ_ASSERT(!GetProperty(BackdropProperty()), - "We shouldn't have setup backdrop frame list before"); -#ifdef DEBUG - { - nsIFrame* placeholder = aChildList.FirstChild(); - MOZ_ASSERT(aChildList.OnlyChild(), "Should have only one backdrop"); - MOZ_ASSERT(placeholder->IsPlaceholderFrame(), - "The frame to be stored should be a placeholder"); - MOZ_ASSERT(static_cast<nsPlaceholderFrame*>(placeholder) - ->GetOutOfFlowFrame() - ->IsBackdropFrame(), - "The placeholder should points to a backdrop frame"); - } -#endif - nsFrameList* list = new (PresShell()) nsFrameList(std::move(aChildList)); - SetProperty(BackdropProperty(), list); } else { MOZ_ASSERT_UNREACHABLE("Unexpected child list"); } @@ -242,7 +221,7 @@ void nsContainerFrame::Destroy(DestroyContext& aContext) { if (MOZ_UNLIKELY(!mProperties.IsEmpty())) { using T = mozilla::FrameProperties::UntypedDescriptor; - bool hasO = false, hasOC = false, hasEOC = false, hasBackdrop = false; + bool hasO = false, hasOC = false, hasEOC = false; mProperties.ForEach([&](const T& aProp, uint64_t) { if (aProp == OverflowProperty()) { hasO = true; @@ -250,8 +229,6 @@ void nsContainerFrame::Destroy(DestroyContext& aContext) { hasOC = true; } else if (aProp == ExcessOverflowContainersProperty()) { hasEOC = true; - } else if (aProp == BackdropProperty()) { - hasBackdrop = true; } return true; }); @@ -272,13 +249,6 @@ void nsContainerFrame::Destroy(DestroyContext& aContext) { SafelyDestroyFrameListProp(aContext, presShell, ExcessOverflowContainersProperty()); } - - MOZ_ASSERT(!GetProperty(BackdropProperty()) || - StyleDisplay()->mTopLayer != StyleTopLayer::None, - "only top layer frame may have backdrop"); - if (hasBackdrop) { - SafelyDestroyFrameListProp(aContext, presShell, BackdropProperty()); - } } nsSplittableFrame::Destroy(aContext); @@ -305,10 +275,6 @@ const nsFrameList& nsContainerFrame::GetChildList(ChildListID aListID) const { nsFrameList* list = GetExcessOverflowContainers(); return list ? *list : nsFrameList::EmptyList(); } - case FrameChildListID::Backdrop: { - nsFrameList* list = GetProperty(BackdropProperty()); - return list ? *list : nsFrameList::EmptyList(); - } default: return nsSplittableFrame::GetChildList(aListID); } @@ -335,9 +301,6 @@ void nsContainerFrame::GetChildLists(nsTArray<ChildList>* aLists) const { (void)this; // silence clang -Wunused-lambda-capture in opt builds reinterpret_cast<L>(aValue)->AppendIfNonempty( aLists, FrameChildListID::ExcessOverflowContainers); - } else if (aProp == BackdropProperty()) { - reinterpret_cast<L>(aValue)->AppendIfNonempty(aLists, - FrameChildListID::Backdrop); } return true; }); @@ -2819,9 +2782,8 @@ void nsContainerFrame::SanityCheckChildListsBeforeReflow() const { "the process."); for (const auto& [list, listID] : f->ChildLists()) { if (!itemLists.contains(listID)) { - MOZ_ASSERT( - absLists.contains(listID) || listID == FrameChildListID::Backdrop, - "unexpected non-empty child list"); + MOZ_ASSERT(absLists.contains(listID), + "unexpected non-empty child list"); continue; } for (const auto* child : list) { diff --git a/layout/generic/nsContainerFrame.h b/layout/generic/nsContainerFrame.h @@ -495,7 +495,6 @@ class nsContainerFrame : public nsSplittableFrame { NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowProperty) NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowContainersProperty) NS_DECLARE_FRAME_PROPERTY_FRAMELIST(ExcessOverflowContainersProperty) - NS_DECLARE_FRAME_PROPERTY_FRAMELIST(BackdropProperty) // Only really used on nsBlockFrame instances, but the caller thinks it could // have arbitrary nsContainerFrames. diff --git a/layout/generic/nsFrameList.cpp b/layout/generic/nsFrameList.cpp @@ -477,8 +477,6 @@ const char* ChildListName(FrameChildListID aListID) { return "MarkerList"; case FrameChildListID::PushedFloats: return "PushedFloatsList"; - case FrameChildListID::Backdrop: - return "BackdropList"; case FrameChildListID::NoReflowPrincipal: return "NoReflowPrincipalList"; } diff --git a/layout/generic/nsFrameList.h b/layout/generic/nsFrameList.h @@ -45,7 +45,6 @@ enum class FrameChildListID { Float, Marker, PushedFloats, - Backdrop, // A special alias for FrameChildListID::Principal that suppress the reflow // request that is normally done when manipulating child lists. NoReflowPrincipal, diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp @@ -10559,12 +10559,7 @@ void nsGridContainerFrame::StoreUsedTrackSizes(LogicalAxis aAxis, void nsGridContainerFrame::SetInitialChildList(ChildListID aListID, nsFrameList&& aChildList) { ChildListIDs supportedLists = {FrameChildListID::Principal}; - // We don't handle the FrameChildListID::Backdrop frames in any way, but it - // only contains a placeholder for ::backdrop which is OK to not reflow (for - // now anyway). - supportedLists += FrameChildListID::Backdrop; MOZ_ASSERT(supportedLists.contains(aListID), "unexpected child list"); - return nsContainerFrame::SetInitialChildList(aListID, std::move(aChildList)); } diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp @@ -100,7 +100,10 @@ void nsPlaceholderFrame::Reflow(nsPresContext* aPresContext, // Popups are an exception though, because their position doesn't depend on // the placeholder, so they don't have this requirement (and this condition // doesn't hold anyways because the default popupgroup goes before than the - // default tooltip, for example). + // default tooltip, for example). Same for the backdrop. + // TODO(emilio): All top layer nodes technically can hit this, but their + // static pos is supposed to be 0, 0, see + // https://github.com/w3c/csswg-drafts/issues/9939. // // We also have an exception if the out-of-flow created an orthogonal flow, // because in this case we may have needed to do a measuring reflow during @@ -108,6 +111,7 @@ void nsPlaceholderFrame::Reflow(nsPresContext* aPresContext, // placeholder being reflowed first. if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW) && !mOutOfFlowFrame->IsMenuPopupFrame() && + mOutOfFlowFrame->Style()->GetPseudoType() != PseudoStyleType::backdrop && !mOutOfFlowFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW) && !mOutOfFlowFrame->GetWritingMode().IsOrthogonalTo(GetWritingMode())) { // Unfortunately, this can currently happen when the placeholder is in a diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp @@ -251,6 +251,8 @@ void nsVideoFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, } nsIContent* videoControlsDiv = GetVideoControls(); + const nsSize containerSize = + aReflowInput.ComputedSizeAsContainerIfConstrained(); // Reflow the child frames. We may have up to three: an image // frame (for the poster image), a container frame for the controls, @@ -264,8 +266,6 @@ void nsVideoFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, ReflowInput kidReflowInput(aPresContext, aReflowInput, child, availableSize); ReflowOutput kidDesiredSize(myWM); - const nsSize containerSize = - aReflowInput.ComputedSizeAsContainerIfConstrained(); if (child->GetContent() == mPosterImage) { // Reflow the poster frame. @@ -323,7 +323,8 @@ void nsVideoFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, } } } else { - NS_ERROR("Unexpected extra child frame in nsVideoFrame; skipping"); + // We expect a placeholder for ::backdrop if we're fullscreen. + MOZ_ASSERT(child->IsPlaceholderFrame()); } } diff --git a/layout/mathml/nsMathMLContainerFrame.h b/layout/mathml/nsMathMLContainerFrame.h @@ -388,8 +388,7 @@ class nsMathMLmathBlockFrame final : public nsBlockFrame { // mFrames void SetInitialChildList(ChildListID aListID, nsFrameList&& aChildList) override { - MOZ_ASSERT(aListID == mozilla::FrameChildListID::Principal || - aListID == mozilla::FrameChildListID::Backdrop, + MOZ_ASSERT(aListID == mozilla::FrameChildListID::Principal, "unexpected frame list"); nsBlockFrame::SetInitialChildList(aListID, std::move(aChildList)); if (aListID == mozilla::FrameChildListID::Principal) { diff --git a/layout/style/AnimationCommon.h b/layout/style/AnimationCommon.h @@ -138,6 +138,7 @@ class OwningElementRef final { enum SortingIndex : uint8_t { NotPseudo, + Backdrop, Marker, Before, After, @@ -153,6 +154,8 @@ class OwningElementRef final { switch (aPseudoRequest.mType) { case PseudoStyleType::NotPseudo: return SortingIndex::NotPseudo; + case PseudoStyleType::backdrop: + return SortingIndex::Backdrop; case PseudoStyleType::marker: return SortingIndex::Marker; case PseudoStyleType::before: diff --git a/layout/style/GeckoBindings.cpp b/layout/style/GeckoBindings.cpp @@ -138,6 +138,9 @@ void Gecko_GetAnonymousContentForElement(const Element* aElement, nsTArray<nsIContent*>* aArray) { MOZ_ASSERT(aElement->MayHaveAnonymousChildren()); if (aElement->HasProperties()) { + if (auto* backdrop = nsLayoutUtils::GetBackdropPseudo(aElement)) { + aArray->AppendElement(backdrop); + } if (auto* marker = nsLayoutUtils::GetMarkerPseudo(aElement)) { aArray->AppendElement(marker); } diff --git a/layout/style/PseudoStyleType.h b/layout/style/PseudoStyleType.h @@ -168,6 +168,9 @@ struct PseudoStyleRequest { static PseudoStyleRequest Marker() { return PseudoStyleRequest(PseudoStyleType::marker); } + static PseudoStyleRequest Backdrop() { + return PseudoStyleRequest(PseudoStyleType::backdrop); + } PseudoStyleType mType = PseudoStyleType::NotPseudo; RefPtr<nsAtom> mIdentifier; diff --git a/layout/style/RestyleManager.cpp b/layout/style/RestyleManager.cpp @@ -2026,64 +2026,48 @@ RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame( mRestyleManager->mAnimationsWithDestroyedFrame = this; } -void RestyleManager::AnimationsWithDestroyedFrame :: - StopAnimationsForElementsWithoutFrames() { - StopAnimationsWithoutFrame(mContents, PseudoStyleRequest::NotPseudo()); - StopAnimationsWithoutFrame(mBeforeContents, PseudoStyleRequest::Before()); - StopAnimationsWithoutFrame(mAfterContents, PseudoStyleRequest::After()); - StopAnimationsWithoutFrame(mMarkerContents, PseudoStyleRequest::Marker()); +void RestyleManager::AnimationsWithDestroyedFrame::Put( + nsIContent* aContent, ComputedStyle* aComputedStyle) { + MOZ_ASSERT(aContent); + PseudoStyleType pseudoType = aComputedStyle->GetPseudoType(); + nsIContent* target = aContent; + if (pseudoType == PseudoStyleType::NotPseudo || + !AnimationUtils::StoresAnimationsInParent(pseudoType)) { + pseudoType = PseudoStyleType::NotPseudo; + } else { + target = aContent->GetParent(); + } + mContents.AppendElement(std::make_pair(target->AsElement(), pseudoType)); } -void RestyleManager::AnimationsWithDestroyedFrame ::StopAnimationsWithoutFrame( - nsTArray<RefPtr<Element>>& aArray, - const PseudoStyleRequest& aPseudoRequest) { +void RestyleManager::AnimationsWithDestroyedFrame:: + StopAnimationsForElementsWithoutFrames() { nsPresContext* context = mRestyleManager->PresContext(); nsAnimationManager* animationManager = context->AnimationManager(); nsTransitionManager* transitionManager = context->TransitionManager(); const Document* doc = context->Document(); - for (Element* element : aArray) { - PseudoStyleRequest request = aPseudoRequest; - - switch (aPseudoRequest.mType) { - case PseudoStyleType::NotPseudo: { - if (element->GetPrimaryFrame()) { - continue; - } - - // The contents of view transition pseudos are put together with - // NotPseudo. - const auto type = element->GetPseudoElementType(); - if (PseudoStyle::IsViewTransitionPseudoElement(type)) { - request = { - type, - element->HasName() - ? element->GetParsedAttr(nsGkAtoms::name)->GetAtomValue() - : nullptr}; - // View transition pseudo-elements use the document element to look up - // their animations. - element = doc->GetRootElement(); - MOZ_ASSERT(element); - } - break; + for (auto& [element, pseudoType] : mContents) { + PseudoStyleRequest request(pseudoType); + if (pseudoType == PseudoStyleType::NotPseudo) { + if (element->GetPrimaryFrame()) { + continue; } - case PseudoStyleType::before: - if (nsLayoutUtils::GetBeforeFrame(element)) { - continue; - } - break; - case PseudoStyleType::after: - if (nsLayoutUtils::GetAfterFrame(element)) { - continue; - } - break; - case PseudoStyleType::marker: - if (nsLayoutUtils::GetMarkerFrame(element)) { - continue; - } - break; - default: - MOZ_ASSERT_UNREACHABLE("Unexpected PseudoStyleType"); - break; + // The contents of view transition pseudos are put together with + // NotPseudo. + const auto type = element->GetPseudoElementType(); + if (PseudoStyle::IsViewTransitionPseudoElement(type)) { + request = {type, + element->HasName() + ? element->GetParsedAttr(nsGkAtoms::name)->GetAtomValue() + : nullptr}; + // View transition pseudo-elements use the document element to look up + // their animations. + element = doc->GetRootElement(); + MOZ_ASSERT(element); + } + } else if (auto* pseudo = element->GetPseudoElement(request); + pseudo && pseudo->GetPrimaryFrame()) { + continue; } animationManager->StopAnimationsForElement(element, request); @@ -2604,47 +2588,6 @@ struct RestyleManager::TextPostTraversalState { nsChangeHint mComputedHint; }; -static void UpdateBackdropIfNeeded(nsIFrame* aFrame, ServoStyleSet& aStyleSet, - nsStyleChangeList& aChangeList) { - const nsStyleDisplay* display = aFrame->Style()->StyleDisplay(); - if (display->mTopLayer != StyleTopLayer::Auto) { - return; - } - - // Elements in the top layer are guaranteed to have absolute or fixed - // position per https://fullscreen.spec.whatwg.org/#new-stacking-layer. - MOZ_ASSERT(display->IsAbsolutelyPositionedStyle()); - - nsIFrame* backdropPlaceholder = - aFrame->GetChildList(FrameChildListID::Backdrop).FirstChild(); - if (!backdropPlaceholder) { - return; - } - - MOZ_ASSERT(backdropPlaceholder->IsPlaceholderFrame()); - nsIFrame* backdropFrame = - nsPlaceholderFrame::GetRealFrameForPlaceholder(backdropPlaceholder); - MOZ_ASSERT(backdropFrame->IsBackdropFrame()); - MOZ_ASSERT(backdropFrame->Style()->GetPseudoType() == - PseudoStyleType::backdrop); - - RefPtr<ComputedStyle> newStyle = aStyleSet.ResolvePseudoElementStyle( - *aFrame->GetContent()->AsElement(), PseudoStyleType::backdrop, nullptr, - aFrame->Style()); - - // NOTE(emilio): We can't use the changes handled for the owner of the - // backdrop frame, since it's out of flow, and parented to the viewport or - // canvas frame (depending on the `position` value). - MOZ_ASSERT(backdropFrame->GetParent()->IsViewportFrame() || - backdropFrame->GetParent()->IsCanvasFrame()); - nsTArray<nsIFrame*> wrappersToRestyle; - nsTArray<RefPtr<Element>> anchorsToSuppress; - ServoRestyleState state(aStyleSet, aChangeList, wrappersToRestyle, - anchorsToSuppress); - nsIFrame::UpdateStyleOfOwnedChildFrame(backdropFrame, newStyle, state); - MOZ_ASSERT(anchorsToSuppress.IsEmpty()); -} - static void UpdateFirstLetterIfNeeded(nsIFrame* aFrame, ServoRestyleState& aRestyleState) { MOZ_ASSERT( @@ -2720,9 +2663,6 @@ static void UpdateFramePseudoElementStyles(nsIFrame* aFrame, } else { UpdateFirstLetterIfNeeded(aFrame, aRestyleState); } - - UpdateBackdropIfNeeded(aFrame, aRestyleState.StyleSet(), - aRestyleState.ChangeList()); } enum class ServoPostTraversalFlags : uint32_t { @@ -2827,6 +2767,32 @@ static ServoPostTraversalFlags SendA11yNotifications( return Flags::Empty; } +static bool NeedsToReframeForConditionallyCreatedPseudoElement( + Element* aElement, ComputedStyle* aNewStyle, nsIFrame* aStyleFrame, + ServoRestyleState& aRestyleState) { + const auto& disp = *aStyleFrame->StyleDisplay(); + if (disp.IsListItem() && aStyleFrame->IsBlockFrameOrSubclass() && + !nsLayoutUtils::GetMarkerPseudo(aElement)) { + RefPtr<ComputedStyle> pseudoStyle = + aRestyleState.StyleSet().ProbePseudoElementStyle( + *aElement, PseudoStyleType::marker, nullptr, aNewStyle); + if (pseudoStyle) { + return true; + } + } + if (disp.mTopLayer == StyleTopLayer::Auto && + !aElement->IsInNativeAnonymousSubtree() && + !nsLayoutUtils::GetBackdropPseudo(aElement)) { + RefPtr<ComputedStyle> pseudoStyle = + aRestyleState.StyleSet().ProbePseudoElementStyle( + *aElement, PseudoStyleType::backdrop, nullptr, aNewStyle); + if (pseudoStyle) { + return true; + } + } + return false; +} + bool RestyleManager::ProcessPostTraversal(Element* aElement, ServoRestyleState& aRestyleState, ServoPostTraversalFlags aFlags) { @@ -2890,19 +2856,13 @@ bool RestyleManager::ProcessPostTraversal(Element* aElement, ServoRestyleState::TableAwareParentFor(maybeAnonBoxChild)); } - // If we don't have a ::marker pseudo-element, but need it, then - // reconstruct the frame. (The opposite situation implies 'display' + // If we don't have a ::marker or ::backdrop pseudo-element, but need it, + // then reconstruct the frame. (The opposite situation implies 'display' // changes so doesn't need to be handled explicitly here.) - if (wasRestyled && styleFrame->StyleDisplay()->IsListItem() && - styleFrame->IsBlockFrameOrSubclass() && - !nsLayoutUtils::GetMarkerPseudo(aElement)) { - RefPtr<ComputedStyle> pseudoStyle = - aRestyleState.StyleSet().ProbePseudoElementStyle( - *aElement, PseudoStyleType::marker, nullptr, - upToDateStyleIfRestyled); - if (pseudoStyle) { - changeHint |= nsChangeHint_ReconstructFrame; - } + if (wasRestyled && !(changeHint & nsChangeHint_ReconstructFrame) && + NeedsToReframeForConditionallyCreatedPseudoElement( + aElement, upToDateStyleIfRestyled, styleFrame, aRestyleState)) { + changeHint |= nsChangeHint_ReconstructFrame; } } @@ -3798,12 +3758,6 @@ static bool IsFrameAboutToGoAway(nsIFrame* aFrame) { void RestyleManager::DoReparentComputedStyleForFirstLine( nsIFrame* aFrame, ServoStyleSet& aStyleSet) { - if (aFrame->IsBackdropFrame()) { - // Style context of backdrop frame has no parent style, and thus we do not - // need to reparent it. - return; - } - if (IsFrameAboutToGoAway(aFrame)) { // We're entering a display: none subtree, which we know it's going to get // rebuilt. Don't bother reparenting. diff --git a/layout/style/RestyleManager.h b/layout/style/RestyleManager.h @@ -270,27 +270,7 @@ class RestyleManager { // This method takes the content node for the generated content for // animation/transition on ::before and ::after, rather than the // content node for the real element. - void Put(nsIContent* aContent, ComputedStyle* aComputedStyle) { - MOZ_ASSERT(aContent); - PseudoStyleType pseudoType = aComputedStyle->GetPseudoType(); - if (pseudoType == PseudoStyleType::NotPseudo || - PseudoStyle::IsViewTransitionPseudoElement(pseudoType)) { - mContents.AppendElement(aContent->AsElement()); - } else if (pseudoType == PseudoStyleType::before) { - MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == - nsGkAtoms::mozgeneratedcontentbefore); - mBeforeContents.AppendElement(aContent->GetParent()->AsElement()); - } else if (pseudoType == PseudoStyleType::after) { - MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == - nsGkAtoms::mozgeneratedcontentafter); - mAfterContents.AppendElement(aContent->GetParent()->AsElement()); - } else if (pseudoType == PseudoStyleType::marker) { - MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == - nsGkAtoms::mozgeneratedcontentmarker); - mMarkerContents.AppendElement(aContent->GetParent()->AsElement()); - } - } - + void Put(nsIContent* aContent, ComputedStyle* aComputedStyle); void StopAnimationsForElementsWithoutFrames(); private: @@ -303,13 +283,10 @@ class RestyleManager { // Below four arrays might include elements that have already had their // animations or transitions stopped. // - // mBeforeContents, mAfterContents and mMarkerContents hold the real element - // rather than the content node for the generated content (which might + // mContents holds either the real element and NotPseudo, or the parent + // element rather than the content node for generated content (which might // change during a reframe). - nsTArray<RefPtr<Element>> mContents; - nsTArray<RefPtr<Element>> mBeforeContents; - nsTArray<RefPtr<Element>> mAfterContents; - nsTArray<RefPtr<Element>> mMarkerContents; + nsTArray<std::pair<RefPtr<Element>, PseudoStyleType>> mContents; }; /** diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp @@ -770,12 +770,7 @@ bool ServoStyleSet::GeneratedContentPseudoExists( content.IsNormal()) { return false; } - // display:none is equivalent to not having a pseudo at all. - if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) { - return false; - } } - // For ::before and ::after pseudo-elements, no 'content' items is // equivalent to not having the pseudo-element at all. if (type == PseudoStyleType::before || type == PseudoStyleType::after) { @@ -784,12 +779,14 @@ bool ServoStyleSet::GeneratedContentPseudoExists( } MOZ_ASSERT(!aPseudoStyle.StyleContent()->NonAltContentItems().IsEmpty(), "IsItems() implies we have at least one item"); + } + if (type == PseudoStyleType::before || type == PseudoStyleType::after || + type == PseudoStyleType::marker || type == PseudoStyleType::backdrop) { // display:none is equivalent to not having a pseudo at all. if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) { return false; } } - return true; } @@ -1300,21 +1297,9 @@ already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleLazily( */ const Element* elementForStyleResolution = &aElement; PseudoStyleType pseudoTypeForStyleResolution = aPseudoRequest.mType; - if (aPseudoRequest.mType == PseudoStyleType::before) { - if (Element* pseudo = nsLayoutUtils::GetBeforePseudo(&aElement)) { - elementForStyleResolution = pseudo; - pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo; - } - } else if (aPseudoRequest.mType == PseudoStyleType::after) { - if (Element* pseudo = nsLayoutUtils::GetAfterPseudo(&aElement)) { - elementForStyleResolution = pseudo; - pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo; - } - } else if (aPseudoRequest.mType == PseudoStyleType::marker) { - if (Element* pseudo = nsLayoutUtils::GetMarkerPseudo(&aElement)) { - elementForStyleResolution = pseudo; - pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo; - } + if (auto* pseudo = aElement.GetPseudoElement(aPseudoRequest)) { + elementForStyleResolution = pseudo; + pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo; } nsPresContext* pc = GetPresContext(); diff --git a/layout/style/nsCSSPseudoElements.cpp b/layout/style/nsCSSPseudoElements.cpp @@ -80,6 +80,8 @@ nsString nsCSSPseudoElements::PseudoRequestAsString( return u"::before"_ns; case PseudoStyleType::after: return u"::after"_ns; + case PseudoStyleType::backdrop: + return u"::backdrop"_ns; case PseudoStyleType::marker: return u"::marker"_ns; case PseudoStyleType::viewTransition: diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp @@ -977,18 +977,7 @@ nsIFrame* nsComputedDOMStyle::GetOuterFrame() const { if (mPseudo.mType == PseudoStyleType::NotPseudo) { return mElement->GetPrimaryFrame(); } - nsAtom* property = nullptr; - if (mPseudo.mType == PseudoStyleType::before) { - property = nsGkAtoms::beforePseudoProperty; - } else if (mPseudo.mType == PseudoStyleType::after) { - property = nsGkAtoms::afterPseudoProperty; - } else if (mPseudo.mType == PseudoStyleType::marker) { - property = nsGkAtoms::markerPseudoProperty; - } - if (!property) { - return nullptr; - } - auto* pseudo = static_cast<Element*>(mElement->GetProperty(property)); + auto* pseudo = mElement->GetPseudoElement(mPseudo); return pseudo ? pseudo->GetPrimaryFrame() : nullptr; } diff --git a/servo/components/style/gecko/pseudo_element.rs b/servo/components/style/gecko/pseudo_element.rs @@ -272,7 +272,7 @@ impl PseudoElement { /// parent element. #[inline] pub fn animations_stored_in_parent(&self) -> bool { - matches!(*self, Self::Before | Self::After | Self::Marker) + matches!(*self, Self::Before | Self::After | Self::Marker | Self::Backdrop) } /// Whether this pseudo-element is the ::before pseudo. diff --git a/testing/web-platform/meta/css/css-anchor-position/popover-anchor-backdrop-transition.html.ini b/testing/web-platform/meta/css/css-anchor-position/popover-anchor-backdrop-transition.html.ini @@ -1,3 +0,0 @@ -[popover-anchor-backdrop-transition.html] - [Anchored popover ::backdrop transitioning opacity with @starting-style] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-animations/dialog-backdrop-animation.html.ini b/testing/web-platform/meta/css/css-animations/dialog-backdrop-animation.html.ini @@ -1,5 +0,0 @@ -[dialog-backdrop-animation.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] - [CSS Animations on a <dialog> ::backdrop are canceled and restarted as the dialog is hidden and shown] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-pseudo/backdrop-animate-002.html.ini b/testing/web-platform/meta/css/css-pseudo/backdrop-animate-002.html.ini @@ -1,5 +0,0 @@ -[backdrop-animate-002.html] - expected: - if (os == "mac") and not debug: [FAIL, PASS] - if (os == "android") and not debug: [FAIL, PASS] - FAIL diff --git a/testing/web-platform/meta/css/css-pseudo/backdrop-animate.html.ini b/testing/web-platform/meta/css/css-pseudo/backdrop-animate.html.ini @@ -1,3 +0,0 @@ -[backdrop-animate.html] - ['backgroundColor' animation] - expected: FAIL diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py @@ -59,6 +59,7 @@ STATIC_ATOMS = [ Atom("mozgeneratedcontentafter", "_moz_generated_content_after"), Atom("mozgeneratedcontentmarker", "_moz_generated_content_marker"), Atom("mozgeneratedcontentimage", "_moz_generated_content_image"), + Atom("mozgeneratedcontentbackdrop", "_moz_generated_content_backdrop"), Atom("mozquote", "_moz_quote"), Atom("mozsignature", "moz-signature"), # Used by MailNews. Atom("_moz_bullet_font", "-moz-bullet-font"), @@ -2219,6 +2220,7 @@ STATIC_ATOMS = [ Atom("pseudoProperty", "PseudoProperty"), # PseudoStyleType Atom("manualNACProperty", "ManualNACProperty"), # ManualNAC* Atom("markerPseudoProperty", "markerPseudoProperty"), # nsXMLElement* + Atom("backdropPseudoProperty", "backdropPseudoProperty"), # nsXMLElement* # Languages for lang-specific transforms Atom("Japanese", "ja"), Atom("Chinese", "zh-CN"),