From 528cb9f1bf8d3a33a86a7e858ec41615c5b17275 Mon Sep 17 00:00:00 2001 From: Scott Johnson Date: Wed, 24 Jul 2013 12:47:01 -0500 Subject: [PATCH] Bug 743402, Part 1: Add a GetConsumedHeight() function to nsSplittableFrame in order to retrieve the portion of the computed height that was consumed by previous-in-flows. [r=roc] --- layout/generic/nsBlockReflowState.cpp | 16 ++++++++++++++-- layout/generic/nsBlockReflowState.h | 11 ++++++++++- layout/generic/nsHTMLReflowState.h | 17 +++++++++++++++-- layout/generic/nsSplittableFrame.cpp | 13 +++++++++++++ layout/generic/nsSplittableFrame.h | 9 +++++++++ 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index 78b65045dcb5..2919629265d3 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -35,7 +35,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, nsBlockFrame* aFrame, bool aTopMarginRoot, bool aBottomMarginRoot, - bool aBlockNeedsFloatManager) + bool aBlockNeedsFloatManager, + nscoord aConsumedHeight) : mBlock(aFrame), mPresContext(aPresContext), mReflowState(aReflowState), @@ -44,7 +45,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mPrevBottomMargin(), mLineNumber(0), mFlags(0), - mFloatBreakType(NS_STYLE_CLEAR_NONE) + mFloatBreakType(NS_STYLE_CLEAR_NONE), + mConsumedHeight(aConsumedHeight) { SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nullptr); SetFlag(BRS_ISOVERFLOWCONTAINER, @@ -113,6 +115,16 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mMinLineHeight = aReflowState.CalcLineHeight(); } +nscoord +nsBlockReflowState::GetConsumedHeight() +{ + if (mConsumedHeight == NS_INTRINSICSIZE) { + mConsumedHeight = mBlock->GetConsumedHeight(); + } + + return mConsumedHeight; +} + void nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame, const nsRect& aFloatAvailableSpace, diff --git a/layout/generic/nsBlockReflowState.h b/layout/generic/nsBlockReflowState.h index 1a000f6698a3..881586adcefd 100644 --- a/layout/generic/nsBlockReflowState.h +++ b/layout/generic/nsBlockReflowState.h @@ -40,7 +40,8 @@ public: nsPresContext* aPresContext, nsBlockFrame* aFrame, bool aTopMarginRoot, bool aBottomMarginRoot, - bool aBlockNeedsFloatManager); + bool aBlockNeedsFloatManager, + nscoord aConsumedHeight = NS_INTRINSICSIZE); /** * Get the available reflow space (the area not occupied by floats) @@ -110,6 +111,11 @@ public: return result; } + /** + * Retrieve the height "consumed" by any previous-in-flows. + */ + nscoord GetConsumedHeight(); + // Reconstruct the previous bottom margin that goes above |aLine|. void ReconstructMarginAbove(nsLineList::iterator aLine); @@ -257,6 +263,9 @@ public: uint8_t mFloatBreakType; + // The amount of computed height "consumed" by previous-in-flows. + nscoord mConsumedHeight; + void SetFlag(uint32_t aFlag, bool aValue) { NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag"); diff --git a/layout/generic/nsHTMLReflowState.h b/layout/generic/nsHTMLReflowState.h index 69fd6a3917ca..388ea91dc2cc 100644 --- a/layout/generic/nsHTMLReflowState.h +++ b/layout/generic/nsHTMLReflowState.h @@ -480,15 +480,28 @@ public: } return std::max(aWidth, mComputedMinWidth); } + /** * Apply the mComputed(Min/Max)Height constraints to the content * size computed so far. + * + * @param aHeight The height that we've computed an to which we want to apply + * min/max constraints. + * @param aConsumed The amount of the computed height that was consumed by + * our prev-in-flows. */ - nscoord ApplyMinMaxHeight(nscoord aHeight) const { + nscoord ApplyMinMaxHeight(nscoord aHeight, nscoord aConsumed = 0) const { + aHeight += aConsumed; + if (NS_UNCONSTRAINEDSIZE != mComputedMaxHeight) { aHeight = std::min(aHeight, mComputedMaxHeight); } - return std::max(aHeight, mComputedMinHeight); + + if (NS_UNCONSTRAINEDSIZE != mComputedMinHeight) { + aHeight = std::max(aHeight, mComputedMinHeight); + } + + return aHeight - aConsumed; } bool ShouldReflowAllKids() const { diff --git a/layout/generic/nsSplittableFrame.cpp b/layout/generic/nsSplittableFrame.cpp index 22d842d8914e..44cd2f8a97f9 100644 --- a/layout/generic/nsSplittableFrame.cpp +++ b/layout/generic/nsSplittableFrame.cpp @@ -203,6 +203,19 @@ nsSplittableFrame::RemoveFromFlow(nsIFrame* aFrame) aFrame->SetNextInFlow(nullptr); } +nscoord +nsSplittableFrame::GetConsumedHeight() const +{ + nscoord height = 0; + + // Reduce the height by the computed height of prev-in-flows. + for (nsIFrame* prev = GetPrevInFlow(); prev; prev = prev->GetPrevInFlow()) { + height += prev->GetRect().height; + } + + return height; +} + #ifdef DEBUG void nsSplittableFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent) diff --git a/layout/generic/nsSplittableFrame.h b/layout/generic/nsSplittableFrame.h index 1ed3a556c99b..d7df231ee2e9 100644 --- a/layout/generic/nsSplittableFrame.h +++ b/layout/generic/nsSplittableFrame.h @@ -76,6 +76,15 @@ public: protected: nsSplittableFrame(nsStyleContext* aContext) : nsFrame(aContext) {} + /** + * Determine the height consumed by our previous-in-flows. + * + * @note (bz) This makes laying out a splittable frame with N in-flows + * O(N^2)! So, use this function with caution and minimize the number + * of calls to this method. + */ + nscoord GetConsumedHeight() const; + #ifdef DEBUG virtual void DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent) MOZ_OVERRIDE; #endif