diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index e524d981769..6c5424aab8c 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -451,22 +451,23 @@ IsFrameSpecial(nsIFrame* aFrame) return (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) != 0; } -static nsIFrame* GetSpecialSibling(nsIFrame* aFrame) +static void +GetSpecialSibling(nsFrameManager* aFrameManager, nsIFrame* aFrame, nsIFrame** aResult) { // We only store the "special sibling" annotation with the first - // frame in the continuation chain. Walk back to find that frame now. - aFrame = aFrame->GetFirstContinuation(); + // frame in the flow. Walk back to find that frame now. + aFrame = aFrame->GetFirstInFlow(); void* value = aFrame->GetProperty(nsGkAtoms::IBSplitSpecialSibling); - return static_cast(value); + *aResult = static_cast(value); } static nsIFrame* -GetLastSpecialSibling(nsIFrame* aFrame) +GetLastSpecialSibling(nsFrameManager* aFrameManager, nsIFrame* aFrame) { for (nsIFrame *frame = aFrame, *next; ; frame = next) { - next = GetSpecialSibling(frame); + GetSpecialSibling(aFrameManager, frame, &next); if (!next) return frame; } @@ -536,18 +537,10 @@ IsInlineOutside(nsIFrame* aFrame) return aFrame->GetStyleDisplay()->IsInlineOutside(); } -/** - * True if aFrame is an actual inline frame in the sense of non-replaced - * display:inline CSS boxes. In other words, it can be affected by {ib} - * splitting and can contain first-letter frames. Basically, this is either an - * inline frame (positioned or otherwise) or an line frame (this last because - * it can contain first-letter and because inserting blocks in the middle of it - * needs to terminate it). - */ static PRBool -IsInlineFrame(const nsIFrame* aFrame) +IsBlockOutside(nsIFrame* aFrame) { - return aFrame->IsFrameOfType(nsIFrame::eLineParticipant); + return aFrame->GetStyleDisplay()->IsBlockOutside(); } //---------------------------------------------------------------------- @@ -1423,7 +1416,7 @@ nsFrameConstructorState::AddChild(nsIFrame* aNewFrame, // Now add the special siblings too. nsIFrame* specialSibling = aNewFrame; while (specialSibling && IsFrameSpecial(specialSibling)) { - specialSibling = GetSpecialSibling(specialSibling); + GetSpecialSibling(mFrameManager, specialSibling, &specialSibling); if (specialSibling) { NS_ASSERTION(frameItems == &aFrameItems, "IB split ending up in an out-of-flow childlist?"); @@ -7965,7 +7958,8 @@ FindPreviousAnonymousSibling(nsIPresShell* aPresShell, // The frame may be a special frame (a split inline frame that // contains a block). Get the last part of that split. if (IsFrameSpecial(prevSibling)) { - prevSibling = GetLastSpecialSibling(prevSibling); + prevSibling = GetLastSpecialSibling(aPresShell->FrameManager(), + prevSibling); } // The frame may have a continuation. If so, we want the @@ -8150,7 +8144,8 @@ nsCSSFrameConstructor::FindPreviousSibling(nsIContent* aContainer, // The frame may be a special frame (a split inline frame that // contains a block). Get the last part of that split. if (IsFrameSpecial(prevSibling)) { - prevSibling = GetLastSpecialSibling(prevSibling); + prevSibling = GetLastSpecialSibling(mPresShell->FrameManager(), + prevSibling); } // The frame may have a continuation. Get the last continuation @@ -8423,7 +8418,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, if (item == child) // Call ContentInserted with this index. ContentInserted(aContainer, child, - iter.index(), mTempFrameTreeState); + iter.index(), mTempFrameTreeState, PR_FALSE); LAYOUT_PHASE_TEMP_REENTER(); } } @@ -8450,9 +8445,20 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, return NS_OK; } - // If the frame we are manipulating is a ``special'' 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 special sibling, not to the frame itself. + // If the frame we are manipulating is a ``special'' frame (that + // is, one that's been created as a result of a block-in-inline + // situation) then do something different instead of just + // appending newly created frames. Note that only the + // first-in-flow is marked so we check before getting to the + // last-in-flow. + // + // We run into this situation occasionally while loading web + // pages, typically when some content generation tool has + // sprinkled invalid markup into the document. More often than + // not, we'll be able to just use the normal fast-path frame + // construction code, because the frames will be appended to the + // ``anonymous'' block that got created to parent the block + // children of the inline. if (IsFrameSpecial(parentFrame)) { #ifdef DEBUG if (gNoisyContentUpdates) { @@ -8464,7 +8470,37 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, // Since we're appending, we'll walk to the last anonymous frame // that was created for the broken inline frame. - parentFrame = GetLastSpecialSibling(parentFrame); + nsFrameManager *frameManager = mPresShell->FrameManager(); + + while (1) { + nsIFrame* sibling; + GetSpecialSibling(frameManager, parentFrame, &sibling); + if (! sibling) + break; + + parentFrame = sibling; + } + + // If this frame is the anonymous block frame, then all's well: + // just append frames as usual. + const nsStyleDisplay* display = parentFrame->GetStyleDisplay(); + + if (NS_STYLE_DISPLAY_BLOCK != display->mDisplay) { + // Nope, it's an inline, so just reframe the entire stinkin' mess if the + // content is a block. We _could_ do better here with a little more work... + // find out if the child is a block or inline, an inline means we don't have to reframe + nsIContent *child = aContainer->GetChildAt(aNewIndexInContainer); + PRBool needReframe = !child; + if (child && child->IsNodeOfType(nsINode::eELEMENT)) { + nsRefPtr styleContext; + styleContext = ResolveStyleContext(parentFrame, child); + // XXX since the block child goes in the last inline of the sacred triad, frames would + // need to be moved into the 2nd triad (block) but that is more work, for now bail. + needReframe = styleContext->GetStyleDisplay()->IsBlockOutside(); + } + if (needReframe) + return ReframeContainingBlock(parentFrame); + } } // Get the parent frame's last continuation @@ -8560,7 +8596,8 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, // Perform special check for diddling around with the frames in // a special inline frame. - if (WipeContainingBlock(state, containingBlock, parentFrame, frameItems)) { + if (WipeContainingBlock(state, containingBlock, parentFrame, + frameItems.childList)) { return NS_OK; } @@ -8604,6 +8641,121 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, return NS_OK; } +// Return TRUE if the insertion of aChild into aParent1,2 should force a reframe. aParent1 is +// the special inline container which contains a block. aParentFrame is approximately aParent1's +// primary frame and will be set to the correct parent of aChild if a reframe is not necessary. +// aParent2 is aParentFrame's content. aPrevSibling will be set to the correct prev sibling of +// aChild if a reframe is not necessary. +PRBool +nsCSSFrameConstructor::NeedSpecialFrameReframe(nsIContent* aParent1, + nsIContent* aParent2, + nsIFrame*& aParentFrame, + nsIContent* aChild, + PRInt32 aIndexInContainer, + nsIFrame*& aPrevSibling, + nsIFrame* aNextSibling) +{ + // XXXbz aNextSibling is utterly unused. Why? + + if (IsBlockOutside(aParentFrame)) + return PR_FALSE; + + // find out if aChild is a block or inline + PRBool childIsBlock = PR_FALSE; + if (aChild->IsNodeOfType(nsINode::eELEMENT)) { + nsRefPtr styleContext; + styleContext = ResolveStyleContext(aParentFrame, aChild); + const nsStyleDisplay* display = styleContext->GetStyleDisplay(); + childIsBlock = display->IsBlockOutside(); + } + nsIFrame* prevParent; // parent of prev sibling + nsIFrame* nextParent; // parent of next sibling + + if (childIsBlock) { + if (aPrevSibling) { + prevParent = aPrevSibling->GetParent(); + NS_ASSERTION(prevParent, "program error - null parent frame"); + if (!IsBlockOutside(prevParent)) { // prevParent is an inline + // XXX we need to find out if prevParent is the 1st inline or the last. If it + // is the 1st, then aChild and the frames after aPrevSibling within the 1st inline + // need to be moved to the block(inline). If it is the last, then aChild and the + // frames before aPrevSibling within the last need to be moved to the block(inline). + return PR_TRUE; // For now, bail. + } + aParentFrame = prevParent; // prevParent is a block, put aChild there + } + else { + // XXXbz see comments in ContentInserted about this being wrong in many + // cases! Why doesn't this just use aNextSibling anyway? Why are we + // looking sometimes in aParent1 and sometimes in aParent2? + nsIFrame* nextSibling = (aIndexInContainer >= 0) + ? FindNextSibling(aParent2, aParentFrame, + aIndexInContainer) + : FindNextAnonymousSibling(mPresShell, mDocument, + aParent1, aChild); + if (nextSibling) { + nextParent = nextSibling->GetParent(); + NS_ASSERTION(nextParent, "program error - null parent frame"); + if (!IsBlockOutside(nextParent)) { + // XXX we need to move aChild, aNextSibling and all the frames after aNextSibling within + // the 1st inline to the block(inline). + return PR_TRUE; // for now, bail + } + // put aChild in nextParent which is the block(inline) and leave aPrevSibling null + aParentFrame = nextParent; + } + } + } + else { // aChild is an inline + if (aPrevSibling) { + prevParent = aPrevSibling->GetParent(); + NS_ASSERTION(prevParent, "program error - null parent frame"); + if (!IsBlockOutside(prevParent)) { // prevParent is an inline + // aChild goes into the same inline frame as aPrevSibling + aParentFrame = aPrevSibling->GetParent(); + NS_ASSERTION(aParentFrame, "program error - null parent frame"); + } + else { // prevParent is a block + // XXXbz see comments in ContentInserted about this being wrong in many + // cases! Why doesn't this just use aNextSibling anyway? Why are we + // looking sometimes in aParent1 and sometimes in aParent2? + nsIFrame* nextSibling = (aIndexInContainer >= 0) + ? FindNextSibling(aParent2, aParentFrame, + aIndexInContainer) + : FindNextAnonymousSibling(mPresShell, + mDocument, aParent1, + aChild); + if (nextSibling) { + nextParent = nextSibling->GetParent(); + NS_ASSERTION(nextParent, "program error - null parent frame"); + if (!IsBlockOutside(nextParent)) { + // nextParent is the ending inline frame. Put aChild there and + // set aPrevSibling to null so aChild is its first element. + aParentFrame = nextSibling->GetParent(); + NS_ASSERTION(aParentFrame, "program error - null parent frame"); + aPrevSibling = nsnull; + } + else { // nextParent is a block + // prevParent and nextParent should be the same, and aChild goes there + NS_ASSERTION(prevParent == nextParent, "special frame error"); + aParentFrame = prevParent; + } + } + else { + // The child has no next sibling, so we can't find the ending inline + // frame (which might not exist in this case anyway!), but aChild + // should go in there. Force a reframe. + // XXXbz wouldn't getting prevParent's special sibling work, with + // reframing only needed if that's null? + return PR_TRUE; + } + } + } + // else aChild goes into the 1st inline frame which is aParentFrame + } + return PR_FALSE; +} + #ifdef MOZ_XUL enum content_operation @@ -8676,7 +8828,8 @@ nsresult nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer, - nsILayoutHistoryState* aFrameState) + nsILayoutHistoryState* aFrameState, + PRBool aInReinsertContent) { AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC); // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and @@ -8802,14 +8955,18 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, : FindNextAnonymousSibling(mPresShell, mDocument, aContainer, aChild); } + PRBool handleSpecialFrame = IsFrameSpecial(parentFrame) && !aInReinsertContent; + // Now, find the geometric parent so that we can handle // continuations properly. Use the prev sibling if we have it; // otherwise use the next sibling. if (prevSibling) { - parentFrame = prevSibling->GetParent()->GetContentInsertionFrame(); + if (!handleSpecialFrame) + parentFrame = prevSibling->GetParent()->GetContentInsertionFrame(); } else if (nextSibling) { - parentFrame = nextSibling->GetParent()->GetContentInsertionFrame(); + if (!handleSpecialFrame) + parentFrame = nextSibling->GetParent()->GetContentInsertionFrame(); } else { // No previous or next sibling, so treat this like an appended frame. @@ -8834,6 +8991,26 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, return NS_OK; } + // If the frame we are manipulating is a special frame then see if we need to reframe + // NOTE: if we are in ReinsertContent, then don't reframe as we are already doing just that! + if (handleSpecialFrame) { + // a special inline frame has propagated some of its children upward to be children + // of the block and those frames may need to move around. Sometimes we may need to reframe +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentInserted: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special\n"); + } +#endif + // if we don't need to reframe then set parentFrame and prevSibling to the correct values + if (NeedSpecialFrameReframe(aContainer, container, parentFrame, + aChild, aIndexInContainer, prevSibling, + nextSibling)) { + return ReframeContainingBlock(parentFrame); + } + } + nsFrameConstructorState state(mPresShell, mFixedContainingBlock, GetAbsoluteContainingBlock(parentFrame), GetFloatContainingBlock(parentFrame), @@ -8846,6 +9023,8 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, // is not the normal structure and requires custom updating // logic. nsIFrame* containingBlock = state.mFloatedItems.containingBlock; + nsStyleContext* blockSC; + nsIContent* blockContent = nsnull; PRBool haveFirstLetterStyle = PR_FALSE; PRBool haveFirstLineStyle = PR_FALSE; @@ -8898,6 +9077,33 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, ? FindNextSibling(container, parentFrame, aIndexInContainer, aChild) : FindNextAnonymousSibling(mPresShell, mDocument, aContainer, aChild); } + + handleSpecialFrame = IsFrameSpecial(parentFrame) && !aInReinsertContent; + if (handleSpecialFrame && + NeedSpecialFrameReframe(aContainer, container, parentFrame, + aChild, aIndexInContainer, prevSibling, + nextSibling)) { +#ifdef DEBUG + nsIContent* parentContainer = blockContent->GetParent(); + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentInserted: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special inline\n"); + printf(" ==> blockContent=%p, parentContainer=%p\n", + static_cast(blockContent), + static_cast(parentContainer)); + } +#endif + + NS_ASSERTION(GetFloatContainingBlock(parentFrame) == containingBlock, + "Unexpected block ancestor for parentFrame"); + + // Note that in this case we're guaranteed that the closest block + // containing parentFrame is |containingBlock|. So + // ReframeContainingBlock(parentFrame) will make sure to rebuild the + // first-letter stuff we just blew away. + return ReframeContainingBlock(parentFrame); + } } } @@ -8939,7 +9145,8 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, // Perform special check for diddling around with the frames in // a special inline frame. - if (WipeContainingBlock(state, containingBlock, parentFrame, frameItems)) + if (WipeContainingBlock(state, containingBlock, parentFrame, + frameItems.childList)) return NS_OK; if (haveFirstLineStyle && parentFrame == containingBlock) { @@ -9057,7 +9264,7 @@ nsCSSFrameConstructor::ReinsertContent(nsIContent* aContainer, nsresult res = ContentRemoved(aContainer, aChild, ix, PR_TRUE); if (NS_SUCCEEDED(res)) { - res = ContentInserted(aContainer, aChild, ix, nsnull); + res = ContentInserted(aContainer, aChild, ix, nsnull, PR_TRUE); } return res; @@ -9280,9 +9487,21 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, // frames. // NOTE: if we are in ReinsertContent, // then do not reframe as we are already doing just that! - if (!aInReinsertContent && - MaybeRecreateContainerForIBSplitterFrame(childFrame, &rv)) { - return rv; + if (IsFrameSpecial(childFrame) && !aInReinsertContent) { + // We are pretty harsh here (and definitely not optimal) -- we + // wipe out the entire containing block and recreate it from + // scratch. The reason is that because we know that a special + // inline frame has propagated some of its children upward to be + // children of the block and that those frames may need to move + // around. This logic guarantees a correct answer. +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentRemoved: childFrame="); + nsFrame::ListTag(stdout, childFrame); + printf(" is special\n"); + } +#endif + return ReframeContainingBlock(childFrame); } // Get the childFrame's parent frame @@ -10691,7 +10910,9 @@ nsCSSFrameConstructor::FindPrimaryFrameFor(nsFrameManager* aFrameManager, // that's been split because it contained a block), we need to // follow the out-of-flow "special sibling" link, and search // *that* subtree as well. - parentFrame = GetSpecialSibling(parentFrame); + nsIFrame* specialSibling = nsnull; + GetSpecialSibling(aFrameManager, parentFrame, &specialSibling); + parentFrame = specialSibling; } else { break; @@ -10835,49 +11056,19 @@ nsCSSFrameConstructor::MaybeRecreateFramesForContent(nsIContent* aContent) } PRBool -nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame, - nsresult* aResult) +nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame, nsresult* aResult) { - NS_PRECONDITION(aFrame, "Must have a frame"); - NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root"); - NS_PRECONDITION(aResult, "Null out param?"); - NS_PRECONDITION(aFrame == aFrame->GetFirstContinuation(), - "aFrame not the result of GetPrimaryFrameFor()?"); - - if (IsFrameSpecial(aFrame)) { - // The removal functions can't handle removal of an {ib} split directly; we - // need to rebuild the containing block. -#ifdef DEBUG - if (gNoisyContentUpdates) { - printf("nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame: " - "frame="); - nsFrame::ListTag(stdout, aFrame); - printf(" is special\n"); - } -#endif - - *aResult = ReframeContainingBlock(aFrame); - return PR_TRUE; - } - - // We might still need to reconstruct things if the parent of aFrame is - // special, since in that case the removal of aFrame might affect the - // splitting of its parent. - nsIFrame* parent = aFrame->GetParent(); - if (!IsFrameSpecial(parent)) { + if (!aFrame || !IsFrameSpecial(aFrame)) return PR_FALSE; - } #ifdef DEBUG - if (gNoisyContentUpdates || 1) { - printf("nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame: " - "frame="); - nsFrame::ListTag(stdout, parent); + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::RecreateFramesForContent: frame="); + nsFrame::ListTag(stdout, aFrame); printf(" is special\n"); } #endif - - *aResult = ReframeContainingBlock(parent); + *aResult = ReframeContainingBlock(aFrame); return PR_TRUE; } @@ -10895,15 +11086,23 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent) // block *here*, rather than trying to remove and re-insert the // content (which would otherwise result in *two* nested reframe // containing block from ContentRemoved() and ContentInserted(), - // below!). We'd really like to optimize away one of those - // containing block reframes, hence the code here. + // below!) nsIFrame* frame = mPresShell->GetPrimaryFrameFor(aContent); nsresult rv = NS_OK; - if (frame && MaybeRecreateContainerForIBSplitterFrame(frame, &rv)) { - return rv; + if (frame) { + // If the frame is an anonymous frame created as part of inline-in-block + // splitting --- or if its parent is such an anonymous frame (i.e., this + // frame might have been the cause of such splitting), then recreate the + // containing block. Note that if |frame| is an inline, then it can't + // possibly have caused the splitting, and if the inline is changing to a + // block, any reframing that's needed will happen in ContentInserted. + if (MaybeRecreateContainerForIBSplitterFrame(frame, &rv) || + (!IsInlineOutside(frame) && + MaybeRecreateContainerForIBSplitterFrame(frame->GetParent(), &rv))) + return rv; } nsCOMPtr container = aContent->GetParent(); @@ -10922,7 +11121,7 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent) if (NS_SUCCEEDED(rv)) { // Now, recreate the frames associated with this content object. rv = ContentInserted(container, aContent, - indexInContainer, mTempFrameTreeState); + indexInContainer, mTempFrameTreeState, PR_FALSE); } } else { // The content is the root node, so just rebuild the world. @@ -11752,7 +11951,8 @@ nsCSSFrameConstructor::WrapFramesInFirstLetterFrame( while (frame) { nsIFrame* nextFrame = frame->GetNextSibling(); - if (nsGkAtoms::textFrame == frame->GetType()) { + nsIAtom* frameType = frame->GetType(); + if (nsGkAtoms::textFrame == frameType) { // Wrap up first-letter content in a letter frame nsIContent* textContent = frame->GetContent(); if (IsFirstLetterContent(textContent)) { @@ -11771,7 +11971,9 @@ nsCSSFrameConstructor::WrapFramesInFirstLetterFrame( return NS_OK; } } - else if (IsInlineFrame(frame)) { + else if ((nsGkAtoms::inlineFrame == frameType) || + (nsGkAtoms::lineFrame == frameType) || + (nsGkAtoms::positionedInlineFrame == frameType)) { nsIFrame* kids = frame->GetFirstChild(nsnull); WrapFramesInFirstLetterFrame(aState, aBlockFrame, frame, kids, aModifiedParent, aTextFrame, @@ -11924,7 +12126,8 @@ nsCSSFrameConstructor::RemoveFirstLetterFrames(nsPresContext* aPresContext, nsIFrame* kid = aFrame->GetFirstChild(nsnull); while (kid) { - if (nsGkAtoms::letterFrame == kid->GetType()) { + nsIAtom* frameType = kid->GetType(); + if (nsGkAtoms::letterFrame == frameType) { // Bingo. Found it. First steal away the text frame. nsIFrame* textFrame = kid->GetFirstChild(nsnull); if (!textFrame) { @@ -11958,7 +12161,9 @@ nsCSSFrameConstructor::RemoveFirstLetterFrames(nsPresContext* aPresContext, *aStopLooking = PR_TRUE; break; } - else if (IsInlineFrame(kid)) { + else if ((nsGkAtoms::inlineFrame == frameType) || + (nsGkAtoms::lineFrame == frameType) || + (nsGkAtoms::positionedInlineFrame == frameType)) { // Look inside child inline frame for the letter frame RemoveFirstLetterFrames(aPresContext, aPresShell, aFrameManager, kid, aStopLooking); @@ -12316,9 +12521,6 @@ nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState, nsIFrame* inlineFrame = nsnull; if (list3) { - // If we ever start constructing a second inline in the split even when - // list3 is null, the logic in MaybeRecreateContainerForIBSplitterFrame - // needs to be adjusted. if (aIsPositioned) { inlineFrame = NS_NewPositionedInlineFrame(mPresShell, aStyleContext); } @@ -12473,34 +12675,24 @@ PRBool nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, nsIFrame* aContainingBlock, nsIFrame* aFrame, - const nsFrameItems& aFrameList) + nsIFrame* aFrameList) { - if (!aFrameList.childList) { - return PR_FALSE; - } - // Before we go and append the frames, check for a special // situation: an inline frame that will now contain block // frames. This is a no-no and the frame construction logic knows - // how to fix this. See defition of IsInlineFrame() for what "an - // inline" is. Whether we have "a block" is tested for by - // AreAllKidsInline. + // how to fix this. - // We also need to check for an append of - // content ending in an inline to the block in an {ib} split. If - // that happens, we also need to reframe, since that content - // needs to go into the following inline in the split. - - if (IsInlineFrame(aFrame)) { - // Nothing to do if all kids are inline - if (AreAllKidsInline(aFrameList.childList)) { - return PR_FALSE; - } - } else if (!IsFrameSpecial(aFrame) || - !aFrameList.lastChild->GetStyleDisplay()->IsInlineOutside()) { - // Nothing to do if aFrame is not special or if the last kid is not inline + // If we don't have a block within an inline, just return false. Here + // "an inline" is an actual inline frame (positioned or not) or a lineframe + // (corresponding to :first-line), since the latter should stop at the first + // block it runs into and we might be inserting one in the middle of it. + // Whether we have "a block" is tested for by AreAllKidsInline. + nsIAtom* frameType = aFrame->GetType(); + if ((frameType != nsGkAtoms::inlineFrame && + frameType != nsGkAtoms::positionedInlineFrame && + frameType != nsGkAtoms::lineFrame) || + AreAllKidsInline(aFrameList)) return PR_FALSE; - } // Ok, reverse tracks: wipe out the frames we just created nsFrameManager *frameManager = aState.mFrameManager; @@ -12509,7 +12701,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, // or entries in the undisplayed content map are removed frameManager->ClearAllUndisplayedContentIn(aFrame->GetContent()); - CleanupFrameReferences(frameManager, aFrameList.childList); + CleanupFrameReferences(frameManager, aFrameList); if (aState.mAbsoluteItems.childList) { CleanupFrameReferences(frameManager, aState.mAbsoluteItems.childList); } @@ -12524,7 +12716,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, CleanupFrameReferences(frameManager, aState.mPopupItems.childList); } #endif - nsFrameList tmp(aFrameList.childList); + nsFrameList tmp(aFrameList); tmp.DestroyFrames(); tmp.SetFrames(aState.mAbsoluteItems.childList); diff --git a/mozilla/layout/base/nsCSSFrameConstructor.h b/mozilla/layout/base/nsCSSFrameConstructor.h index de1f9ffcbee..a2288586619 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.h +++ b/mozilla/layout/base/nsCSSFrameConstructor.h @@ -111,7 +111,8 @@ public: nsresult ContentInserted(nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer, - nsILayoutHistoryState* aFrameState); + nsILayoutHistoryState* aFrameState, + PRBool aInReinsertContent); nsresult ContentRemoved(nsIContent* aContainer, nsIContent* aChild, @@ -753,16 +754,7 @@ private: nsresult RecreateFramesForContent(nsIContent* aContent); - // If removal of aFrame from the frame tree requires reconstruction of some - // containing block (either of aFrame or of its parent) due to {ib} splits, - // recreate the relevant containing block. The return value indicates - // whether this happened. If this method returns true, *aResult is the - // return value of ReframeContainingBlock. If this method returns false, the - // value of *aResult is no affected. aFrame and aResult must not be null. - // aFrame must be the result of a GetPrimaryFrameFor() call (which means its - // parent is also not null). - PRBool MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame, - nsresult* aResult); + PRBool MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame, nsresult* aResult); nsresult CreateContinuingOuterTableFrame(nsIPresShell* aPresShell, nsPresContext* aPresContext, @@ -846,9 +838,17 @@ private: PRBool AreAllKidsInline(nsIFrame* aFrameList); PRBool WipeContainingBlock(nsFrameConstructorState& aState, - nsIFrame* aContainingBlock, + nsIFrame* blockContent, nsIFrame* aFrame, - const nsFrameItems& aFrameList); + nsIFrame* aFrameList); + + PRBool NeedSpecialFrameReframe(nsIContent* aParent1, + nsIContent* aParent2, + nsIFrame*& aParentFrame, + nsIContent* aChild, + PRInt32 aIndexInContainer, + nsIFrame*& aPrevSibling, + nsIFrame* aNextSibling); nsresult ReframeContainingBlock(nsIFrame* aFrame); diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index d24988cf214..a9339683401 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -2366,7 +2366,8 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) // Have the style sheet processor construct frame for the root // content object down - mFrameConstructor->ContentInserted(nsnull, root, 0, nsnull); + mFrameConstructor->ContentInserted(nsnull, root, 0, + nsnull, PR_FALSE); VERIFY_STYLE_TREE; MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::InitialReflow(), this=%p\n", (void*)this)); @@ -4538,7 +4539,7 @@ PresShell::ContentInserted(nsIDocument* aDocument, WillCauseReflow(); mFrameConstructor->ContentInserted(aContainer, aChild, - aIndexInContainer, nsnull); + aIndexInContainer, nsnull, PR_FALSE); VERIFY_STYLE_TREE; DidCauseReflow(); } diff --git a/mozilla/layout/reftests/reftest.list b/mozilla/layout/reftests/reftest.list index 31ca8782c6f..4a64f88f78c 100644 --- a/mozilla/layout/reftests/reftest.list +++ b/mozilla/layout/reftests/reftest.list @@ -63,4 +63,4 @@ include columns/reftest.list include image-region/reftest.list # block-inside-inline splits -include ib-split/reftest.list +#include ib-split/reftest.list