diff --git a/layout/generic/nsHTMLReflowState.cpp b/layout/generic/nsHTMLReflowState.cpp index 0a533eaf1f38..eae93d08b5f4 100644 --- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -55,6 +55,8 @@ #include "nsIServiceManager.h" #include "nsIPercentHeightObserver.h" #include "nsLayoutUtils.h" +#include "nsPlaceholderFrame.h" +#include "nsFrameManager.h" #include "mozilla/Preferences.h" #ifdef IBMBIDI #include "nsBidiUtils.h" @@ -847,7 +849,7 @@ static bool AreAllEarlierInFlowFramesEmpty(nsIFrame* aFrame, // cbrs->frame is the actual containing block void nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext* aPresContext, - nsIFrame* aPlaceholderFrame, + nsPlaceholderFrame* aPlaceholderFrame, nsIFrame* aContainingBlock, nscoord aBlockLeftContentEdge, nscoord aBlockContentWidth, @@ -930,17 +932,12 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext* aPresContext, nsLayoutUtils::GetAsBlock(aContainingBlock->GetContentInsertionFrame()); if (blockFrame) { nscoord blockYOffset = blockFrame->GetOffsetTo(aContainingBlock).y; - bool isValid; - nsBlockInFlowLineIterator iter(blockFrame, aPlaceholderFrame, &isValid); - if (!isValid) { + const nsLineBox* lineBox = aPlaceholderFrame->GetCachedLineBox(); + if (!lineBox) { // Give up. We're probably dealing with somebody using // position:absolute inside native-anonymous content anyway. aHypotheticalBox.mTop = placeholderOffset.y; } else { - NS_ASSERTION(iter.GetContainer() == blockFrame, - "Found placeholder in wrong block!"); - nsBlockFrame::line_iterator lineBox = iter.GetLine(); - // How we determine the hypothetical box depends on whether the element // would have been inline-level or block-level if (mStyleDisplay->IsOriginalDisplayInlineOutside()) { @@ -954,10 +951,10 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext* aPresContext, // have been just before this line. // XXXbz the line box is not fully reflowed yet if our // containing block is relatively positioned... - if (lineBox != iter.End()) { + bool allEmpty = true; + if (!lineBox->IsValidCachedIsEmpty() || !lineBox->CachedIsEmpty()) { nsIFrame * firstFrame = lineBox->mFirstChild; bool found = false; - bool allEmpty = true; while (firstFrame) { // See bug 223064 allEmpty = AreAllEarlierInFlowFramesEmpty(firstFrame, aPlaceholderFrame, &found); @@ -966,20 +963,17 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext* aPresContext, firstFrame = firstFrame->GetNextSibling(); } NS_ASSERTION(firstFrame, "Couldn't find placeholder!"); + } - if (allEmpty) { - // The top of the hypothetical box is the top of the line - // containing the placeholder, since there is nothing in the - // line before our placeholder except empty frames. - aHypotheticalBox.mTop = lineBox->mBounds.y + blockYOffset; - } else { - // The top of the hypothetical box is just below the line - // containing the placeholder. - aHypotheticalBox.mTop = lineBox->mBounds.YMost() + blockYOffset; - } + if (allEmpty) { + // The top of the hypothetical box is the top of the line + // containing the placeholder, since there is nothing in the + // line before our placeholder except empty frames. + aHypotheticalBox.mTop = lineBox->mBounds.y + blockYOffset; } else { - // Just use the placeholder's y-offset wrt the containing block - aHypotheticalBox.mTop = placeholderOffset.y; + // The top of the hypothetical box is just below the line + // containing the placeholder. + aHypotheticalBox.mTop = lineBox->mBounds.YMost() + blockYOffset; } } } @@ -1105,9 +1099,10 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext* aPresContext, "Why are we here?"); // Get the placeholder frame - nsIFrame* placeholderFrame; + nsPlaceholderFrame* placeholderFrame; - placeholderFrame = aPresContext->PresShell()->GetPlaceholderFrameFor(frame); + placeholderFrame = + aPresContext->PresShell()->FrameManager()->GetPlaceholderFrameFor(frame); NS_ASSERTION(nsnull != placeholderFrame, "no placeholder frame"); // If both 'left' and 'right' are 'auto' or both 'top' and 'bottom' are diff --git a/layout/generic/nsHTMLReflowState.h b/layout/generic/nsHTMLReflowState.h index 57d9378dd108..fd6445874347 100644 --- a/layout/generic/nsHTMLReflowState.h +++ b/layout/generic/nsHTMLReflowState.h @@ -49,6 +49,7 @@ class nsRenderingContext; class nsFloatManager; class nsLineLayout; class nsIPercentHeightObserver; +class nsPlaceholderFrame; struct nsStyleDisplay; struct nsStyleVisibility; @@ -511,7 +512,7 @@ protected: nscoord& aCBWidth); void CalculateHypotheticalBox(nsPresContext* aPresContext, - nsIFrame* aPlaceholderFrame, + nsPlaceholderFrame* aPlaceholderFrame, nsIFrame* aContainingBlock, nscoord aBlockLeftContentEdge, nscoord aBlockContentWidth, diff --git a/layout/generic/nsLineBox.cpp b/layout/generic/nsLineBox.cpp index 130ddf9f7c6f..f3f00f8a40fa 100644 --- a/layout/generic/nsLineBox.cpp +++ b/layout/generic/nsLineBox.cpp @@ -289,7 +289,7 @@ nsLineBox::IsEmpty() const } bool -nsLineBox::CachedIsEmpty() +nsLineBox::CachedIsEmpty() const { if (mFlags.mDirty) { return IsEmpty(); diff --git a/layout/generic/nsLineBox.h b/layout/generic/nsLineBox.h index b2a8c1df6410..5d727a24f5f0 100644 --- a/layout/generic/nsLineBox.h +++ b/layout/generic/nsLineBox.h @@ -486,14 +486,14 @@ public: // Call this only while in Reflow() for the block the line belongs // to, only between reflowing the line (or sliding it, if we skip // reflowing it) and the end of reflowing the block. - bool CachedIsEmpty(); + bool CachedIsEmpty() const; void InvalidateCachedIsEmpty() { mFlags.mEmptyCacheValid = PR_FALSE; } // For debugging purposes - bool IsValidCachedIsEmpty() { + bool IsValidCachedIsEmpty() const { return mFlags.mEmptyCacheValid; } @@ -514,8 +514,8 @@ public: PRUint32 mLineWrapped: 1; PRUint32 mInvalidateTextRuns : 1; PRUint32 mResizeReflowOptimizationDisabled: 1; // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow - PRUint32 mEmptyCacheValid: 1; - PRUint32 mEmptyCacheState: 1; + mutable PRUint32 mEmptyCacheValid: 1; + mutable PRUint32 mEmptyCacheState: 1; // mHasBullet indicates that this is an inline line whose block's // bullet is adjacent to this line and non-empty. PRUint32 mHasBullet : 1; diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp index cbfb5f1162b1..994d8ee8f162 100644 --- a/layout/generic/nsPlaceholderFrame.cpp +++ b/layout/generic/nsPlaceholderFrame.cpp @@ -145,6 +145,15 @@ nsPlaceholderFrame::Reflow(nsPresContext* aPresContext, aDesiredSize.width = 0; aDesiredSize.height = 0; + // Cache our line box. + mCachedLineBox = nsnull; + if (aReflowState.mLineLayout) { + nsLineList::iterator* line = aReflowState.mLineLayout->GetLine(); + if (line) { + mCachedLineBox = line->get(); + } + } + aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; diff --git a/layout/generic/nsPlaceholderFrame.h b/layout/generic/nsPlaceholderFrame.h index e53d44e5af0d..82e5c4e0246f 100644 --- a/layout/generic/nsPlaceholderFrame.h +++ b/layout/generic/nsPlaceholderFrame.h @@ -69,6 +69,8 @@ #include "nsFrame.h" #include "nsGkAtoms.h" +class nsLineBox; + nsIFrame* NS_NewPlaceholderFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aTypeBit); @@ -200,8 +202,17 @@ public: return outOfFlow; } + // GetCachedLineBox is only OK to call if you're sure this + // placeholder has has Reflow() called since any changes to the + // frame tree that could have affected which line box the + // placeholder is in. + const nsLineBox* GetCachedLineBox() const { + return mCachedLineBox; + } + protected: nsIFrame* mOutOfFlowFrame; + nsLineBox* mCachedLineBox; }; #endif /* nsPlaceholderFrame_h___ */