Bug 1419964 - Remove AdjustParentFrameForAfterContent

Tag #1375
This commit is contained in:
Matt A. Tobin 2020-04-17 07:22:58 -04:00 committed by Roy Tam
commit eaf0831388

View file

@ -6323,132 +6323,25 @@ nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
return nullptr;
}
/**
* This function will check whether aContainer has :after generated content.
* If so, appending to it should actually insert. The return value is the
* parent to use for newly-appended content. *aAfterFrame points to the :after
* frame before which appended content should go, if there is one.
*/
static nsContainerFrame*
AdjustAppendParentForAfterContent(nsFrameManager* aFrameManager,
nsIContent* aContainer,
nsContainerFrame* aParentFrame,
nsIContent* aChild,
nsIFrame** aAfterFrame)
{
// If the parent frame has any pseudo-elements or aContainer is a
// display:contents node then we need to walk through the child
// frames to find the first one that is either a ::after frame for an
// ancestor of aChild or a frame that is for a node later in the
// document than aChild and return that in aAfterFrame.
nsIFrame* afterBeforeOwnerFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aParentFrame);
if (afterBeforeOwnerFrame->GetProperty(nsIFrame::GenConProperty()) ||
nsLayoutUtils::HasPseudoStyle(aContainer, aParentFrame->StyleContext(),
CSSPseudoElementType::after,
aParentFrame->PresContext()) ||
aFrameManager->GetDisplayContentsStyleFor(aContainer)) {
nsIFrame* afterFrame = nullptr;
nsContainerFrame* parent =
static_cast<nsContainerFrame*>(aParentFrame->LastContinuation());
bool done = false;
while (!done && parent) {
// Ensure that all normal flow children are on the principal child list.
parent->DrainSelfOverflowList();
nsIFrame* child = parent->GetChildList(nsIFrame::kPrincipalList).LastChild();
if (child && child->IsPseudoFrame(aContainer) &&
!child->IsGeneratedContentFrame()) {
// Drill down into non-generated pseudo frames of aContainer.
nsContainerFrame* childAsContainer = do_QueryFrame(child);
if (childAsContainer) {
parent = nsLayoutUtils::LastContinuationWithChild(childAsContainer);
continue;
}
}
for (; child; child = child->GetPrevSibling()) {
nsIContent* c = child->GetContent();
if (child->IsGeneratedContentFrame()) {
nsIContent* p = c->GetParent();
if (c->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter) {
if (!nsContentUtils::ContentIsDescendantOf(aChild, p) &&
p != aContainer &&
nsContentUtils::PositionIsBefore(p, aChild)) {
// ::after generated content for content earlier in the doc and not
// for an ancestor. "p != aContainer" may seem redundant but it
// checks if the ::after belongs to the XBL insertion point we're
// inserting aChild into (in which case ContentIsDescendantOf is
// false even though p == aContainer).
// See layout/reftests/bugs/482592-1a.xhtml for an example of that.
done = true;
break;
}
} else if (nsContentUtils::PositionIsBefore(p, aChild)) {
// Non-::after generated content for content earlier in the doc.
done = true;
break;
}
} else if (nsContentUtils::PositionIsBefore(c, aChild)) {
// Content is before aChild.
done = true;
break;
}
afterFrame = child;
}
parent = static_cast<nsContainerFrame*>(parent->GetPrevContinuation());
}
if (afterFrame) {
*aAfterFrame = afterFrame;
return afterFrame->GetParent();
}
}
*aAfterFrame = nullptr;
if (IsFramePartOfIBSplit(aParentFrame)) {
// We might be in a situation where the last part of the {ib} split was
// empty. Since we have no ::after pseudo-element, we do in fact want to be
// appending to that last part, so advance to it if needed. Note that here
// aParentFrame is the result of a GetLastIBSplitSibling call, so must be
// either the last or next to last ib-split sibling.
nsContainerFrame* trailingInline = GetIBSplitSibling(aParentFrame);
if (trailingInline) {
aParentFrame = trailingInline;
}
// Always make sure to look at the last continuation of the frame
// for the {ib} case, even if that continuation is empty. We
// don't do this for the non-ib-split-frame case, since in the
// other cases appending to the last nonempty continuation is fine
// and in fact not doing that can confuse code that doesn't know
// to pull kids from continuations other than its next one.
aParentFrame =
static_cast<nsContainerFrame*>(aParentFrame->LastContinuation());
}
return aParentFrame;
}
/**
* This function will get the previous sibling to use for an append operation.
* it takes a parent frame (must not be null) and its :after frame (may be
* null).
*
* It takes a parent frame (must not be null) and the next insertion sibling, if
* the parent content is display: contents or has ::after content (may be null).
*/
static nsIFrame*
FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aAfterFrame)
FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
{
if (aAfterFrame) {
NS_ASSERTION(aAfterFrame->GetParent() == aParentFrame, "Wrong parent");
NS_ASSERTION(aAfterFrame->GetPrevSibling() ||
aParentFrame->PrincipalChildList().FirstChild() == aAfterFrame,
":after frame must be on the principal child list here");
return aAfterFrame->GetPrevSibling();
}
aParentFrame->DrainSelfOverflowList();
if (aNextSibling) {
MOZ_ASSERT(aNextSibling->GetParent() == aParentFrame, "Wrong parent");
MOZ_ASSERT(aNextSibling->GetPrevSibling() ||
aParentFrame->PrincipalChildList().FirstChild() == aNextSibling,
"next sibling must be on the principal child list here");
return aNextSibling->GetPrevSibling();
}
return aParentFrame->GetChildList(kPrincipalList).LastChild();
}
@ -7417,7 +7310,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
// If the frame we are manipulating is a ib-split frame (that is, one
// that's been created as a result of a block-in-inline situation) then we
// need to append to the last ib-split sibling, not to the frame itself.
bool parentIBSplit = IsFramePartOfIBSplit(parentFrame);
const bool parentIBSplit = IsFramePartOfIBSplit(parentFrame);
if (parentIBSplit) {
#ifdef DEBUG
if (gNoisyContentUpdates) {
@ -7443,36 +7336,63 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
parentFrame->GetType() != nsGkAtoms::detailsFrame,
"Parent frame should not be fieldset or details!");
// Deal with possible :after generated content on the parent
nsIFrame* parentAfterFrame;
nsContainerFrame* preAdjustedParentFrame = parentFrame;
parentFrame =
::AdjustAppendParentForAfterContent(this, insertion.mContainer, parentFrame,
aFirstNewContent, &parentAfterFrame);
// See if the containing block has :first-letter style applied.
bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame);
if (containingBlock) {
haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
haveFirstLineStyle =
ShouldHaveFirstLineStyle(containingBlock->GetContent(),
containingBlock->StyleContext());
// Deal with possible :after generated content on the parent, or display:
// contents.
nsIFrame* nextSibling = nullptr;
if (GetDisplayContentsStyleFor(insertion.mContainer) ||
nsLayoutUtils::GetAfterFrame(insertion.mContainer)) {
FlattenedChildIterator iter(insertion.mContainer);
iter.Seek(insertion.mContainer->GetLastChild());
StyleDisplay unused = UNSET_DISPLAY;
nextSibling = FindNextSibling(iter, unused);
}
if (nextSibling) {
parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
} else if (parentIBSplit) {
// We might be in a situation where the last part of the {ib} split was
// empty. Since we have no ::after pseudo-element, we do in fact want to be
// appending to that last part, so advance to it if needed. Note that here
// aParentFrame is the result of a GetLastIBSplitSibling call, so must be
// either the last or next to last ib-split sibling.
if (nsContainerFrame* trailingInline = GetIBSplitSibling(parentFrame)) {
parentFrame = trailingInline;
}
// Always make sure to look at the last continuation of the frame
// for the {ib} case, even if that continuation is empty. We
// don't do this for the non-ib-split-frame case, since in the
// other cases appending to the last nonempty continuation is fine
// and in fact not doing that can confuse code that doesn't know
// to pull kids from continuations other than its next one.
parentFrame =
static_cast<nsContainerFrame*>(parentFrame->LastContinuation());
}
nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame);
// See if the containing block has :first-letter style applied.
const bool haveFirstLetterStyle =
containingBlock && HasFirstLetterStyle(containingBlock);
const bool haveFirstLineStyle =
containingBlock &&
ShouldHaveFirstLineStyle(containingBlock->GetContent(),
containingBlock->StyleContext());
if (haveFirstLetterStyle) {
nsWeakFrame wf(parentAfterFrame);
nsWeakFrame wf(nextSibling);
// Before we get going, remove the current letter frames
RemoveLetterFrames(mPresShell, containingBlock);
if (parentAfterFrame && !wf) {
// Ouch, parentAfterFrame was a letter frame and we just deleted it!
// Retry AdjustAppendParentForAfterContent; fortunately this is rare.
parentFrame =
::AdjustAppendParentForAfterContent(this, insertion.mContainer,
preAdjustedParentFrame,
aFirstNewContent, &parentAfterFrame);
if (parentFrame != preAdjustedParentFrame) {
// Reget nextSibling, since we may have killed it.
if (nextSibling && !wf) {
FlattenedChildIterator iter(insertion.mContainer);
iter.Seek(insertion.mContainer->GetLastChild());
StyleDisplay unused = UNSET_DISPLAY;
nextSibling = FindNextSibling(iter, unused);
if (nextSibling) {
parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
containingBlock = GetFloatContainingBlock(parentFrame);
}
}
@ -7488,7 +7408,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
nsIAtom* frameType = parentFrame->GetType();
FlattenedChildIterator iter(aContainer);
bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
const bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild();
FrameConstructionItemList items;
if (aFirstNewContent->GetPreviousSibling() &&
GetParentType(frameType) == eTypeBlock &&
@ -7513,7 +7433,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
AddFrameConstructionItems(state, child, false, insertion, items);
}
nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, parentAfterFrame);
nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, nextSibling);
// Perform special check for diddling around with the frames in
// a ib-split inline frame.
@ -7536,8 +7456,11 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
!prevSibling->IsInlineOutside() ||
prevSibling->GetType() == nsGkAtoms::brFrame);
// :after content can't be <br> so no need to check it
items.SetLineBoundaryAtEnd(!parentAfterFrame ||
!parentAfterFrame->IsInlineOutside());
//
// FIXME(emilio): A display: contents sibling could! Write a test-case and
// fix.
items.SetLineBoundaryAtEnd(
!nextSibling || !nextSibling->IsInlineOutside());
}
// To suppress whitespace-only text frames, we have to verify that
// our container's DOM child list matches its flattened tree child list.