Bug 1323517 Part 5 - Improve the available size computation for reflowing a float. r=jfkthame

First of all, `nsBlockFrame::AdjustFloatAvailableSpace()` is misleading. It
doesn't adjust the argument `aFloatAvailableSpace` at all, nor does it use any
fields in nsBlockFrame. It simply returns the available space in the parent
block's content area. Thus, I move it into BlockReflowState, and have it return
the available size rather than a rect because a size is sufficient for reflowing
a float.

Also, nsBlockFrame::ReflowFloat() only cares about the available size, but not
the position of the available space, so it is sufficient to pass a LogicalSize
computed by the new method ComputeAvailableSizeForFloat().

In FlowAndPlaceFloat(), there is a loop searching for a wide enough band to
place the float. We don't need to adjust availSize every time mBCoord is changed
in the loop. We can just call ComputeAvailableSizeForFloat() to get a new
available size before reflowing the float in the `!earlyFloatReflow` branch.

This patch shouldn't change the behavior.

Differential Revision: https://phabricator.services.mozilla.com/D151207
This commit is contained in:
Ting-Yu Lin 2022-07-07 19:01:56 +00:00
parent 70e03e7368
commit 48a466967c
4 changed files with 40 additions and 57 deletions

View File

@ -265,6 +265,14 @@ LogicalRect BlockReflowState::ComputeBlockAvailSpace(
return result;
}
LogicalSize BlockReflowState::ComputeAvailableSizeForFloat() const {
const auto wm = mReflowInput.GetWritingMode();
const nscoord availBSize = ContentBSize() == NS_UNCONSTRAINEDSIZE
? NS_UNCONSTRAINEDSIZE
: std::max(0, ContentBEnd() - mBCoord);
return LogicalSize(wm, ContentISize(), availBSize);
}
bool BlockReflowState::FloatAvoidingBlockFitsInAvailSpace(
nsIFrame* aFloatAvoidingBlock,
const nsFlowAreaRect& aFloatAvailableSpace) const {
@ -735,17 +743,12 @@ bool BlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) {
mBCoord = bCoord;
}
// Get the band of available space with respect to margin box.
nsFlowAreaRect floatAvailableSpace =
GetFloatAvailableSpaceForPlacingFloat(mBCoord);
LogicalRect adjustedAvailableSpace =
mBlock->AdjustFloatAvailableSpace(*this, floatAvailableSpace.mRect);
LogicalSize availSize = ComputeAvailableSizeForFloat();
SizeComputationInput sizingInput(aFloat, mReflowInput.mRenderingContext, wm,
mReflowInput.ComputedISize());
nscoord floatMarginISize = FloatMarginISize(
mReflowInput, adjustedAvailableSpace.ISize(wm), aFloat, sizingInput);
nscoord floatMarginISize =
FloatMarginISize(mReflowInput, availSize.ISize(wm), aFloat, sizingInput);
LogicalMargin floatMargin(wm); // computed margin
LogicalMargin floatOffsets(wm);
@ -760,8 +763,8 @@ bool BlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) {
bool earlyFloatReflow =
aFloat->IsLetterFrame() || floatMarginISize == NS_UNCONSTRAINEDSIZE;
if (earlyFloatReflow) {
mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, floatMargin,
floatOffsets, false, reflowStatus);
mBlock->ReflowFloat(*this, availSize, aFloat, floatMargin, floatOffsets,
false, reflowStatus);
floatMarginISize = aFloat->ISize(wm) + floatMargin.IStartEnd(wm);
NS_ASSERTION(reflowStatus.IsComplete(),
"letter frames and orthogonal floats with auto block-size "
@ -782,6 +785,10 @@ bool BlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) {
bool mustPlaceFloat =
mReflowInput.mFlags.mIsTopOfPage && IsAdjacentWithBStart();
// Get the band of available space with respect to margin box.
nsFlowAreaRect floatAvailableSpace =
GetFloatAvailableSpaceForPlacingFloat(mBCoord);
for (;;) {
if (mReflowInput.AvailableHeight() != NS_UNCONSTRAINEDSIZE &&
floatAvailableSpace.mRect.BSize(wm) <= 0 && !mustPlaceFloat) {
@ -797,9 +804,6 @@ bool BlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) {
// Nope. try to advance to the next band.
mBCoord += floatAvailableSpace.mRect.BSize(wm);
if (adjustedAvailableSpace.BSize(wm) != NS_UNCONSTRAINEDSIZE) {
adjustedAvailableSpace.BSize(wm) -= floatAvailableSpace.mRect.BSize(wm);
}
floatAvailableSpace = GetFloatAvailableSpaceForPlacingFloat(mBCoord);
mustPlaceFloat = false;
}
@ -832,8 +836,8 @@ bool BlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) {
// where to break.
if (!earlyFloatReflow) {
bool pushedDown = mBCoord != restoreBCoord.SavedValue();
mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, floatMargin,
floatOffsets, pushedDown, reflowStatus);
mBlock->ReflowFloat(*this, ComputeAvailableSizeForFloat(), aFloat,
floatMargin, floatOffsets, pushedDown, reflowStatus);
}
if (aFloat->GetPrevInFlow()) {
floatMargin.BStart(wm) = 0;

View File

@ -219,6 +219,8 @@ class BlockReflowState {
const nsFlowAreaRect& aFloatAvailableSpace,
bool aBlockAvoidsFloats);
LogicalSize ComputeAvailableSizeForFloat() const;
void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaBCoord);
void AdvanceToNextLine() {

View File

@ -6613,41 +6613,23 @@ const nsStyleText* nsBlockFrame::StyleTextForLineLayout() {
return StyleText();
}
////////////////////////////////////////////////////////////////////////
// Float support
LogicalRect nsBlockFrame::AdjustFloatAvailableSpace(
BlockReflowState& aState, const LogicalRect& aFloatAvailableSpace) {
WritingMode wm = aState.mReflowInput.GetWritingMode();
nscoord availBSize = NS_UNCONSTRAINEDSIZE == aState.ContentBSize()
? NS_UNCONSTRAINEDSIZE
: std::max(0, aState.ContentBEnd() - aState.mBCoord);
return LogicalRect(wm, aState.ContentIStart(), aState.ContentBStart(),
aState.ContentISize(), availBSize);
}
nscoord nsBlockFrame::ComputeFloatISize(BlockReflowState& aState,
const LogicalRect& aFloatAvailableSpace,
nsIFrame* aFloat) {
MOZ_ASSERT(aFloat->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW),
"aFloat must be an out-of-flow frame");
// Reflow the float.
LogicalRect availSpace =
AdjustFloatAvailableSpace(aState, aFloatAvailableSpace);
LogicalSize availSize = aState.ComputeAvailableSizeForFloat();
WritingMode blockWM = aState.mReflowInput.GetWritingMode();
WritingMode floatWM = aFloat->GetWritingMode();
ReflowInput floatRS(aState.mPresContext, aState.mReflowInput, aFloat,
availSpace.Size(blockWM).ConvertTo(floatWM, blockWM));
availSize.ConvertTo(floatWM, blockWM));
return floatRS.ComputedSizeWithMarginBorderPadding(blockWM).ISize(blockWM);
}
void nsBlockFrame::ReflowFloat(BlockReflowState& aState,
const LogicalRect& aAdjustedAvailableSpace,
const LogicalSize& aAvailableSize,
nsIFrame* aFloat, LogicalMargin& aFloatMargin,
LogicalMargin& aFloatOffsets,
bool aFloatPushedDown,
@ -6659,17 +6641,15 @@ void nsBlockFrame::ReflowFloat(BlockReflowState& aState,
WritingMode wm = aState.mReflowInput.GetWritingMode();
ReflowInput floatRS(
aState.mPresContext, aState.mReflowInput, aFloat,
aAdjustedAvailableSpace.Size(wm).ConvertTo(aFloat->GetWritingMode(), wm));
ReflowInput floatRS(aState.mPresContext, aState.mReflowInput, aFloat,
aAvailableSize.ConvertTo(aFloat->GetWritingMode(), wm));
// Normally the mIsTopOfPage state is copied from the parent reflow
// input. However, when reflowing a float, if we've placed other
// floats that force this float *down* or *narrower*, we should unset
// the mIsTopOfPage state.
if (floatRS.mFlags.mIsTopOfPage &&
(aFloatPushedDown ||
aAdjustedAvailableSpace.ISize(wm) != aState.ContentISize())) {
(aFloatPushedDown || aAvailableSize.ISize(wm) != aState.ContentISize())) {
floatRS.mFlags.mIsTopOfPage = false;
}
@ -6712,7 +6692,7 @@ void nsBlockFrame::ReflowFloat(BlockReflowState& aState,
if (!aReflowStatus.IsFullyComplete() && ShouldAvoidBreakInside(floatRS)) {
aReflowStatus.SetInlineLineBreakBeforeAndReset();
} else if (aReflowStatus.IsIncomplete() &&
(NS_UNCONSTRAINEDSIZE == aAdjustedAvailableSpace.BSize(wm))) {
aAvailableSize.BSize(wm) == NS_UNCONSTRAINEDSIZE) {
// An incomplete reflow status means we should split the float
// if the height is constrained (bug 145305).
aReflowStatus.Reset();

View File

@ -778,26 +778,23 @@ class nsBlockFrame : public nsContainerFrame {
LineIterator aLine, nsIFrame* aFrame,
LineReflowStatus* aLineReflowStatus);
// Compute the available size for a float.
mozilla::LogicalRect AdjustFloatAvailableSpace(
BlockReflowState& aState,
const mozilla::LogicalRect& aFloatAvailableSpace);
// Computes the border-box inline size of the float
nscoord ComputeFloatISize(BlockReflowState& aState,
const mozilla::LogicalRect& aFloatAvailableSpace,
nsIFrame* aFloat);
// An incomplete aReflowStatus indicates the float should be split
// but only if the available height is constrained.
// aAdjustedAvailableSpace is the result of calling
// nsBlockFrame::AdjustFloatAvailableSpace.
// @param aAvailableSize the result of
// BlockReflowState::ComputeAvailableSizeForFloat().
// @param aFloatPushedDown whether the block-direction position available to
// place a float has been pushed down due to the presence of other
// floats.
// @param aReflowStatus an incomplete status indicates the float should be
// split but only if the available block-size is constrained.
void ReflowFloat(BlockReflowState& aState,
const mozilla::LogicalRect& aAdjustedAvailableSpace,
nsIFrame* aFloat, mozilla::LogicalMargin& aFloatMargin,
mozilla::LogicalMargin& aFloatOffsets,
// Whether the float's position
// (aAdjustedAvailableSpace) has been pushed down
// due to the presence of other floats.
bool aFloatPushedDown, nsReflowStatus& aReflowStatus);
const mozilla::LogicalSize& aAvailableSize, nsIFrame* aFloat,
mozilla::LogicalMargin& aFloatMargin,
mozilla::LogicalMargin& aFloatOffsets, bool aFloatPushedDown,
nsReflowStatus& aReflowStatus);
//----------------------------------------
// Methods for pushing/pulling lines/frames