Bug 1413619 - Fix insertion point computation when display: contents pseudos are involved.

Tag #1375
This commit is contained in:
Matt A. Tobin 2020-04-17 07:20:06 -04:00 • committed by Roy Tam
commit 5b1452e120
10 changed files with 192 additions and 243 deletions

View file

@ -192,17 +192,17 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
} }
bool bool
ExplicitChildIterator::Seek(nsIContent* aChildToFind) ExplicitChildIterator::Seek(const nsIContent* aChildToFind)
{ {
if (aChildToFind->GetParent() == mParent && if (aChildToFind->GetParent() == mParent &&
!aChildToFind->IsRootOfAnonymousSubtree()) { !aChildToFind->IsRootOfAnonymousSubtree()) {
// Fast path: just point ourselves to aChildToFind, which is a // Fast path: just point ourselves to aChildToFind, which is a
// normal DOM child of ours. // normal DOM child of ours.
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind)); mChild = const_cast<nsIContent*>(aChildToFind);
mChild = aChildToFind;
mIndexInInserted = 0; mIndexInInserted = 0;
mDefaultChild = nullptr; mDefaultChild = nullptr;
mIsFirst = false; mIsFirst = false;
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(mChild));
return true; return true;
} }
@ -348,7 +348,7 @@ AllChildrenIterator::Get() const
bool bool
AllChildrenIterator::Seek(nsIContent* aChildToFind) AllChildrenIterator::Seek(const nsIContent* aChildToFind)
{ {
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) { if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
mPhase = eAtExplicitKids; mPhase = eAtExplicitKids;

View file

@ -58,13 +58,13 @@ public:
// found. This version can take shortcuts that the two-argument version // found. This version can take shortcuts that the two-argument version
// can't, so can be faster (and in fact can be O(1) instead of O(N) in many // can't, so can be faster (and in fact can be O(1) instead of O(N) in many
// cases). // cases).
bool Seek(nsIContent* aChildToFind); bool Seek(const nsIContent* aChildToFind);
// Looks for aChildToFind respecting insertion points until aChildToFind is found. // Looks for aChildToFind respecting insertion points until aChildToFind is found.
// or aBound is found. If aBound is nullptr then the seek is unbounded. Returns // or aBound is found. If aBound is nullptr then the seek is unbounded. Returns
// whether aChildToFind was found as an explicit child prior to encountering // whether aChildToFind was found as an explicit child prior to encountering
// aBound. // aBound.
bool Seek(nsIContent* aChildToFind, nsIContent* aBound) bool Seek(const nsIContent* aChildToFind, nsIContent* aBound)
{ {
// It would be nice to assert that we find aChildToFind, but bz thinks that // It would be nice to assert that we find aChildToFind, but bz thinks that
// we might not find aChildToFind when called from ContentInserted // we might not find aChildToFind when called from ContentInserted
@ -131,19 +131,29 @@ class FlattenedChildIterator : public ExplicitChildIterator
public: public:
explicit FlattenedChildIterator(const nsIContent* aParent, explicit FlattenedChildIterator(const nsIContent* aParent,
bool aStartAtBeginning = true) bool aStartAtBeginning = true)
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false) : ExplicitChildIterator(aParent, aStartAtBeginning)
, mXBLInvolved(false)
, mOriginalContent(aParent)
{ {
Init(false); Init(false);
} }
FlattenedChildIterator(FlattenedChildIterator&& aOther) FlattenedChildIterator(FlattenedChildIterator&& aOther)
: ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {} : ExplicitChildIterator(Move(aOther))
, mXBLInvolved(aOther.mXBLInvolved)
, mOriginalContent(aOther.mOriginalContent)
{}
FlattenedChildIterator(const FlattenedChildIterator& aOther) FlattenedChildIterator(const FlattenedChildIterator& aOther)
: ExplicitChildIterator(aOther), mXBLInvolved(aOther.mXBLInvolved) {} : ExplicitChildIterator(aOther)
, mXBLInvolved(aOther.mXBLInvolved)
, mOriginalContent(aOther.mOriginalContent)
{}
bool XBLInvolved() { return mXBLInvolved; } bool XBLInvolved() { return mXBLInvolved; }
const nsIContent* Parent() const { return mOriginalContent; }
protected: protected:
/** /**
* This constructor is a hack to help AllChildrenIterator which sometimes * This constructor is a hack to help AllChildrenIterator which sometimes
@ -151,7 +161,9 @@ protected:
*/ */
FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags, FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
bool aStartAtBeginning = true) bool aStartAtBeginning = true)
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false) : ExplicitChildIterator(aParent, aStartAtBeginning)
, mXBLInvolved(false)
, mOriginalContent(aParent)
{ {
bool ignoreXBL = aFlags & nsIContent::eAllButXBL; bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
Init(ignoreXBL); Init(ignoreXBL);
@ -162,6 +174,8 @@ protected:
// For certain optimizations, nsCSSFrameConstructor needs to know if the // For certain optimizations, nsCSSFrameConstructor needs to know if the
// child list of the element that we're iterating matches its .childNodes. // child list of the element that we're iterating matches its .childNodes.
bool mXBLInvolved; bool mXBLInvolved;
const nsIContent* mOriginalContent;
}; };
/** /**
@ -179,12 +193,11 @@ public:
AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags, AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
bool aStartAtBeginning = true) : bool aStartAtBeginning = true) :
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning), FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { } mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
AllChildrenIterator(AllChildrenIterator&& aOther) AllChildrenIterator(AllChildrenIterator&& aOther)
: FlattenedChildIterator(Move(aOther)), : FlattenedChildIterator(Move(aOther)),
mOriginalContent(aOther.mOriginalContent),
mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx), mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
mFlags(aOther.mFlags), mPhase(aOther.mPhase) mFlags(aOther.mFlags), mPhase(aOther.mPhase)
#ifdef DEBUG #ifdef DEBUG
@ -203,11 +216,10 @@ public:
// Seeks the given node in children of a parent element, starting from // Seeks the given node in children of a parent element, starting from
// the current iterator's position, and sets the iterator at the given child // the current iterator's position, and sets the iterator at the given child
// node if it was found. // node if it was found.
bool Seek(nsIContent* aChildToFind); bool Seek(const nsIContent* aChildToFind);
nsIContent* GetNextChild(); nsIContent* GetNextChild();
nsIContent* GetPreviousChild(); nsIContent* GetPreviousChild();
const nsIContent* Parent() const { return mOriginalContent; }
enum IteratorPhase enum IteratorPhase
{ {
@ -225,8 +237,6 @@ private:
void AppendNativeAnonymousChildren(); void AppendNativeAnonymousChildren();
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame); void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
const nsIContent* mOriginalContent;
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index // mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
// in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is // in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
// eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If // eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If

View file

@ -6662,115 +6662,147 @@ nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
return true; return true;
} }
// FIXME(emilio): If we ever kill IsValidSibling() we can simplify this quite a
// bit (no need to pass aTargetContent or aTargetContentDisplay, and the
// adjust() calls can be responsibility of the caller).
template<nsCSSFrameConstructor::SiblingDirection aDirection>
nsIFrame* nsIFrame*
nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent, nsCSSFrameConstructor::FindSiblingInternal(
nsIContent* aTargetContent, FlattenedChildIterator aIter,
StyleDisplay& aTargetContentDisplay, nsIContent* aTargetContent,
nsContainerFrame* aParentFrame, StyleDisplay& aTargetContentDisplay)
bool aPrevSibling)
{ {
nsIFrame* sibling = aContent->GetPrimaryFrame(); auto adjust = [&](nsIFrame* aPotentialSiblingFrame) -> nsIFrame* {
if (!sibling && GetDisplayContentsStyleFor(aContent)) { return AdjustSiblingFrame(
// A display:contents node - check if it has a ::before / ::after frame... aPotentialSiblingFrame, aTargetContent, aTargetContentDisplay,
sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent) aDirection);
: 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);
// The recursion above has already done all the placeholder and auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
// continuation fixups. return aDirection == SiblingDirection::Forward
? aIter.GetNextChild() : aIter.GetPreviousChild();
};
auto getNearPseudo = [](const nsIContent* aContent) -> nsIFrame* {
return aDirection == SiblingDirection::Forward
? nsLayoutUtils::GetBeforeFrame(aContent)
: nsLayoutUtils::GetAfterFrame(aContent);
};
auto getFarPseudo = [](const nsIContent* aContent) -> nsIFrame* {
return aDirection == SiblingDirection::Forward
? nsLayoutUtils::GetAfterFrame(aContent)
: nsLayoutUtils::GetBeforeFrame(aContent);
};
while (nsIContent* sibling = nextDomSibling(aIter)) {
if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
// XXX the GetContent() == sibling check is needed due to bug 135040.
// Remove it once that's fixed.
if (primaryFrame->GetContent() == sibling) {
if (nsIFrame* frame = adjust(primaryFrame)) {
return frame;
}
}
}
if (GetDisplayContentsStyleFor(sibling)) {
if (nsIFrame* frame = adjust(getNearPseudo(sibling))) {
return frame;
}
const bool startFromBeginning = aDirection == SiblingDirection::Forward;
FlattenedChildIterator iter(sibling, startFromBeginning);
nsIFrame* sibling = FindSiblingInternal<aDirection>(
iter, aTargetContent, aTargetContentDisplay);
if (sibling) { if (sibling) {
return sibling; return sibling;
} }
} }
if (!sibling) { }
// ... then ::after / ::before on the opposite end.
sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent) return adjust(getFarPseudo(aIter.Parent()));
: nsLayoutUtils::GetBeforeFrame(aContent); }
}
if (!sibling) { nsIFrame*
return nullptr; nsCSSFrameConstructor::AdjustSiblingFrame(
} nsIFrame* aSibling,
} else if (!sibling || sibling->GetContent() != aContent) { nsIContent* aTargetContent,
// XXX the GetContent() != aContent check is needed due to bug 135040. mozilla::StyleDisplay& aTargetContentDisplay,
// Remove it once that's fixed. SiblingDirection aDirection)
{
if (!aSibling) {
return nullptr; return nullptr;
} }
// If the frame is out-of-flow, GetPrimaryFrame() will have returned the if (aSibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
// out-of-flow frame; we want the placeholder. aSibling = aSibling->GetPlaceholderFrame();
if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { MOZ_ASSERT(aSibling);
nsIFrame* placeholderFrame = sibling->GetPlaceholderFrame();
NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame");
sibling = placeholderFrame;
} }
// The frame we have now should never be a continuation. MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?");
NS_ASSERTION(!sibling->GetPrevContinuation(), "How did that happen?"); if (aDirection == SiblingDirection::Backward) {
// The frame may be a ib-split frame (a split inline frame that contains a
if (aPrevSibling) { // block). Get the last part of that split.
// The frame may be a ib-split frame (a split inline frame that if (IsFramePartOfIBSplit(aSibling)) {
// contains a block). Get the last part of that split. aSibling = GetLastIBSplitSibling(aSibling, true);
if (IsFramePartOfIBSplit(sibling)) {
sibling = GetLastIBSplitSibling(sibling, true);
} }
// The frame may have a continuation. If so, we want the last // The frame may have a continuation. If so, we want the last
// non-overflow-container continuation as our previous sibling. // non-overflow-container continuation as our previous sibling.
sibling = sibling->GetTailContinuation(); aSibling = aSibling->GetTailContinuation();
} }
if (aTargetContent && if (!IsValidSibling(aSibling, aTargetContent, aTargetContentDisplay)) {
!IsValidSibling(sibling, aTargetContent, aTargetContentDisplay)) { return nullptr;
sibling = nullptr;
} }
return sibling; return aSibling;
} }
nsIFrame* nsIFrame*
nsCSSFrameConstructor::FindPreviousSibling(FlattenedChildIterator aIter, nsCSSFrameConstructor::FindPreviousSibling(const FlattenedChildIterator& aIter,
nsIContent* aTargetContent, StyleDisplay& aTargetContentDisplay)
StyleDisplay& aTargetContentDisplay,
nsContainerFrame* aParentFrame)
{ {
// Note: not all content objects are associated with a frame (e.g., if it's return FindSibling<SiblingDirection::Backward>(aIter, aTargetContentDisplay);
// `display: none') so keep looking until we find a previous frame.
while (nsIContent* sibling = aIter.GetPreviousChild()) {
MOZ_ASSERT(sibling != aTargetContent);
nsIFrame* prevSibling =
FindFrameForContentSibling(sibling, aTargetContent, aTargetContentDisplay,
aParentFrame, true);
if (prevSibling) {
// Found a previous sibling, we're done!
return prevSibling;
}
}
return nullptr;
} }
nsIFrame* nsIFrame*
nsCSSFrameConstructor::FindNextSibling(FlattenedChildIterator aIter, nsCSSFrameConstructor::FindNextSibling(const FlattenedChildIterator& aIter,
nsIContent* aTargetContent, StyleDisplay& aTargetContentDisplay)
StyleDisplay& aTargetContentDisplay,
nsContainerFrame* aParentFrame)
{ {
while (nsIContent* sibling = aIter.GetNextChild()) { return FindSibling<SiblingDirection::Forward>(aIter, aTargetContentDisplay);
MOZ_ASSERT(sibling != aTargetContent); }
nsIFrame* nextSibling =
FindFrameForContentSibling(sibling, aTargetContent, aTargetContentDisplay,
aParentFrame, false);
if (nextSibling) { template<nsCSSFrameConstructor::SiblingDirection aDirection>
// We found a next sibling, we're done! nsIFrame*
return nextSibling; nsCSSFrameConstructor::FindSibling(const FlattenedChildIterator& aIter,
StyleDisplay& aTargetContentDisplay)
{
nsIContent* targetContent = aIter.Get();
nsIFrame* sibling =
FindSiblingInternal<aDirection>(aIter, targetContent, aTargetContentDisplay);
if (sibling) {
return sibling;
}
// Our siblings (if any) do not have a frame to guide us. The frame for the
// target content should be inserted whereever a frame for the container would
// be inserted. This is needed when inserting into display: contents nodes.
const nsIContent* current = aIter.Parent();
while (GetDisplayContentsStyleFor(current)) {
const nsIContent* parent = current->GetFlattenedTreeParent();
MOZ_ASSERT(parent, "No display: contents on the root");
FlattenedChildIterator iter(parent);
iter.Seek(current);
sibling = FindSiblingInternal<aDirection>(
iter, targetContent, aTargetContentDisplay);
if (sibling) {
return sibling;
} }
current = parent;
} }
return nullptr; return nullptr;
@ -6836,8 +6868,7 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
// Note that FindPreviousSibling is passed the iterator by value, so that // Note that FindPreviousSibling is passed the iterator by value, so that
// the later usage of the iterator starts from the same place. // the later usage of the iterator starts from the same place.
StyleDisplay childDisplay = UNSET_DISPLAY; StyleDisplay childDisplay = UNSET_DISPLAY;
nsIFrame* prevSibling = nsIFrame* prevSibling = FindPreviousSibling(iter, childDisplay);
FindPreviousSibling(iter, iter.Get(), childDisplay, aInsertion->mParentFrame);
// Now, find the geometric parent so that we can handle // Now, find the geometric parent so that we can handle
// continuations properly. Use the prev sibling if we have it; // continuations properly. Use the prev sibling if we have it;
@ -6850,34 +6881,7 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
iter.Seek(aEndSkipChild); iter.Seek(aEndSkipChild);
iter.GetPreviousChild(); iter.GetPreviousChild();
} }
nsIFrame* nextSibling = nsIFrame* nextSibling = FindNextSibling(iter, childDisplay);
FindNextSibling(iter, iter.Get(), childDisplay, aInsertion->mParentFrame);
if (GetDisplayContentsStyleFor(aInsertion->mContainer)) {
if (!nextSibling) {
// Our siblings (if any) does not have a frame to guide us.
// The frame for aChild should be inserted whereever a frame for
// the container would be inserted. This is needed when inserting
// into nested display:contents nodes.
nsIContent* child = aInsertion->mContainer;
nsIContent* parent = child->GetParent();
aInsertion->mParentFrame =
::GetAdjustedParentFrame(aInsertion->mParentFrame,
aInsertion->mParentFrame->GetType(),
parent);
InsertionPoint fakeInsertion(aInsertion->mParentFrame, parent);
nsIFrame* result = GetInsertionPrevSibling(&fakeInsertion, child, aIsAppend,
aIsRangeInsertSafe, nullptr, nullptr);
MOZ_ASSERT(aInsertion->mParentFrame->GetContent() ==
fakeInsertion.mParentFrame->GetContent());
// fakeInsertion.mParentFrame may now be a continuation of the frame
// we started with in the ctor above.
aInsertion->mParentFrame = fakeInsertion.mParentFrame;
return result;
}
prevSibling = nextSibling->GetPrevSibling();
}
if (nextSibling) { if (nextSibling) {
aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame(); aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
} else { } else {
@ -8022,22 +8026,6 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
} }
} }
if (!prevSibling) {
// We're inserting the new frames as the first child. See if the
// parent has a :before pseudo-element
nsIFrame* firstChild = insertion.mParentFrame->PrincipalChildList().FirstChild();
if (firstChild &&
nsLayoutUtils::IsGeneratedContentFor(container, firstChild,
nsCSSPseudoElements::before)) {
// Insert the new frames after the last continuation of the :before
prevSibling = firstChild->GetTailContinuation();
insertion.mParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
// Don't change isAppend here; we'll can call AppendFrames as needed, and
// the change to our prevSibling doesn't affect that.
}
}
FrameConstructionItemList items; FrameConstructionItemList items;
ParentType parentType = GetParentType(frameType); ParentType parentType = GetParentType(frameType);
FlattenedChildIterator iter(aContainer); FlattenedChildIterator iter(aContainer);

View file

@ -1962,64 +1962,53 @@ private:
nsIFrame* aPrevSibling, nsIFrame* aPrevSibling,
nsFrameItems& aFrameItems); nsFrameItems& aFrameItems);
/** // The direction in which we should look for siblings.
* Find the right frame to use for aContent when looking for sibling enum class SiblingDirection
* frames for aTargetContent. If aPrevSibling is true, this {
* will look for last continuations, etc, as necessary. This calls Forward,
* IsValidSibling as needed; if that returns false it returns null. Backward,
* };
* @param aContent the content to search for frames
* @param aTargetContent the content we're finding a sibling frame for
* @param aTargetContentDisplay the CSS display enum for aTargetContent if
* already known, UNSET_DISPLAY otherwise. It will be filled in
* if needed.
* @param aParentFrame the nearest ancestor frame, used internally for
* finding ::after / ::before frames
* @param aPrevSibling true if we're searching in reverse DOM order
*/
nsIFrame* FindFrameForContentSibling(nsIContent* aContent,
nsIContent* aTargetContent,
mozilla::StyleDisplay& aTargetContentDisplay,
nsContainerFrame* aParentFrame,
bool aPrevSibling);
/** /**
* Find the frame for the content immediately preceding the one aIter * Find the frame for the content immediately next to the one aIter points to,
* points to, following continuations if necessary. aIter is passed by * in the direction SiblingDirection indicates, following continuations if
* value on purpose, so as not to modify the caller's iterator. * necessary.
*
* aIter is passed by const reference on purpose, so as not to modify the
* caller's iterator.
* *
* @param aIter should be positioned such that aIter.GetPreviousChild() * @param aIter should be positioned such that aIter.GetPreviousChild()
* is the first content to search for frames * is the first content to search for frames
* @param aTargetContent the content we're finding a sibling frame for * @param aTargetContentDisplay the CSS display enum for the content aIter
* @param aTargetContentDisplay the CSS display enum for aTargetContent if * points to if already known, UNSET_DISPLAY otherwise. It will be
* already known, UNSET_DISPLAY otherwise. It will be filled in * filled in if needed.
* if needed.
* @param aParentFrame the nearest ancestor frame, used inernally for
* finding ::after / ::before frames
*/ */
nsIFrame* FindPreviousSibling(mozilla::dom::FlattenedChildIterator aIter, template<SiblingDirection>
nsIContent* aTargetContent, nsIFrame* FindSibling(const mozilla::dom::FlattenedChildIterator& aIter,
mozilla::StyleDisplay& aTargetContentDisplay, mozilla::StyleDisplay& aTargetContentDisplay);
nsContainerFrame* aParentFrame);
/** // Helper for the implementation of FindSibling.
* Find the frame for the content node immediately following the one aIter template<SiblingDirection>
* points to, following continuations if necessary. aIter is passed by value nsIFrame* FindSiblingInternal(
* on purpose, so as not to modify the caller's iterator. mozilla::dom::FlattenedChildIterator,
* nsIContent* aTargetContent,
* @param aIter should be positioned such that aIter.GetNextChild() mozilla::StyleDisplay& aTargetContentDisplay);
* is the first content to search for frames
* @param aTargetContent the content we're finding a sibling frame for // An alias of FindSibling<SiblingDirection::Forward>.
* @param aTargetContentDisplay the CSS display enum for aTargetContent if nsIFrame* FindNextSibling(const mozilla::dom::FlattenedChildIterator& aIter,
* already known, UNSET_DISPLAY otherwise. It will be filled in mozilla::StyleDisplay& aTargetContentDisplay);
* if needed. // An alias of FindSibling<SiblingDirection::Backwards>.
* @param aParentFrame the nearest ancestor frame, used inernally for nsIFrame* FindPreviousSibling(const mozilla::dom::FlattenedChildIterator& aIter,
* finding ::after / ::before frames mozilla::StyleDisplay& aTargetContentDisplay);
*/
nsIFrame* FindNextSibling(mozilla::dom::FlattenedChildIterator aIter, // Given a potential first-continuation sibling frame for aTargetContent,
nsIContent* aTargetContent, // verify that it is an actual valid sibling for it, and return the
mozilla::StyleDisplay& aTargetContentDisplay, // appropriate continuation the new frame for aTargetContent should be
nsContainerFrame* aParentFrame); // inserted next to.
nsIFrame* AdjustSiblingFrame(nsIFrame* aSibling,
nsIContent* aTargetContent,
mozilla::StyleDisplay& aTargetContentDisplay,
SiblingDirection aDirection);
// Find the right previous sibling for an insertion. This also updates the // Find the right previous sibling for an insertion. This also updates the
// parent frame to point to the correct continuation of the parent frame to // parent frame to point to the correct continuation of the parent frame to

View file

@ -132,7 +132,8 @@ nsFrameManager::Destroy()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
/* static */ nsStyleContext* /* static */ nsStyleContext*
nsFrameManager::GetStyleContextInMap(UndisplayedMap* aMap, nsIContent* aContent) nsFrameManager::GetStyleContextInMap(UndisplayedMap* aMap,
const nsIContent* aContent)
{ {
if (!aContent) { if (!aContent) {
return nullptr; return nullptr;

View file

@ -80,7 +80,7 @@ public:
void Destroy(); void Destroy();
// Mapping undisplayed content // Mapping undisplayed content
nsStyleContext* GetUndisplayedContent(nsIContent* aContent) nsStyleContext* GetUndisplayedContent(const nsIContent* aContent)
{ {
if (!mUndisplayedMap) { if (!mUndisplayedMap) {
return nullptr; return nullptr;
@ -105,7 +105,7 @@ public:
/** /**
* Return the registered display:contents style context for aContent, if any. * Return the registered display:contents style context for aContent, if any.
*/ */
nsStyleContext* GetDisplayContentsStyleFor(nsIContent* aContent) nsStyleContext* GetDisplayContentsStyleFor(const nsIContent* aContent)
{ {
if (!mDisplayContentsMap) { if (!mDisplayContentsMap) {
return nullptr; return nullptr;
@ -185,7 +185,7 @@ public:
nsILayoutHistoryState* aState); nsILayoutHistoryState* aState);
protected: protected:
static nsStyleContext* GetStyleContextInMap(UndisplayedMap* aMap, static nsStyleContext* GetStyleContextInMap(UndisplayedMap* aMap,
nsIContent* aContent); const nsIContent* aContent);
static mozilla::UndisplayedNode* static mozilla::UndisplayedNode*
GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap, GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
nsIContent* aParentContent); nsIContent* aParentContent);

View file

@ -1587,33 +1587,6 @@ nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
return nullptr; return nullptr;
} }
// static
bool
nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent,
nsIFrame* aFrame,
nsIAtom* aPseudoElement)
{
NS_PRECONDITION(aFrame, "Must have a frame");
NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
if (!aFrame->IsGeneratedContentFrame()) {
return false;
}
nsIFrame* parent = aFrame->GetParent();
NS_ASSERTION(parent, "Generated content can't be root frame");
if (parent->IsGeneratedContentFrame()) {
// Not the root of the generated content
return false;
}
if (aContent && parent->GetContent() != aContent) {
return false;
}
return (aFrame->GetContent()->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore) ==
(aPseudoElement == nsCSSPseudoElements::before);
}
// static // static
nsIFrame* nsIFrame*
nsLayoutUtils::GetCrossDocParentFrame(const nsIFrame* aFrame, nsLayoutUtils::GetCrossDocParentFrame(const nsIFrame* aFrame,

View file

@ -353,23 +353,6 @@ public:
*/ */
static nsIFrame* GetRealPrimaryFrameFor(const nsIContent* aContent); static nsIFrame* GetRealPrimaryFrameFor(const nsIContent* aContent);
/**
* IsGeneratedContentFor returns true if aFrame is the outermost
* frame for generated content of type aPseudoElement for aContent.
* aFrame *might not* have the aPseudoElement pseudo-style! For example
* it might be a table wrapper frame and the inner table frame might
* have the pseudo-style.
*
* @param aContent the content node we're looking at. If this is
* null, then we just assume that aFrame has the right content
* pointer.
* @param aFrame the frame we're looking at
* @param aPseudoElement the pseudo type we're interested in
* @return whether aFrame is the generated aPseudoElement frame for aContent
*/
static bool IsGeneratedContentFor(nsIContent* aContent, nsIFrame* aFrame,
nsIAtom* aPseudoElement);
#ifdef DEBUG #ifdef DEBUG
// TODO: remove, see bug 598468. // TODO: remove, see bug 598468.
static bool gPreventAssertInCompareTreePosition; static bool gPreventAssertInCompareTreePosition;

View file

@ -248,7 +248,7 @@ asserts(0-10) == grid-fragmentation-015.html grid-fragmentation-015-ref.html # b
== grid-fragmentation-dyn5-019.html grid-fragmentation-019-ref.html == grid-fragmentation-dyn5-019.html grid-fragmentation-019-ref.html
== grid-fragmentation-dyn1-020.html grid-fragmentation-020-ref.html == grid-fragmentation-dyn1-020.html grid-fragmentation-020-ref.html
== grid-fragmentation-dyn2-020.html grid-fragmentation-020-ref.html == grid-fragmentation-dyn2-020.html grid-fragmentation-020-ref.html
!= grid-fragmentation-dyn1-021.html grid-fragmentation-021-ref.html # bug 1251799 == grid-fragmentation-dyn1-021.html grid-fragmentation-021-ref.html
== grid-fragmentation-dyn2-021.html grid-fragmentation-021-ref.html == grid-fragmentation-dyn2-021.html grid-fragmentation-021-ref.html
== grid-fragmentation-dyn3-021.html grid-fragmentation-021-ref.html == grid-fragmentation-dyn3-021.html grid-fragmentation-021-ref.html
== grid-fragmentation-dyn4-021.html grid-fragmentation-021-ref.html == grid-fragmentation-dyn4-021.html grid-fragmentation-021-ref.html

View file

@ -0,0 +1,5 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test Reference</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
PASS