Bug 743402, Part 2: Pull GetEffectiveComputedHeight() into nsSplittableFrame and refactor it to utilize consumed height for paginated content. [r=roc]

This commit is contained in:
Scott Johnson 2013-07-24 12:47:06 -05:00
Родитель 528cb9f1bf
Коммит 21103de30a
4 изменённых файлов: 117 добавлений и 29 удалений

Просмотреть файл

@ -907,6 +907,9 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
#endif
const nsHTMLReflowState *reflowState = &aReflowState;
nscoord consumedHeight = GetConsumedHeight();
nscoord effectiveComputedHeight = GetEffectiveComputedHeight(aReflowState,
consumedHeight);
Maybe<nsHTMLReflowState> mutableReflowState;
// If we have non-auto height, we're clipping our kids and we fit,
// make sure our kids fit too.
@ -922,7 +925,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
heightExtras.top += aReflowState.mComputedMargin.top;
}
if (GetEffectiveComputedHeight(aReflowState) + heightExtras.TopBottom() <=
if (effectiveComputedHeight + heightExtras.TopBottom() <=
aReflowState.availableHeight) {
mutableReflowState.construct(aReflowState);
mutableReflowState.ref().availableHeight = NS_UNCONSTRAINEDSIZE;
@ -957,8 +960,12 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
bool topMarginRoot, bottomMarginRoot;
IsMarginRoot(&topMarginRoot, &bottomMarginRoot);
// Cache the consumed height in the block reflow state so that we don't have
// to continually recompute it.
nsBlockReflowState state(*reflowState, aPresContext, this,
topMarginRoot, bottomMarginRoot, needFloatManager);
topMarginRoot, bottomMarginRoot, needFloatManager,
consumedHeight);
#ifdef IBMBIDI
if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION)
@ -7078,26 +7085,6 @@ nsBlockFrame::GetNearestAncestorBlock(nsIFrame* aCandidate)
return nullptr;
}
nscoord
nsBlockFrame::GetEffectiveComputedHeight(const nsHTMLReflowState& aReflowState) const
{
nscoord height = aReflowState.ComputedHeight();
NS_ABORT_IF_FALSE(height != NS_UNCONSTRAINEDSIZE, "Don't call me!");
if (GetPrevInFlow()) {
// Reduce the height by the computed height of prev-in-flows.
for (nsIFrame* prev = GetPrevInFlow(); prev; prev = prev->GetPrevInFlow()) {
height -= prev->GetRect().height;
}
// We just subtracted our top-border padding, since it was included in the
// first frame's height. Add it back to get the content height.
height += aReflowState.mComputedBorderPadding.top;
// We may have stretched the frame beyond its computed height. Oh well.
height = std::max(0, height);
}
return height;
}
#ifdef IBMBIDI
nsresult
nsBlockFrame::ResolveBidi()

Просмотреть файл

@ -796,13 +796,6 @@ protected:
void SetOverflowLines(FrameLines* aOverflowLines);
void DestroyOverflowLines();
// Determine the computed height that's in effect for this block
// frame (that is, our computed height minus the heights of our
// previous in-flows).
// XXXbz this clearly makes laying out a block with N in-flows
// O(N^2)! Good thing the constant is tiny.
nscoord GetEffectiveComputedHeight(const nsHTMLReflowState& aReflowState) const;
/**
* This class is useful for efficiently modifying the out of flow
* overflow list. It gives the client direct writable access to

Просмотреть файл

@ -12,6 +12,7 @@
#include "nsIContent.h"
#include "nsPresContext.h"
#include "nsStyleContext.h"
#include "nsContainerFrame.h"
NS_IMPL_FRAMEARENA_HELPERS(nsSplittableFrame)
@ -216,6 +217,80 @@ nsSplittableFrame::GetConsumedHeight() const
return height;
}
nscoord
nsSplittableFrame::GetEffectiveComputedHeight(const nsHTMLReflowState& aReflowState,
nscoord aConsumedHeight) const
{
nscoord height = aReflowState.ComputedHeight();
if (height == NS_INTRINSICSIZE) {
return NS_INTRINSICSIZE;
}
if (aConsumedHeight == NS_INTRINSICSIZE) {
aConsumedHeight = GetConsumedHeight();
}
height -= aConsumedHeight;
if (aConsumedHeight != NS_INTRINSICSIZE) {
// We just subtracted our top-border padding, since it was included in the
// first frame's height. Add it back to get the content height.
height += aReflowState.mComputedBorderPadding.top;
}
// We may have stretched the frame beyond its computed height. Oh well.
height = std::max(0, height);
return height;
}
void
nsSplittableFrame::ComputeFinalHeight(const nsHTMLReflowState& aReflowState,
nsReflowStatus* aStatus,
nscoord aContentHeight,
const nsMargin& aBorderPadding,
nsHTMLReflowMetrics& aMetrics,
nscoord aConsumed)
{
// Figure out how much of the computed height should be
// applied to this frame.
nscoord computedHeightLeftOver = GetEffectiveComputedHeight(aReflowState,
aConsumed);
NS_ASSERTION(!( IS_TRUE_OVERFLOW_CONTAINER(this)
&& computedHeightLeftOver ),
"overflow container must not have computedHeightLeftOver");
aMetrics.height =
NSCoordSaturatingAdd(NSCoordSaturatingAdd(aBorderPadding.top,
computedHeightLeftOver),
aBorderPadding.bottom);
if (NS_FRAME_IS_NOT_COMPLETE(*aStatus)
&& aMetrics.height < aReflowState.availableHeight) {
// We ran out of height on this page but we're incomplete
// Set status to complete except for overflow
NS_FRAME_SET_OVERFLOW_INCOMPLETE(*aStatus);
}
if (NS_FRAME_IS_COMPLETE(*aStatus)) {
if (computedHeightLeftOver > 0 &&
NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight &&
aMetrics.height > aReflowState.availableHeight) {
// We don't fit and we consumed some of the computed height,
// so we should consume all the available height and then
// break. If our bottom border/padding straddles the break
// point, then this will increase our height and push the
// border/padding to the next page/column.
aMetrics.height = std::max(aReflowState.availableHeight,
aContentHeight);
NS_FRAME_SET_INCOMPLETE(*aStatus);
if (!GetNextInFlow())
*aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
}
}
}
#ifdef DEBUG
void
nsSplittableFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)

Просмотреть файл

@ -85,6 +85,39 @@ protected:
*/
nscoord GetConsumedHeight() const;
/**
* Retrieve the effective computed height of this frame, which is the computed
* height, minus the height consumed by any previous in-flows.
*/
nscoord GetEffectiveComputedHeight(const nsHTMLReflowState& aReflowState,
nscoord aConsumed = NS_INTRINSICSIZE) const;
/**
* Compute the final height of this frame.
*
* @param aReflowState Data structure passed from parent during reflow.
* @param aReflowStatus A pointed to the reflow status for when we're finished
* doing reflow. this will get set appropriately if the height causes
* us to exceed the current available (page) height.
* @param aContentHeight The height of content, precomputed outside of this
* function. The final height that is used in aMetrics will be set to
* either this or the available height, whichever is larger, in the
* case where our available height is constrained, and we overflow that
* available height.
* @param aBorderPadding The margins representing the border padding for block
* frames. Can be 0.
* @param aMetrics Out parameter for final height. Taken as an
* nsHTMLReflowMetrics object so that aMetrics can be passed in
* directly during reflow.
* @param aConsumed The height already consumed by our previous-in-flows.
*/
void ComputeFinalHeight(const nsHTMLReflowState& aReflowState,
nsReflowStatus* aStatus,
nscoord aContentHeight,
const nsMargin& aBorderPadding,
nsHTMLReflowMetrics& aMetrics,
nscoord aConsumed);
#ifdef DEBUG
virtual void DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent) MOZ_OVERRIDE;
#endif