Bug 1355351: Simplify nsLayoutUtils callers, and make child iterators notice display: contents pseudos. r=heycam
This also happens to fix other bugs, like making display: contents pseudos
animatable, which weren't before.
MozReview-Commit-ID: LhwTPNbFvSZ
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -514,34 +514,27 @@ EffectCompositor::GetServoAnimationRule(
/* static */ dom::Element*
EffectCompositor::GetElementToRestyle(dom::Element* aElement,
CSSPseudoElementType aPseudoType)
{
if (aPseudoType == CSSPseudoElementType::NotPseudo) {
return aElement;
}
- nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
- if (!primaryFrame) {
- return nullptr;
+ if (aPseudoType == CSSPseudoElementType::before) {
+ return nsLayoutUtils::GetBeforePseudo(aElement);
}
- nsIFrame* pseudoFrame;
- if (aPseudoType == CSSPseudoElementType::before) {
- pseudoFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame);
- } else if (aPseudoType == CSSPseudoElementType::after) {
- pseudoFrame = nsLayoutUtils::GetAfterFrame(primaryFrame);
- } else {
- NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
- "other that :before or :after");
- return nullptr;
+
+ if (aPseudoType == CSSPseudoElementType::after) {
+ return nsLayoutUtils::GetAfterPseudo(aElement);
}
- if (!pseudoFrame) {
- return nullptr;
- }
- return pseudoFrame->GetContent()->AsElement();
+
+ NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
+ "other that :before or :after");
+ return nullptr;
}
bool
EffectCompositor::HasPendingStyleUpdates() const
{
for (auto& elementSet : mElementsToRestyle) {
if (elementSet.Count()) {
return true;
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -1459,29 +1459,27 @@ KeyframeEffectReadOnly::CanThrottleTrans
nsIFrame*
KeyframeEffectReadOnly::GetAnimationFrame() const
{
if (!mTarget) {
return nullptr;
}
- nsIFrame* frame = mTarget->mElement->GetPrimaryFrame();
- if (!frame) {
- return nullptr;
- }
-
+ nsIFrame* frame;
if (mTarget->mPseudoType == CSSPseudoElementType::before) {
- frame = nsLayoutUtils::GetBeforeFrame(frame);
+ frame = nsLayoutUtils::GetBeforeFrame(mTarget->mElement);
} else if (mTarget->mPseudoType == CSSPseudoElementType::after) {
- frame = nsLayoutUtils::GetAfterFrame(frame);
+ frame = nsLayoutUtils::GetAfterFrame(mTarget->mElement);
} else {
+ frame = mTarget->mElement->GetPrimaryFrame();
MOZ_ASSERT(mTarget->mPseudoType == CSSPseudoElementType::NotPseudo,
"unknown mTarget->mPseudoType");
}
+
if (!frame) {
return nullptr;
}
return nsLayoutUtils::GetStyleFrame(frame);
}
nsIDocument*
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -312,57 +312,48 @@ ExplicitChildIterator::GetPreviousChild(
return mChild;
}
nsIContent*
AllChildrenIterator::Get() const
{
switch (mPhase) {
case eAtBeforeKid: {
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- MOZ_ASSERT(frame, "No frame at eAtBeforeKid phase");
- nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
- MOZ_ASSERT(beforeFrame, "No content before frame at eAtBeforeKid phase");
- return beforeFrame->GetContent();
+ Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
+ MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase");
+ return before;
}
case eAtExplicitKids:
return ExplicitChildIterator::Get();
case eAtAnonKids:
return mAnonKids[mAnonKidsIdx];
case eAtAfterKid: {
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- MOZ_ASSERT(frame, "No frame at eAtAfterKid phase");
- nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
- MOZ_ASSERT(afterFrame, "No content before frame at eAtBeforeKid phase");
- return afterFrame->GetContent();
+ Element* after = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
+ MOZ_ASSERT(after, "No content after frame at eAtAfterKid phase");
+ return after;
}
default:
return nullptr;
}
}
bool
AllChildrenIterator::Seek(nsIContent* aChildToFind)
{
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
mPhase = eAtExplicitKids;
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
- if (beforeFrame) {
- if (beforeFrame->GetContent() == aChildToFind) {
- mPhase = eAtBeforeKid;
- return true;
- }
- }
+ Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
+ if (beforePseudo && beforePseudo == aChildToFind) {
+ mPhase = eAtBeforeKid;
+ return true;
}
}
if (mPhase == eAtExplicitKids) {
if (ExplicitChildIterator::Seek(aChildToFind)) {
return true;
}
mPhase = eAtAnonKids;
@@ -399,23 +390,20 @@ AllChildrenIterator::AppendNativeAnonymo
}
}
nsIContent*
AllChildrenIterator::GetNextChild()
{
if (mPhase == eAtBegin) {
mPhase = eAtExplicitKids;
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
- if (beforeFrame) {
- mPhase = eAtBeforeKid;
- return beforeFrame->GetContent();
- }
+ Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
+ if (beforeContent) {
+ mPhase = eAtBeforeKid;
+ return beforeContent;
}
}
if (mPhase == eAtBeforeKid) {
// Advance into our explicit kids.
mPhase = eAtExplicitKids;
}
@@ -441,43 +429,37 @@ AllChildrenIterator::GetNextChild()
mAnonKidsIdx++;
}
}
if (mAnonKidsIdx < mAnonKids.Length()) {
return mAnonKids[mAnonKidsIdx];
}
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
- if (afterFrame) {
- mPhase = eAtAfterKid;
- return afterFrame->GetContent();
- }
+ Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
+ if (afterContent) {
+ mPhase = eAtAfterKid;
+ return afterContent;
}
}
mPhase = eAtEnd;
return nullptr;
}
nsIContent*
AllChildrenIterator::GetPreviousChild()
{
if (mPhase == eAtEnd) {
MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length());
mPhase = eAtAnonKids;
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
- if (afterFrame) {
- mPhase = eAtAfterKid;
- return afterFrame->GetContent();
- }
+ Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
+ if (afterContent) {
+ mPhase = eAtAfterKid;
+ return afterContent;
}
}
if (mPhase == eAtAfterKid) {
mPhase = eAtAnonKids;
}
if (mPhase == eAtAnonKids) {
@@ -496,23 +478,20 @@ AllChildrenIterator::GetPreviousChild()
}
if (mPhase == eAtExplicitKids) {
nsIContent* kid = ExplicitChildIterator::GetPreviousChild();
if (kid) {
return kid;
}
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
- if (beforeFrame) {
- mPhase = eAtBeforeKid;
- return beforeFrame->GetContent();
- }
+ Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
+ if (beforeContent) {
+ mPhase = eAtBeforeKid;
+ return beforeContent;
}
}
mPhase = eAtBegin;
return nullptr;
}
static bool
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3751,21 +3751,21 @@ nsDOMWindowUtils::GetOMTAStyle(nsIDOMEle
{
nsCOMPtr<Element> element = do_QueryInterface(aElement);
if (!element) {
return NS_ERROR_INVALID_ARG;
}
RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
nsIFrame* frame = element->GetPrimaryFrame();
- if (frame && !aPseudoElement.IsEmpty()) {
+ if (!aPseudoElement.IsEmpty()) {
if (aPseudoElement.EqualsLiteral("::before")) {
- frame = nsLayoutUtils::GetBeforeFrame(frame);
+ frame = nsLayoutUtils::GetBeforeFrame(element);
} else if (aPseudoElement.EqualsLiteral("::after")) {
- frame = nsLayoutUtils::GetAfterFrame(frame);
+ frame = nsLayoutUtils::GetAfterFrame(element);
} else {
return NS_ERROR_INVALID_ARG;
}
}
if (frame && nsLayoutUtils::AreAsyncAnimationsEnabled()) {
if (aProperty.EqualsLiteral("opacity")) {
Layer* layer =
FrameLayerBuilder::GetDedicatedLayer(frame,
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -3324,24 +3324,24 @@ ElementRestyler::MustReframeForPseudo(CS
return false;
}
}
if (aPseudoType == CSSPseudoElementType::before) {
// Check for a ::before pseudo style and the absence of a ::before content,
// but only if aFrame is null or is the first continuation/ib-split.
if ((aFrame && !nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aFrame)) ||
- nsLayoutUtils::GetBeforeFrameForContent(aGenConParentFrame, aContent)) {
+ nsLayoutUtils::GetBeforeFrame(aContent)) {
return false;
}
} else {
// Similarly for ::after, but check for being the last continuation/
// ib-split.
if ((aFrame && nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame)) ||
- nsLayoutUtils::GetAfterFrameForContent(aGenConParentFrame, aContent)) {
+ nsLayoutUtils::GetAfterFrame(aContent)) {
return false;
}
}
// Checking for a ::before frame (which we do above) is cheaper than getting
// the ::before style context here.
return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext, aPseudoType,
mPresContext);
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -330,35 +330,26 @@ ServoRestyleManager::ProcessPostTraversa
}
}
/* static */ nsIFrame*
ServoRestyleManager::FrameForPseudoElement(const nsIContent* aContent,
nsIAtom* aPseudoTagOrNull)
{
MOZ_ASSERT_IF(aPseudoTagOrNull, aContent->IsElement());
- nsIFrame* primaryFrame = aContent->GetPrimaryFrame();
-
if (!aPseudoTagOrNull) {
- return primaryFrame;
+ return aContent->GetPrimaryFrame();
}
- // FIXME(emilio): Need to take into account display: contents pseudos!
- if (!primaryFrame) {
- return nullptr;
- }
-
- // NOTE: we probably need to special-case display: contents here. Gecko's
- // RestyleManager passes the primary frame of the parent instead.
if (aPseudoTagOrNull == nsCSSPseudoElements::before) {
- return nsLayoutUtils::GetBeforeFrameForContent(primaryFrame, aContent);
+ return nsLayoutUtils::GetBeforeFrame(aContent);
}
if (aPseudoTagOrNull == nsCSSPseudoElements::after) {
- return nsLayoutUtils::GetAfterFrameForContent(primaryFrame, aContent);
+ return nsLayoutUtils::GetAfterFrame(aContent);
}
MOZ_CRASH("Unkown pseudo-element given to "
"ServoRestyleManager::FrameForPseudoElement");
return nullptr;
}
void
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -6733,32 +6733,30 @@ nsCSSFrameConstructor::FindFrameForConte
nsIContent* aTargetContent,
StyleDisplay& aTargetContentDisplay,
nsContainerFrame* aParentFrame,
bool aPrevSibling)
{
nsIFrame* sibling = aContent->GetPrimaryFrame();
if (!sibling && GetDisplayContentsStyleFor(aContent)) {
// A display:contents node - check if it has a ::before / ::after frame...
- sibling = aPrevSibling ?
- nsLayoutUtils::GetAfterFrameForContent(aParentFrame, aContent) :
- nsLayoutUtils::GetBeforeFrameForContent(aParentFrame, aContent);
+ sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent)
+ : nsLayoutUtils::GetBeforeFrame(aContent);
if (!sibling) {
// ... then recurse into children ...
const bool forward = !aPrevSibling;
FlattenedChildIterator iter(aContent, forward);
sibling = aPrevSibling ?
FindPreviousSibling(iter, aTargetContent, aTargetContentDisplay, aParentFrame) :
FindNextSibling(iter, aTargetContent, aTargetContentDisplay, aParentFrame);
}
if (!sibling) {
// ... then ::after / ::before on the opposite end.
- sibling = aPrevSibling ?
- nsLayoutUtils::GetBeforeFrameForContent(aParentFrame, aContent) :
- nsLayoutUtils::GetAfterFrameForContent(aParentFrame, aContent);
+ sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent)
+ : nsLayoutUtils::GetBeforeFrame(aContent);
}
if (!sibling) {
return nullptr;
}
} else if (!sibling || sibling->GetContent() != aContent) {
// XXX the GetContent() != aContent check is needed due to bug 135040.
// Remove it once that's fixed.
return nullptr;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1580,46 +1580,50 @@ nsLayoutUtils::GetChildListNameFor(nsIFr
// else it's positioned and should have been on the 'id' child list.
NS_POSTCONDITION(found, "not in child list");
}
#endif
return id;
}
-/*static*/ nsIFrame*
-nsLayoutUtils::GetBeforeFrameForContent(nsIFrame* aFrame,
- const nsIContent* aContent)
-{
- auto* pseudo =
- static_cast<Element*>(aContent->GetProperty(nsGkAtoms::beforePseudoProperty));
- return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
+static Element*
+GetPseudo(const nsIContent* aContent, nsIAtom* aPseudoProperty)
+{
+ MOZ_ASSERT(aPseudoProperty == nsGkAtoms::beforePseudoProperty ||
+ aPseudoProperty == nsGkAtoms::afterPseudoProperty);
+ return static_cast<Element*>(aContent->GetProperty(aPseudoProperty));
+}
+
+/*static*/ Element*
+nsLayoutUtils::GetBeforePseudo(const nsIContent* aContent)
+{
+ return GetPseudo(aContent, nsGkAtoms::beforePseudoProperty);
}
/*static*/ nsIFrame*
-nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame)
-{
- return GetBeforeFrameForContent(aFrame, aFrame->GetContent());
+nsLayoutUtils::GetBeforeFrame(const nsIContent* aContent)
+{
+ Element* pseudo = GetBeforePseudo(aContent);
+ return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
+}
+
+/*static*/ Element*
+nsLayoutUtils::GetAfterPseudo(const nsIContent* aContent)
+{
+ return GetPseudo(aContent, nsGkAtoms::afterPseudoProperty);
}
/*static*/ nsIFrame*
-nsLayoutUtils::GetAfterFrameForContent(nsIFrame* aFrame,
- const nsIContent* aContent)
-{
- auto* pseudo =
- static_cast<Element*>(aContent->GetProperty(nsGkAtoms::afterPseudoProperty));
+nsLayoutUtils::GetAfterFrame(const nsIContent* aContent)
+{
+ Element* pseudo = GetAfterPseudo(aContent);
return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
}
-/*static*/ nsIFrame*
-nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame)
-{
- return GetAfterFrameForContent(aFrame, aFrame->GetContent());
-}
-
// static
nsIFrame*
nsLayoutUtils::GetClosestFrameOfType(nsIFrame* aFrame,
nsIAtom* aFrameType,
nsIFrame* aStopAt)
{
for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
if (frame->GetType() == aFrameType) {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -281,60 +281,36 @@ public:
/**
* Use heuristics to figure out the child list that
* aChildFrame is currently in.
*/
static mozilla::layout::FrameChildListID GetChildListNameFor(nsIFrame* aChildFrame);
/**
- * GetBeforeFrameForContent returns the ::before frame for aContent, if
- * one exists. This is typically O(1). The frame passed in must be
- * the first-in-flow.
- *
- * @param aGenConParentFrame an ancestor of the ::before frame
- * @param aContent the content whose ::before is wanted
- * @return the ::before frame or nullptr if there isn't one
+ * Returns the ::before pseudo-element for aContent, if any.
*/
- static nsIFrame* GetBeforeFrameForContent(nsIFrame* aGenConParentFrame,
- const nsIContent* aContent);
-
- /**
- * GetBeforeFrame returns the outermost ::before frame of the given frame, if
- * one exists. This is typically O(1). The frame passed in must be
- * the first-in-flow.
- *
- * @param aFrame the frame whose ::before is wanted
- * @return the :before frame or nullptr if there isn't one
- */
- static nsIFrame* GetBeforeFrame(nsIFrame* aFrame);
+ static mozilla::dom::Element* GetBeforePseudo(const nsIContent* aContent);
/**
- * GetAfterFrameForContent returns the ::after frame for aContent, if one
- * exists. This will walk the in-flow chain of aGenConParentFrame to the
- * last-in-flow if needed. This function is typically O(N) in the number
- * of child frames, following in-flows, etc.
- *
- * @param aGenConParentFrame an ancestor of the ::after frame
- * @param aContent the content whose ::after is wanted
- * @return the ::after frame or nullptr if there isn't one
+ * Returns the frame corresponding to the ::before pseudo-element for
+ * aContent, if any.
*/
- static nsIFrame* GetAfterFrameForContent(nsIFrame* aGenConParentFrame,
- const nsIContent* aContent);
+ static nsIFrame* GetBeforeFrame(const nsIContent* aContent);
/**
- * GetAfterFrame returns the outermost ::after frame of the given frame, if one
- * exists. This will walk the in-flow chain to the last-in-flow if
- * needed. This function is typically O(N) in the number of child
- * frames, following in-flows, etc.
- *
- * @param aFrame the frame whose ::after is wanted
- * @return the :after frame or nullptr if there isn't one
+ * Returns the ::after pseudo-element for aContent, if any.
*/
- static nsIFrame* GetAfterFrame(nsIFrame* aFrame);
+ static mozilla::dom::Element* GetAfterPseudo(const nsIContent* aContent);
+
+ /**
+ * Returns the frame corresponding to the ::after pseudo-element for aContent,
+ * if any.
+ */
+ static nsIFrame* GetAfterFrame(const nsIContent* aContent);
/**
* Given a frame, search up the frame tree until we find an
* ancestor that (or the frame itself) is of type aFrameType, if any.
*
* @param aFrame the frame to start at
* @param aFrameType the frame type to look for
* @param aStopAt a frame to stop at after we checked it
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -10360,29 +10360,26 @@ nsIFrame::IsPseudoStackingContextFromSty
return disp->IsAbsPosContainingBlock(this) ||
disp->IsFloating(this) ||
(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT);
}
Element*
nsIFrame::GetPseudoElement(CSSPseudoElementType aType)
{
- nsIFrame* frame = nullptr;
+ if (!mContent) {
+ return nullptr;
+ }
if (aType == CSSPseudoElementType::before) {
- frame = nsLayoutUtils::GetBeforeFrame(this);
- } else if (aType == CSSPseudoElementType::after) {
- frame = nsLayoutUtils::GetAfterFrame(this);
- }
-
- if (frame) {
- nsIContent* content = frame->GetContent();
- if (content->IsElement()) {
- return content->AsElement();
- }
+ return nsLayoutUtils::GetBeforePseudo(mContent);
+ }
+
+ if (aType == CSSPseudoElementType::after) {
+ return nsLayoutUtils::GetAfterPseudo(mContent);
}
return nullptr;
}
static bool
IsFrameScrolledOutOfView(nsIFrame *aFrame)
{