Bug 1079139: make nsFlowAreaRect.mRect a LogicalRect. r=jfkthame

This commit is contained in:
Simon Montagu 2014-10-21 15:16:13 -07:00
parent b3b5a2204e
commit 8d64967541
11 changed files with 374 additions and 321 deletions

View File

@ -906,17 +906,20 @@ nsBlockFrame::GetPrefWidthTightBounds(nsRenderingContext* aRenderingContext,
}
static bool
AvailableSpaceShrunk(const nsRect& aOldAvailableSpace,
const nsRect& aNewAvailableSpace)
AvailableSpaceShrunk(WritingMode aWM,
const LogicalRect& aOldAvailableSpace,
const LogicalRect& aNewAvailableSpace)
{
if (aNewAvailableSpace.width == 0) {
// Positions are not significant if the width is zero.
return aOldAvailableSpace.width != 0;
if (aNewAvailableSpace.ISize(aWM) == 0) {
// Positions are not significant if the inline size is zero.
return aOldAvailableSpace.ISize(aWM) != 0;
}
NS_ASSERTION(aOldAvailableSpace.x <= aNewAvailableSpace.x &&
aOldAvailableSpace.XMost() >= aNewAvailableSpace.XMost(),
NS_ASSERTION(aOldAvailableSpace.IStart(aWM) <=
aNewAvailableSpace.IStart(aWM) &&
aOldAvailableSpace.IEnd(aWM) >=
aNewAvailableSpace.IEnd(aWM),
"available space should never grow");
return aOldAvailableSpace.width != aNewAvailableSpace.width;
return aOldAvailableSpace.ISize(aWM) != aNewAvailableSpace.ISize(aWM);
}
static LogicalSize
@ -1813,17 +1816,17 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
* Propagate reflow "damage" from from earlier lines to the current
* line. The reflow damage comes from the following sources:
* 1. The regions of float damage remembered during reflow.
* 2. The combination of nonzero |aDeltaY| and any impact by a float,
* either the previous reflow or now.
* 2. The combination of nonzero |aDeltaBCoord| and any impact by a
* float, either the previous reflow or now.
*
* When entering this function, |aLine| is still at its old position and
* |aDeltaY| indicates how much it will later be slid (assuming it
* |aDeltaBCoord| indicates how much it will later be slid (assuming it
* doesn't get marked dirty and reflowed entirely).
*/
void
nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState,
nsLineBox* aLine,
nscoord aDeltaY)
nscoord aDeltaBCoord)
{
nsFloatManager *floatManager = aState.mReflowState.mFloatManager;
NS_ASSERTION((aState.mReflowState.parentReflowState &&
@ -1839,23 +1842,35 @@ nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState,
if (floatManager->HasFloatDamage()) {
// Need to check mBounds *and* mCombinedArea to find intersections
// with aLine's floats
nscoord lineYA = aLine->BStart() + aDeltaY;
nscoord lineYB = lineYA + aLine->BSize();
nscoord lineBCoordBefore = aLine->BStart() + aDeltaBCoord;
nscoord lineBCoordAfter = lineBCoordBefore + aLine->BSize();
// Scrollable overflow should be sufficient for things that affect
// layout.
nsRect overflow = aLine->GetOverflowArea(eScrollableOverflow);
nscoord lineYCombinedA = overflow.y + aDeltaY;
nscoord lineYCombinedB = lineYCombinedA + overflow.height;
WritingMode wm = aState.mReflowState.GetWritingMode();
if (floatManager->IntersectsDamage(wm, lineYA, lineYB) ||
floatManager->IntersectsDamage(wm, lineYCombinedA, lineYCombinedB)) {
nscoord containerWidth = aState.mContainerWidth;
LogicalRect overflow = aLine->GetOverflowArea(eScrollableOverflow, wm,
containerWidth);
nscoord lineBCoordCombinedBefore = overflow.BStart(wm) + aDeltaBCoord;
nscoord lineBCoordCombinedAfter = lineBCoordCombinedBefore +
overflow.BSize(wm);
// "Translate" the float manager with an offset of (0, 0) in order to
// set the origin to our writing mode
LogicalPoint oPt(wm);
WritingMode oldWM = floatManager->Translate(wm, oPt, containerWidth);
bool isDirty = floatManager->IntersectsDamage(wm, lineBCoordBefore,
lineBCoordAfter) ||
floatManager->IntersectsDamage(wm, lineBCoordCombinedBefore,
lineBCoordCombinedAfter);
floatManager->Untranslate(oldWM, oPt, containerWidth);
if (isDirty) {
aLine->MarkDirty();
return;
}
}
// Check if the line is moving relative to the float manager
if (aDeltaY + aState.mReflowState.mBlockDelta != 0) {
if (aDeltaBCoord + aState.mReflowState.mBlockDelta != 0) {
if (aLine->IsBlock()) {
// Unconditionally reflow sliding blocks; we only really need to reflow
// if there's a float impacting this block, but the current float manager
@ -1865,7 +1880,7 @@ nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState,
} else {
bool wasImpactedByFloat = aLine->IsImpactedByFloat();
nsFlowAreaRect floatAvailableSpace =
aState.GetFloatAvailableSpaceForBSize(aLine->BStart() + aDeltaY,
aState.GetFloatAvailableSpaceForBSize(aLine->BStart() + aDeltaBCoord,
aLine->BSize(),
nullptr);
@ -1912,7 +1927,7 @@ nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent,
}
static void DumpLine(const nsBlockReflowState& aState, nsLineBox* aLine,
nscoord aDeltaY, int32_t aDeltaIndent) {
nscoord aDeltaBCoord, int32_t aDeltaIndent) {
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow) {
nsRect ovis(aLine->GetVisualOverflowArea());
@ -1925,7 +1940,7 @@ static void DumpLine(const nsBlockReflowState& aState, nsLineBox* aLine,
aLine->ISize(), aLine->BSize(),
ovis.x, ovis.y, ovis.width, ovis.height,
oscr.x, oscr.y, oscr.width, oscr.height,
aDeltaY, aState.mPrevBEndMargin.get(), aLine->GetChildCount());
aDeltaBCoord, aState.mPrevBEndMargin.get(), aLine->GetChildCount());
}
#endif
}
@ -3136,7 +3151,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
aLine.get(), floatAvailableSpace.mHasFloats?"true":"false");
#endif
aLine->SetLineIsImpactedByFloat(floatAvailableSpace.mHasFloats);
nsRect availSpace;
WritingMode wm = aState.mReflowState.GetWritingMode();
LogicalRect availSpace(wm);
aState.ComputeBlockAvailSpace(frame, display, floatAvailableSpace,
replacedBlock != nullptr, availSpace);
@ -3146,7 +3162,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// margins at the top of the page as we ought to, it wouldn't be
// needed.
if ((!aState.mReflowState.mFlags.mIsTopOfPage || clearedFloats) &&
availSpace.height < 0) {
availSpace.BSize(wm) < 0) {
// We know already that this child block won't fit on this
// page/column due to the top margin or the clearance. So we need
// to get out of here now. (If we don't, most blocks will handle
@ -3154,9 +3170,9 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// won't, and will thus make their parent overly-large and force
// *it* to be pushed in its entirety.)
// Doing this means that we also don't need to worry about the
// |availSpace.height += bStartMargin| below interacting with pushed
// floats (which force nscoord_MAX clearance) to cause a
// constrained height to turn into an unconstrained one.
// |availSpace.BSize(wm) += bStartMargin| below interacting with
// pushed floats (which force nscoord_MAX clearance) to cause a
// constrained block size to turn into an unconstrained one.
aState.mBCoord = startingBCoord;
aState.mPrevBEndMargin = incomingMargin;
*aKeepReflowGoing = false;
@ -3169,12 +3185,12 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
return;
}
// Now put the Y coordinate back to the top of the top-margin +
// clearance, and flow the block.
// Now put the block-dir coordinate back to the start of the
// block-start-margin + clearance, and flow the block.
aState.mBCoord -= bStartMargin;
availSpace.y -= bStartMargin;
if (NS_UNCONSTRAINEDSIZE != availSpace.height) {
availSpace.height += bStartMargin;
availSpace.BStart(wm) -= bStartMargin;
if (NS_UNCONSTRAINEDSIZE != availSpace.BSize(wm)) {
availSpace.BSize(wm) += bStartMargin;
}
// Reflow the block into the available space
@ -3182,7 +3198,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// will initialize it
nsHTMLReflowState
blockHtmlRS(aState.mPresContext, aState.mReflowState, frame,
LogicalSize(frame->GetWritingMode(), availSpace.Size()));
availSpace.Size(wm).ConvertTo(frame->GetWritingMode(), wm));
blockHtmlRS.mFlags.mHasClearance = aLine->HasClearance();
nsFloatManager::SavedState
@ -3544,9 +3560,11 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
this, aFloatAvailableSpace.mHasFloats);
#endif
WritingMode outerWM = aState.mReflowState.GetWritingMode();
WritingMode lineWM = GetWritingMode(aLine->mFirstChild);
LogicalRect lineRect(lineWM, aFloatAvailableSpace.mRect,
aState.mContainerWidth);
LogicalRect lineRect =
aFloatAvailableSpace.mRect.ConvertTo(lineWM, outerWM,
aState.mContainerWidth);
nscoord iStart = lineRect.IStart(lineWM);
nscoord availISize = lineRect.ISize(lineWM);
@ -3683,11 +3701,12 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
//
// What we do is to advance past the first float we find and
// then reflow the line all over again.
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aFloatAvailableSpace.mRect.height,
"unconstrained height on totally empty line");
NS_ASSERTION(NS_UNCONSTRAINEDSIZE !=
aFloatAvailableSpace.mRect.BSize(outerWM),
"unconstrained block size on totally empty line");
// See the analogous code for blocks in nsBlockReflowState::ClearFloats.
if (aFloatAvailableSpace.mRect.height > 0) {
if (aFloatAvailableSpace.mRect.BSize(outerWM) > 0) {
NS_ASSERTION(aFloatAvailableSpace.mHasFloats,
"redo line on totally empty line with non-empty band...");
// We should never hit this case if we've placed floats on the
@ -3695,7 +3714,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// and needs to happen after the caller pops the space manager
// state.
aState.mFloatManager->AssertStateMatches(aFloatStateBeforeLine);
aState.mBCoord += aFloatAvailableSpace.mRect.height;
aState.mBCoord += aFloatAvailableSpace.mRect.BSize(outerWM);
aFloatAvailableSpace = aState.GetFloatAvailableSpace();
} else {
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mReflowState.AvailableBSize(),
@ -4114,7 +4133,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
line_iterator aLine,
nsFloatManager::SavedState *aFloatStateBeforeLine,
nsRect& aFloatAvailableSpace,
LogicalRect& aFloatAvailableSpace,
nscoord& aAvailableSpaceHeight,
bool* aKeepReflowGoing)
{
@ -4130,6 +4149,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
// There are exactly two places a bullet can be placed: near the
// first or second line. It's only placed on the second line in a
// rare case: when the first line is empty.
WritingMode wm = aState.mReflowState.GetWritingMode();
bool addedBullet = false;
if (HasOutsideBullet() &&
((aLine == mLines.front() &&
@ -4140,8 +4160,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
nsHTMLReflowMetrics metrics(aState.mReflowState);
nsIFrame* bullet = GetOutsideBullet();
ReflowBullet(bullet, aState, metrics, aState.mBCoord);
NS_ASSERTION(!BulletIsEmpty() ||
metrics.BSize(aState.mReflowState.GetWritingMode()) == 0,
NS_ASSERTION(!BulletIsEmpty() || metrics.BSize(wm) == 0,
"empty bullet took up space");
aLineLayout.AddBulletFrame(bullet, metrics);
addedBullet = true;
@ -4153,7 +4172,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
// Floats that are in the line are handled during line reflow (and may
// result in floats being pushed to below the line or (I HOPE???) in a
// reflow with a forced break position).
nsRect oldFloatAvailableSpace(aFloatAvailableSpace);
LogicalRect oldFloatAvailableSpace(aFloatAvailableSpace);
// As we redo for floats, we can't reduce the amount of height we're
// checking.
aAvailableSpaceHeight = std::max(aAvailableSpaceHeight, aLine->BSize());
@ -4161,13 +4180,14 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
aState.GetFloatAvailableSpaceForBSize(aLine->BStart(),
aAvailableSpaceHeight,
aFloatStateBeforeLine).mRect;
NS_ASSERTION(aFloatAvailableSpace.y == oldFloatAvailableSpace.y, "yikes");
NS_ASSERTION(aFloatAvailableSpace.BStart(wm) ==
oldFloatAvailableSpace.BStart(wm), "yikes");
// Restore the height to the position of the next band.
aFloatAvailableSpace.height = oldFloatAvailableSpace.height;
aFloatAvailableSpace.BSize(wm) = oldFloatAvailableSpace.BSize(wm);
// If the available space between the floats is smaller now that we
// know the height, return false (and cause another pass with
// LINE_REFLOW_REDO_MORE_FLOATS).
if (AvailableSpaceShrunk(oldFloatAvailableSpace, aFloatAvailableSpace)) {
if (AvailableSpaceShrunk(wm, oldFloatAvailableSpace, aFloatAvailableSpace)) {
return false;
}
@ -5717,15 +5737,16 @@ nsBlockFrame::StyleTextForLineLayout()
////////////////////////////////////////////////////////////////////////
// Float support
nsRect
LogicalRect
nsBlockFrame::AdjustFloatAvailableSpace(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
const LogicalRect& aFloatAvailableSpace,
nsIFrame* aFloatFrame)
{
// Compute the available width. By default, assume the width of the
// containing block.
// Compute the available inline size. By default, assume the inline
// size of the containing block.
nscoord availISize;
const nsStyleDisplay* floatDisplay = aFloatFrame->StyleDisplay();
WritingMode wm = aState.mReflowState.GetWritingMode();
if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
eCompatibility_NavQuirks != aState.mPresContext->CompatibilityMode() ) {
@ -5736,7 +5757,7 @@ nsBlockFrame::AdjustFloatAvailableSpace(nsBlockReflowState& aState,
// give tables only the available space
// if they can shrink we may not be constrained to place
// them in the next line
availISize = aFloatAvailableSpace.width;
availISize = aFloatAvailableSpace.ISize(wm);
}
nscoord availBSize = NS_UNCONSTRAINEDSIZE == aState.ContentBSize()
@ -5754,39 +5775,37 @@ nsBlockFrame::AdjustFloatAvailableSpace(nsBlockReflowState& aState,
}
#endif
WritingMode wm = aState.mReflowState.GetWritingMode();
LogicalRect availSpace(wm, aState.ContentIStart(), aState.ContentBStart(),
availISize, availBSize);
// for now return a physical rect
return availSpace.GetPhysicalRect(wm, aState.mContainerWidth);
return LogicalRect(wm, aState.ContentIStart(), aState.ContentBStart(),
availISize, availBSize);
}
nscoord
nsBlockFrame::ComputeFloatWidth(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsBlockFrame::ComputeFloatISize(nsBlockReflowState& aState,
const LogicalRect& aFloatAvailableSpace,
nsIFrame* aFloat)
{
NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
"aFloat must be an out-of-flow frame");
// Reflow the float.
nsRect availSpace = AdjustFloatAvailableSpace(aState, aFloatAvailableSpace,
aFloat);
LogicalRect availSpace = AdjustFloatAvailableSpace(aState,
aFloatAvailableSpace,
aFloat);
WritingMode wm = aFloat->GetWritingMode();
nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState, aFloat,
LogicalSize(wm, availSpace.Size()));
WritingMode blockWM = aState.mReflowState.GetWritingMode();
WritingMode floatWM = aFloat->GetWritingMode();
nsHTMLReflowState
floatRS(aState.mPresContext, aState.mReflowState, aFloat,
availSpace.Size(blockWM).ConvertTo(floatWM, blockWM));
return floatRS.ComputedWidth() + floatRS.ComputedPhysicalBorderPadding().LeftRight() +
floatRS.ComputedPhysicalMargin().LeftRight();
return floatRS.ComputedSizeWithMarginBorderPadding(blockWM).ISize(blockWM);
}
void
nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
const nsRect& aAdjustedAvailableSpace,
const LogicalRect& aAdjustedAvailableSpace,
nsIFrame* aFloat,
nsMargin& aFloatMargin,
nsMargin& aFloatOffsets,
LogicalMargin& aFloatMargin,
LogicalMargin& aFloatOffsets,
bool aFloatPushedDown,
nsReflowStatus& aReflowStatus)
{
@ -5795,18 +5814,19 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
// Reflow the float.
aReflowStatus = NS_FRAME_COMPLETE;
WritingMode wm = aState.mReflowState.GetWritingMode();
#ifdef NOISY_FLOAT
printf("Reflow Float %p in parent %p, availSpace(%d,%d,%d,%d)\n",
aFloat, this,
aFloatAvailableSpace.x, aFloatAvailableSpace.y,
aFloatAvailableSpace.width, aFloatAvailableSpace.height
aFloat, this,
aFloatAvailableSpace.IStart(wm), aFloatAvailableSpace.BStart(wm),
aFloatAvailableSpace.ISize(wm), aFloatAvailableSpace.BSize(wm)
);
#endif
nsHTMLReflowState
floatRS(aState.mPresContext, aState.mReflowState, aFloat,
LogicalSize(aFloat->GetWritingMode(),
aAdjustedAvailableSpace.Size()));
aAdjustedAvailableSpace.Size(wm).ConvertTo(aFloat->GetWritingMode(),
wm));
// Normally the mIsTopOfPage state is copied from the parent reflow
// state. However, when reflowing a float, if we've placed other
@ -5818,7 +5838,7 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
// about adjacency with the top, so it seems misleading.
if (floatRS.mFlags.mIsTopOfPage &&
(aFloatPushedDown ||
aAdjustedAvailableSpace.width != aState.ContentISize())) {
aAdjustedAvailableSpace.ISize(wm) != aState.ContentISize())) {
floatRS.mFlags.mIsTopOfPage = false;
}
@ -5856,9 +5876,9 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
ShouldAvoidBreakInside(floatRS)) {
aReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
} else if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) &&
(NS_UNCONSTRAINEDSIZE == aAdjustedAvailableSpace.height)) {
// An incomplete reflow status means we should split the float
// if the height is constrained (bug 145305).
(NS_UNCONSTRAINEDSIZE == aAdjustedAvailableSpace.BSize(wm))) {
// An incomplete reflow status means we should split the float
// if the height is constrained (bug 145305).
aReflowStatus = NS_FRAME_COMPLETE;
}
@ -5875,8 +5895,11 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
}
// Capture the margin and offsets information for the caller
aFloatMargin = floatRS.ComputedPhysicalMargin(); // float margins don't collapse
aFloatOffsets = floatRS.ComputedPhysicalOffsets();
aFloatMargin =
// float margins don't collapse
floatRS.ComputedLogicalMargin().ConvertTo(wm, floatRS.GetWritingMode());
aFloatOffsets =
floatRS.ComputedLogicalOffsets().ConvertTo(wm, floatRS.GetWritingMode());
const nsHTMLReflowMetrics& metrics = brc.GetMetrics();
@ -5886,8 +5909,8 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
// we be doing this in nsBlockReflowState::FlowAndPlaceFloat after
// we've positioned the float, and shouldn't we be doing the equivalent
// of |PlaceFrameView| here?
WritingMode wm = metrics.GetWritingMode();
aFloat->SetSize(wm, metrics.Size(wm));
WritingMode metricsWM = metrics.GetWritingMode();
aFloat->SetSize(metricsWM, metrics.Size(metricsWM));
if (aFloat->HasView()) {
nsContainerFrame::SyncFrameViewAfterReflow(aState.mPresContext, aFloat,
aFloat->GetView(),
@ -6829,7 +6852,7 @@ nsBlockFrame::ReflowBullet(nsIFrame* aBulletFrame,
// the block.
// FIXME: aLineTop isn't actually set correctly by some callers, since
// they reposition the line.
nsRect floatAvailSpace =
LogicalRect floatAvailSpace =
aState.GetFloatAvailableSpaceWithState(aLineTop,
&aState.mFloatManagerStateBefore)
.mRect;
@ -6849,13 +6872,11 @@ nsBlockFrame::ReflowBullet(nsIFrame* aBulletFrame,
// in the current writing mode. Then we subtract out the start
// border/padding and the bullet's width and margin to offset the position.
WritingMode wm = rs.GetWritingMode();
nscoord containerWidth = floatAvailSpace.XMost();
LogicalRect logicalFAS(wm, floatAvailSpace, containerWidth);
// Get the bullet's margin, converted to our writing mode so that we can
// combine it with other logical values here.
LogicalMargin bulletMargin =
reflowState.ComputedLogicalMargin().ConvertTo(wm, bulletWM);
nscoord iStart = logicalFAS.IStart(wm) -
nscoord iStart = floatAvailSpace.IStart(wm) -
rs.ComputedLogicalBorderPadding().IStart(wm) -
bulletMargin.IEnd(wm) -
aMetrics.ISize(wm);
@ -6863,11 +6884,11 @@ nsBlockFrame::ReflowBullet(nsIFrame* aBulletFrame,
// Approximate the bullets position; vertical alignment will provide
// the final vertical location. We pass our writing-mode here, because
// it may be different from the bullet frame's mode.
nscoord bStart = logicalFAS.BStart(wm);
aBulletFrame->SetRect(wm, LogicalRect(wm, LogicalPoint(wm, iStart, bStart),
LogicalSize(wm, aMetrics.ISize(wm),
aMetrics.BSize(wm))),
containerWidth);
nscoord bStart = floatAvailSpace.BStart(wm);
aBulletFrame->SetRect(wm, LogicalRect(wm, iStart, bStart,
aMetrics.ISize(wm),
aMetrics.BSize(wm)),
aState.mContainerWidth);
aBulletFrame->DidReflow(aState.mPresContext, &aState.mReflowState,
nsDidReflowStatus::FINISHED);
}
@ -7020,20 +7041,22 @@ nsBlockFrame::BlockCanIntersectFloats(nsIFrame* aFrame)
// in the available space given, which means that variation shouldn't
// matter.
/* static */
nsBlockFrame::ReplacedElementWidthToClear
nsBlockFrame::WidthToClearPastFloats(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsBlockFrame::ReplacedElementISizeToClear
nsBlockFrame::ISizeToClearPastFloats(nsBlockReflowState& aState,
const LogicalRect& aFloatAvailableSpace,
nsIFrame* aFrame)
{
nscoord leftOffset, rightOffset;
nscoord inlineStartOffset, inlineEndOffset;
WritingMode wm = aState.mReflowState.GetWritingMode();
nsCSSOffsetState offsetState(aFrame, aState.mReflowState.rendContext,
aState.mContentArea.Width(wm));
ReplacedElementWidthToClear result;
ReplacedElementISizeToClear result;
aState.ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace,
leftOffset, rightOffset);
nscoord availWidth = aState.mContentArea.Width(wm) - leftOffset - rightOffset;
inlineStartOffset,
inlineEndOffset);
nscoord availISize = aState.mContentArea.ISize(wm) -
inlineStartOffset - inlineEndOffset;
// We actually don't want the min width here; see bug 427782; we only
// want to displace if the width won't compute to a value small enough
@ -7041,16 +7064,19 @@ nsBlockFrame::WidthToClearPastFloats(nsBlockReflowState& aState,
// All we really need here is the result of ComputeSize, and we
// could *almost* get that from an nsCSSOffsetState, except for the
// last argument.
LogicalSize availSpace(aFrame->GetWritingMode(),
nsSize(availWidth, NS_UNCONSTRAINEDSIZE));
WritingMode frWM = aFrame->GetWritingMode();
LogicalSize availSpace = LogicalSize(wm, availISize, NS_UNCONSTRAINEDSIZE).
ConvertTo(frWM, wm);
nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState,
aFrame, availSpace);
result.borderBoxWidth = reflowState.ComputedWidth() +
reflowState.ComputedPhysicalBorderPadding().LeftRight();
result.borderBoxISize =
reflowState.ComputedSizeWithBorderPadding().ConvertTo(wm, frWM).ISize(wm);
// Use the margins from offsetState rather than reflowState so that
// they aren't reduced by ignoring margins in overconstrained cases.
result.marginLeft = offsetState.ComputedPhysicalMargin().left;
result.marginRight = offsetState.ComputedPhysicalMargin().right;
LogicalMargin computedMargin =
offsetState.ComputedLogicalMargin().ConvertTo(wm, frWM);
result.marginIStart = computedMargin.IStart(wm);
result.marginIEnd = computedMargin.IEnd(wm);
return result;
}

View File

@ -314,19 +314,19 @@ public:
static bool BlockCanIntersectFloats(nsIFrame* aFrame);
/**
* Returns the width that needs to be cleared past floats for blocks
* that cannot intersect floats. aState must already have
* GetAvailableSpace called on it for the vertical position that we
* care about (which need not be its current mY)
* Returns the inline size that needs to be cleared past floats for
* blocks that cannot intersect floats. aState must already have
* GetAvailableSpace called on it for the block-dir position that we
* care about (which need not be its current mBCoord)
*/
struct ReplacedElementWidthToClear {
nscoord marginLeft, borderBoxWidth, marginRight;
nscoord MarginBoxWidth() const
{ return marginLeft + borderBoxWidth + marginRight; }
struct ReplacedElementISizeToClear {
nscoord marginIStart, borderBoxISize, marginIEnd;
nscoord MarginBoxISize() const
{ return marginIStart + borderBoxISize + marginIEnd; }
};
static ReplacedElementWidthToClear
WidthToClearPastFloats(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
static ReplacedElementISizeToClear
ISizeToClearPastFloats(nsBlockReflowState& aState,
const mozilla::LogicalRect& aFloatAvailableSpace,
nsIFrame* aFrame);
/**
@ -605,13 +605,13 @@ protected:
// Return false if it needs another reflow because of reduced space
// between floats that are next to it (but not next to its top), and
// return true otherwise.
bool PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
line_iterator aLine,
bool PlaceLine(nsBlockReflowState& aState,
nsLineLayout& aLineLayout,
line_iterator aLine,
nsFloatManager::SavedState* aFloatStateBeforeLine,
nsRect& aFloatAvailableSpace, /* in-out */
nscoord& aAvailableSpaceHeight, /* in-out */
bool* aKeepReflowGoing);
mozilla::LogicalRect& aFloatAvailableSpace, //in-out
nscoord& aAvailableSpaceHeight, // in-out
bool* aKeepReflowGoing);
/**
* If NS_BLOCK_LOOK_FOR_DIRTY_FRAMES is set, call MarkLineDirty
@ -669,28 +669,29 @@ protected:
nsIFrame* aFrame,
LineReflowStatus* aLineReflowStatus);
// Compute the available width for a float.
nsRect AdjustFloatAvailableSpace(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsIFrame* aFloatFrame);
// Computes the border-box width of the float
nscoord ComputeFloatWidth(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsIFrame* aFloat);
// Compute the available inline size for a float.
mozilla::LogicalRect AdjustFloatAvailableSpace(
nsBlockReflowState& aState,
const mozilla::LogicalRect& aFloatAvailableSpace,
nsIFrame* aFloatFrame);
// Computes the border-box inline size of the float
nscoord ComputeFloatISize(nsBlockReflowState& 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.
void ReflowFloat(nsBlockReflowState& aState,
const nsRect& aAdjustedAvailableSpace,
nsIFrame* aFloat,
nsMargin& aFloatMargin,
nsMargin& aFloatOffsets,
void ReflowFloat(nsBlockReflowState& 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);
bool aFloatPushedDown,
nsReflowStatus& aReflowStatus);
//----------------------------------------
// Methods for pushing/pulling lines/frames
@ -756,7 +757,7 @@ protected:
void PropagateFloatDamage(nsBlockReflowState& aState,
nsLineBox* aLine,
nscoord aDeltaY);
nscoord aDeltaBCoord);
void CheckFloats(nsBlockReflowState& aState);

View File

@ -214,7 +214,7 @@ nsBlockReflowContext::ComputeCollapsedBStartMargin(const nsHTMLReflowState& aRS,
}
void
nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
nsBlockReflowContext::ReflowBlock(const LogicalRect& aSpace,
bool aApplyBStartMargin,
nsCollapsingMargin& aPrevMargin,
nscoord aClearance,
@ -227,7 +227,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
mFrame = aFrameRS.frame;
mWritingMode = aState.mReflowState.GetWritingMode();
mContainerWidth = aState.mContainerWidth;
mSpace = LogicalRect(mWritingMode, aSpace, mContainerWidth);
mSpace = aSpace;
if (!aIsAdjacentWithBStart) {
aFrameRS.mFlags.mIsTopOfPage = false; // make sure this is cleared

View File

@ -28,15 +28,15 @@ public:
const nsHTMLReflowState& aParentRS);
~nsBlockReflowContext() { }
void ReflowBlock(const nsRect& aSpace,
bool aApplyBStartMargin,
nsCollapsingMargin& aPrevMargin,
nscoord aClearance,
bool aIsAdjacentWithBStart,
nsLineBox* aLine,
nsHTMLReflowState& aReflowState,
nsReflowStatus& aReflowStatus,
nsBlockReflowState& aState);
void ReflowBlock(const mozilla::LogicalRect& aSpace,
bool aApplyBStartMargin,
nsCollapsingMargin& aPrevMargin,
nscoord aClearance,
bool aIsAdjacentWithBStart,
nsLineBox* aLine,
nsHTMLReflowState& aReflowState,
nsReflowStatus& aReflowStatus,
nsBlockReflowState& aState);
bool PlaceBlock(const nsHTMLReflowState& aReflowState,
bool aForceFit,

View File

@ -129,44 +129,48 @@ nsBlockReflowState::GetConsumedBSize()
}
void
nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
const nsRect& aFloatAvailableSpace,
nscoord& aLeftResult,
nscoord& aRightResult)
nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(
nsIFrame* aFrame,
const LogicalRect& aFloatAvailableSpace,
nscoord& aIStartResult,
nscoord& aIEndResult)
{
nsRect contentArea =
mContentArea.GetPhysicalRect(mReflowState.GetWritingMode(), mContainerWidth);
WritingMode wm = mReflowState.GetWritingMode();
// The frame is clueless about the float manager and therefore we
// only give it free space. An example is a table frame - the
// tables do not flow around floats.
// However, we can let its margins intersect floats.
NS_ASSERTION(aFloatAvailableSpace.x >= contentArea.x, "bad avail space rect x");
NS_ASSERTION(aFloatAvailableSpace.width == 0 ||
aFloatAvailableSpace.XMost() <= contentArea.XMost(),
"bad avail space rect width");
NS_ASSERTION(aFloatAvailableSpace.IStart(wm) >= mContentArea.IStart(wm),
"bad avail space rect inline-coord");
NS_ASSERTION(aFloatAvailableSpace.ISize(wm) == 0 ||
aFloatAvailableSpace.IEnd(wm) <= mContentArea.IEnd(wm),
"bad avail space rect inline-size");
nscoord leftOffset, rightOffset;
if (aFloatAvailableSpace.width == contentArea.width) {
nscoord iStartOffset, iEndOffset;
if (aFloatAvailableSpace.ISize(wm) == mContentArea.ISize(wm)) {
// We don't need to compute margins when there are no floats around.
leftOffset = 0;
rightOffset = 0;
iStartOffset = 0;
iEndOffset = 0;
} else {
nsMargin frameMargin;
nsCSSOffsetState os(aFrame, mReflowState.rendContext, contentArea.width);
frameMargin = os.ComputedPhysicalMargin();
LogicalMargin frameMargin(wm);
nsCSSOffsetState os(aFrame, mReflowState.rendContext,
mContentArea.ISize(wm));
frameMargin =
os.ComputedLogicalMargin().ConvertTo(wm, aFrame->GetWritingMode());
nscoord leftFloatXOffset = aFloatAvailableSpace.x - contentArea.x;
leftOffset = std::max(leftFloatXOffset, frameMargin.left) -
frameMargin.left;
leftOffset = std::max(leftOffset, 0); // in case of negative margin
nscoord rightFloatXOffset =
contentArea.XMost() - aFloatAvailableSpace.XMost();
rightOffset = std::max(rightFloatXOffset, frameMargin.right) -
frameMargin.right;
rightOffset = std::max(rightOffset, 0); // in case of negative margin
nscoord iStartFloatIOffset =
aFloatAvailableSpace.IStart(wm) - mContentArea.IStart(wm);
iStartOffset = std::max(iStartFloatIOffset, frameMargin.IStart(wm)) -
frameMargin.IStart(wm);
iStartOffset = std::max(iStartOffset, 0); // in case of negative margin
nscoord iEndFloatIOffset =
mContentArea.IEnd(wm) - aFloatAvailableSpace.IEnd(wm);
iEndOffset = std::max(iEndFloatIOffset, frameMargin.IEnd(wm)) -
frameMargin.IEnd(wm);
iEndOffset = std::max(iEndOffset, 0); // in case of negative margin
}
aLeftResult = leftOffset;
aRightResult = rightOffset;
aIStartResult = iStartOffset;
aIEndResult = iEndOffset;
}
static nscoord
@ -193,19 +197,15 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
const nsStyleDisplay* aDisplay,
const nsFlowAreaRect& aFloatAvailableSpace,
bool aBlockAvoidsFloats,
nsRect& aResult)
LogicalRect& aResult)
{
#ifdef REALLY_NOISY_REFLOW
printf("CBAS frame=%p has floats %d\n",
aFrame, aFloatAvailableSpace.mHasFloats);
#endif
WritingMode wm = mReflowState.GetWritingMode();
LogicalRect result(wm);
LogicalRect floatAvailSpace = LogicalRect(wm,
aFloatAvailableSpace.mRect,
mContainerWidth); //??mReflowState.AvailableWidth());
result.BStart(wm) = mBCoord;
result.BSize(wm) = GetFlag(BRS_UNCONSTRAINEDBSIZE)
aResult.BStart(wm) = mBCoord;
aResult.BSize(wm) = GetFlag(BRS_UNCONSTRAINEDBSIZE)
? NS_UNCONSTRAINEDSIZE
: mReflowState.AvailableBSize() - mBCoord
- GetBEndMarginClone(aFrame, mReflowState.rendContext, mContentArea, wm);
@ -222,7 +222,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
// applies to a specific set of frame classes and no new ones?
// If we did that, then for those frames where the condition below is
// true but nsBlockFrame::BlockCanIntersectFloats is false,
// nsBlockFrame::WidthToClearPastFloats would need to use the
// nsBlockFrame::ISizeToClearPastFloats would need to use the
// shrink-wrap formula, max(MIN_ISIZE, min(avail width, PREF_ISIZE))
// rather than just using MIN_ISIZE.
NS_ASSERTION(nsBlockFrame::BlockCanIntersectFloats(aFrame) ==
@ -238,15 +238,15 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
case NS_STYLE_FLOAT_EDGE_CONTENT: // content and only content does runaround of floats
// The child block will flow around the float. Therefore
// give it all of the available space.
result.IStart(wm) = ContentIStart();
result.ISize(wm) = ContentISize();
aResult.IStart(wm) = mContentArea.IStart(wm);
aResult.ISize(wm) = mContentArea.ISize(wm);
break;
case NS_STYLE_FLOAT_EDGE_MARGIN:
{
// The child block's margins should be placed adjacent to,
// but not overlap the float.
result.IStart(wm) = floatAvailSpace.IStart(wm);
result.ISize(wm) = floatAvailSpace.ISize(wm);
aResult.IStart(wm) = aFloatAvailableSpace.mRect.IStart(wm);
aResult.ISize(wm) = aFloatAvailableSpace.mRect.ISize(wm);
}
break;
}
@ -255,24 +255,21 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
// Since there are no floats present the float-edge property
// doesn't matter therefore give the block element all of the
// available space since it will flow around the float itself.
result.IStart(wm) = ContentIStart();
result.ISize(wm) = ContentISize();
aResult.IStart(wm) = mContentArea.IStart(wm);
aResult.ISize(wm) = mContentArea.ISize(wm);
}
aResult = result.GetPhysicalRect(wm, mContainerWidth);
}
else {
aResult = result.GetPhysicalRect(wm, mContainerWidth);
nsRect contentArea =
mContentArea.GetPhysicalRect(wm, mContainerWidth);
nscoord leftOffset, rightOffset;
nscoord iStartOffset, iEndOffset;
ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace.mRect,
leftOffset, rightOffset);
aResult.x = contentArea.x + leftOffset;
aResult.width = contentArea.width - leftOffset - rightOffset;
iStartOffset, iEndOffset);
aResult.IStart(wm) = mContentArea.IStart(wm) + iStartOffset;
aResult.ISize(wm) = mContentArea.ISize(wm) - iStartOffset - iEndOffset;
}
#ifdef REALLY_NOISY_REFLOW
printf(" CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height);
printf(" CBAS: result %d %d %d %d\n", aResult.IStart(wm), aResult.BStart(wm),
aResult.ISize(wm), aResult.BSize(wm));
#endif
}
@ -302,16 +299,17 @@ nsBlockReflowState::GetFloatAvailableSpaceWithState(
mFloatManager->GetFlowArea(wm, aBCoord, nsFloatManager::BAND_FROM_POINT,
blockSize, mContentArea, aState,
mContainerWidth);
// Keep the width >= 0 for compatibility with nsSpaceManager.
if (result.mRect.width < 0)
result.mRect.width = 0;
// Keep the inline size >= 0 for compatibility with nsSpaceManager.
if (result.mRect.ISize(wm) < 0) {
result.mRect.ISize(wm) = 0;
}
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow) {
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("GetAvailableSpace: band=%d,%d,%d,%d hasfloats=%d\n",
result.mRect.x, result.mRect.y, result.mRect.width,
result.mRect.height, result.mHasFloats);
result.mRect.IStart(wm), result.mRect.BStart(wm),
result.mRect.ISize(wm), result.mRect.BSize(wm), result.mHasFloats);
}
#endif
return result;
@ -339,15 +337,16 @@ nsBlockReflowState::GetFloatAvailableSpaceForBSize(
mFloatManager->GetFlowArea(wm, aBCoord, nsFloatManager::WIDTH_WITHIN_HEIGHT,
aBSize, mContentArea, aState, mContainerWidth);
// Keep the width >= 0 for compatibility with nsSpaceManager.
if (result.mRect.width < 0)
result.mRect.width = 0;
if (result.mRect.ISize(wm) < 0) {
result.mRect.ISize(wm) = 0;
}
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow) {
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("GetAvailableSpaceForHeight: space=%d,%d,%d,%d hasfloats=%d\n",
result.mRect.x, result.mRect.y, result.mRect.width,
result.mRect.height, result.mHasFloats);
result.mRect.IStart(wm), result.mRect.BStart(wm),
result.mRect.ISize(wm), result.mRect.BSize(wm), result.mHasFloats);
}
#endif
return result;
@ -522,7 +521,7 @@ nsBlockReflowState::RecoverStateFrom(nsLineList::iterator aLine,
bool
nsBlockReflowState::AddFloat(nsLineLayout* aLineLayout,
nsIFrame* aFloat,
nscoord aAvailableWidth)
nscoord aAvailableISize)
{
NS_PRECONDITION(aLineLayout, "must have line layout");
NS_PRECONDITION(mBlock->end_lines() != mCurrentLine, "null ptr");
@ -573,19 +572,21 @@ nsBlockReflowState::AddFloat(nsLineLayout* aLineLayout,
// If one or more floats has already been pushed to the next line,
// don't let this one go on the current line, since that would violate
// float ordering.
nsRect floatAvailableSpace = GetFloatAvailableSpace().mRect;
LogicalRect floatAvailableSpace = GetFloatAvailableSpace().mRect;
if (mBelowCurrentLineFloats.IsEmpty() &&
(aLineLayout->LineIsEmpty() ||
mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aFloat)
<= aAvailableWidth)) {
mBlock->ComputeFloatISize(*this, floatAvailableSpace, aFloat)
<= aAvailableISize)) {
// And then place it
placed = FlowAndPlaceFloat(aFloat);
if (placed) {
// Pass on updated available space to the current inline reflow engine
WritingMode wm = mReflowState.GetWritingMode();
nsFlowAreaRect floatAvailSpace = GetFloatAvailableSpace(mBCoord);
nsRect availSpace(nsPoint(floatAvailSpace.mRect.x, mBCoord),
floatAvailSpace.mRect.Size());
aLineLayout->UpdateBand(availSpace, aFloat);
LogicalRect availSpace(wm, floatAvailSpace.mRect.IStart(wm), mBCoord,
floatAvailSpace.mRect.ISize(wm),
floatAvailSpace.mRect.BSize(wm));
aLineLayout->UpdateBand(wm, availSpace, aFloat);
// Record this float in the current-line list
mCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
} else {
@ -608,37 +609,43 @@ nsBlockReflowState::AddFloat(nsLineLayout* aLineLayout,
}
bool
nsBlockReflowState::CanPlaceFloat(nscoord aFloatWidth,
nsBlockReflowState::CanPlaceFloat(nscoord aFloatISize,
const nsFlowAreaRect& aFloatAvailableSpace)
{
// A float fits at a given vertical position if there are no floats at
// its horizontal position (no matter what its width) or if its width
// fits in the space remaining after prior floats have been placed.
// A float fits at a given block-dir position if there are no floats
// at its inline-dir position (no matter what its inline size) or if
// its inline size fits in the space remaining after prior floats have
// been placed.
// FIXME: We should allow overflow by up to half a pixel here (bug 21193).
return !aFloatAvailableSpace.mHasFloats ||
aFloatAvailableSpace.mRect.width >= aFloatWidth;
aFloatAvailableSpace.mRect.ISize(mReflowState.GetWritingMode()) >=
aFloatISize;
}
static nscoord
FloatMarginWidth(const nsHTMLReflowState& aCBReflowState,
nscoord aFloatAvailableWidth,
FloatMarginISize(const nsHTMLReflowState& aCBReflowState,
nscoord aFloatAvailableISize,
nsIFrame *aFloat,
const nsCSSOffsetState& aFloatOffsetState)
{
AutoMaybeDisableFontInflation an(aFloat);
WritingMode fosWM = aFloatOffsetState.GetWritingMode();
return aFloat->ComputeSize(
aCBReflowState.rendContext,
fosWM,
aCBReflowState.ComputedSize(fosWM),
aFloatAvailableWidth,
aFloatOffsetState.ComputedLogicalMargin().Size(fosWM),
aFloatOffsetState.ComputedLogicalBorderPadding().Size(fosWM) -
aFloatOffsetState.ComputedLogicalPadding().Size(fosWM),
aFloatOffsetState.ComputedLogicalPadding().Size(fosWM),
true).Width(fosWM) +
aFloatOffsetState.ComputedPhysicalMargin().LeftRight() +
aFloatOffsetState.ComputedPhysicalBorderPadding().LeftRight();
WritingMode wm = aFloatOffsetState.GetWritingMode();
LogicalSize floatSize =
aFloat->ComputeSize(
aCBReflowState.rendContext,
wm,
aCBReflowState.ComputedSize(wm),
aFloatAvailableISize,
aFloatOffsetState.ComputedLogicalMargin().Size(wm),
aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm) -
aFloatOffsetState.ComputedLogicalPadding().Size(wm),
aFloatOffsetState.ComputedLogicalPadding().Size(wm),
true);
return floatSize.ISize(wm) +
aFloatOffsetState.ComputedLogicalMargin().IStartEnd(wm) +
aFloatOffsetState.ComputedLogicalBorderPadding().IStartEnd(wm);
}
bool
@ -679,8 +686,8 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
}
// Get the band of available space
nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mBCoord);
nsRect adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this,
floatAvailableSpace.mRect, aFloat);
LogicalRect adjustedAvailableSpace =
mBlock->AdjustFloatAvailableSpace(*this, floatAvailableSpace.mRect, aFloat);
NS_ASSERTION(aFloat->GetParent() == mBlock,
"Float frame has wrong parent");
@ -688,12 +695,12 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
nsCSSOffsetState offsets(aFloat, mReflowState.rendContext,
mReflowState.ComputedWidth());
nscoord floatMarginWidth = FloatMarginWidth(mReflowState,
adjustedAvailableSpace.width,
nscoord floatMarginISize = FloatMarginISize(mReflowState,
adjustedAvailableSpace.ISize(wm),
aFloat, offsets);
nsMargin floatMargin; // computed margin
nsMargin floatOffsets;
LogicalMargin floatMargin(wm); // computed margin
LogicalMargin floatOffsets(wm);
nsReflowStatus reflowStatus;
// If it's a floating first-letter, we need to reflow it before we
@ -703,7 +710,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
if (isLetter) {
mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, floatMargin,
floatOffsets, false, reflowStatus);
floatMarginWidth = aFloat->GetSize().width + floatMargin.LeftRight();
floatMarginISize = aFloat->ISize(wm) + floatMargin.IStartEnd(wm);
NS_ASSERTION(NS_FRAME_IS_COMPLETE(reflowStatus),
"letter frames shouldn't break, and if they do now, "
"then they're breaking at the wrong point");
@ -727,14 +734,14 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
for (;;) {
if (mReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE &&
floatAvailableSpace.mRect.height <= 0 &&
floatAvailableSpace.mRect.BSize(wm) <= 0 &&
!mustPlaceFloat) {
// No space, nowhere to put anything.
PushFloatPastBreak(aFloat);
return false;
}
if (CanPlaceFloat(floatMarginWidth, floatAvailableSpace)) {
if (CanPlaceFloat(floatMarginISize, floatAvailableSpace)) {
// We found an appropriate place.
break;
}
@ -743,9 +750,9 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) {
mBCoord += floatAvailableSpace.mRect.height;
if (adjustedAvailableSpace.height != NS_UNCONSTRAINEDSIZE) {
adjustedAvailableSpace.height -= floatAvailableSpace.mRect.height;
mBCoord += floatAvailableSpace.mRect.BSize(wm);
if (adjustedAvailableSpace.BSize(wm) != NS_UNCONSTRAINEDSIZE) {
adjustedAvailableSpace.BSize(wm) -= floatAvailableSpace.mRect.BSize(wm);
}
floatAvailableSpace = GetFloatAvailableSpace(mBCoord);
} else {
@ -785,14 +792,14 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
}
// the table does not fit anymore in this line so advance to next band
mBCoord += floatAvailableSpace.mRect.height;
mBCoord += floatAvailableSpace.mRect.BSize(wm);
// To match nsBlockFrame::AdjustFloatAvailableSpace, we have to
// get a new width for the new band.
floatAvailableSpace = GetFloatAvailableSpace(mBCoord);
adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this,
floatAvailableSpace.mRect, aFloat);
floatMarginWidth = FloatMarginWidth(mReflowState,
adjustedAvailableSpace.width,
floatMarginISize = FloatMarginISize(mReflowState,
adjustedAvailableSpace.ISize(wm),
aFloat, offsets);
}
@ -804,20 +811,20 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// We don't worry about the geometry of the prev in flow, let the continuation
// place and size itself as required.
// Assign an x and y coordinate to the float.
nscoord floatX, floatY;
if (NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) {
floatX = floatAvailableSpace.mRect.x;
// Assign inline and block dir coordinates to the float.
LogicalPoint floatPos(wm);
if ((NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) == wm.IsBidiLTR()) {
floatPos.I(wm) = floatAvailableSpace.mRect.IStart(wm);
}
else {
if (!keepFloatOnSameLine) {
floatX = floatAvailableSpace.mRect.XMost() - floatMarginWidth;
}
floatPos.I(wm) = floatAvailableSpace.mRect.IEnd(wm) - floatMarginISize;
}
else {
// this is the IE quirk (see few lines above)
// the table is kept in the same line: don't let it overlap the
// previous float
floatX = floatAvailableSpace.mRect.x;
// previous float
floatPos.I(wm) = floatAvailableSpace.mRect.IStart(wm);
}
}
// CSS2 spec, 9.5.1 rule [4]: "A floating box's outer top may not
@ -825,7 +832,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// containing block is the content edge of the block box, this
// means the margin edge of the float can't be higher than the
// content edge of the block that contains it.)
floatY = std::max(mBCoord, ContentBStart());
floatPos.B(wm) = std::max(mBCoord, ContentBStart());
// Reflow the float after computing its vertical position so it knows
// where to break.
@ -835,9 +842,9 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
floatOffsets, pushedDown, reflowStatus);
}
if (aFloat->GetPrevInFlow())
floatMargin.top = 0;
floatMargin.BStart(wm) = 0;
if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus))
floatMargin.bottom = 0;
floatMargin.BEnd(wm) = 0;
// In the case that we're in columns and not splitting floats, we need
// to check here that the float's height fit, and if it didn't, bail.
@ -847,10 +854,10 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// its entirety to the next page (NS_FRAME_IS_TRUNCATED or
// NS_INLINE_IS_BREAK_BEFORE), we need to do the same.
if ((ContentBSize() != NS_UNCONSTRAINEDSIZE &&
adjustedAvailableSpace.height == NS_UNCONSTRAINEDSIZE &&
adjustedAvailableSpace.BSize(wm) == NS_UNCONSTRAINEDSIZE &&
!mustPlaceFloat &&
aFloat->GetSize().height + floatMargin.TopBottom() >
ContentBEnd() - floatY) ||
aFloat->BSize(wm) + floatMargin.BStartEnd(wm) >
ContentBEnd() - floatPos.B(wm)) ||
NS_FRAME_IS_TRUNCATED(reflowStatus) ||
NS_INLINE_IS_BREAK_BEFORE(reflowStatus)) {
PushFloatPastBreak(aFloat);
@ -859,13 +866,14 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// We can't use aFloat->ShouldAvoidBreakInside(mReflowState) here since
// its mIsTopOfPage may be true even though the float isn't at the
// top when floatY > 0.
// top when floatPos.B(wm) > 0.
if (ContentBSize() != NS_UNCONSTRAINEDSIZE &&
!mustPlaceFloat && (!mReflowState.mFlags.mIsTopOfPage || floatY > 0) &&
!mustPlaceFloat &&
(!mReflowState.mFlags.mIsTopOfPage || floatPos.B(wm) > 0) &&
NS_STYLE_PAGE_BREAK_AVOID == aFloat->StyleDisplay()->mBreakInside &&
(!NS_FRAME_IS_FULLY_COMPLETE(reflowStatus) ||
aFloat->GetSize().height + floatMargin.TopBottom() >
ContentBEnd() - floatY) &&
aFloat->BSize(wm) + floatMargin.BStartEnd(wm) >
ContentBEnd() - floatPos.B(wm)) &&
!aFloat->GetPrevInFlow()) {
PushFloatPastBreak(aFloat);
return false;
@ -874,11 +882,21 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// Calculate the actual origin of the float frame's border rect
// relative to the parent block; the margin must be added in
// to get the border rect
nsPoint origin(floatMargin.left + floatX,
floatMargin.top + floatY);
//XXX temporary! ApplyRelativePositioning still uses physical margin and point
LogicalSize size = aFloat->GetLogicalSize(wm);
LogicalMargin margin = aFloat->GetLogicalUsedMargin(wm);
size.ISize(wm) += margin.IStartEnd(wm);
size.BSize(wm) += margin.BStartEnd(wm);
nsPoint physicalPos =
LogicalRect(wm, floatPos, size).GetPhysicalPosition(wm, mContainerWidth);
nsPoint origin(floatMargin.Left(wm) + physicalPos.x,
floatMargin.Top(wm) + physicalPos.y);
// If float is relatively positioned, factor that in as well
nsHTMLReflowState::ApplyRelativePositioning(aFloat, floatOffsets, &origin);
nsHTMLReflowState::ApplyRelativePositioning(aFloat,
floatOffsets.GetPhysicalMargin(wm),
&origin);
// Position the float and make sure and views are properly
// positioned. We need to explicitly position its child views as
@ -897,13 +915,13 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// Place the float in the float manager
// calculate region
LogicalRect region =
nsFloatManager::CalculateRegionFor(wm, aFloat,
LogicalMargin(wm, floatMargin),
nsFloatManager::CalculateRegionFor(wm, aFloat, floatMargin,
mContainerWidth);
// if the float split, then take up all of the vertical height
if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus) &&
(NS_UNCONSTRAINEDSIZE != ContentBSize())) {
region.BSize(wm) = std::max(region.BSize(wm), ContentBSize() - floatY);
region.BSize(wm) = std::max(region.BSize(wm),
ContentBSize() - floatPos.B(wm));
}
DebugOnly<nsresult> rv = mFloatManager->AddFloat(aFloat, region, wm,
mContainerWidth);
@ -1045,27 +1063,27 @@ nsBlockReflowState::ClearFloats(nscoord aBCoord, uint8_t aBreakType,
nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(newBCoord);
if (!floatAvailableSpace.mHasFloats) {
// If there aren't any floats here, then we always fit.
// We check this before calling WidthToClearPastFloats, which is
// We check this before calling ISizeToClearPastFloats, which is
// somewhat expensive.
break;
}
nsBlockFrame::ReplacedElementWidthToClear replacedWidth =
nsBlockFrame::WidthToClearPastFloats(*this, floatAvailableSpace.mRect,
nsBlockFrame::ReplacedElementISizeToClear replacedISize =
nsBlockFrame::ISizeToClearPastFloats(*this, floatAvailableSpace.mRect,
aReplacedBlock);
if (std::max(floatAvailableSpace.mRect.x -
mContentArea.X(wm, mContainerWidth),
replacedWidth.marginLeft) +
replacedWidth.borderBoxWidth +
std::max(mContentArea.XMost(wm, mContainerWidth) -
floatAvailableSpace.mRect.XMost(),
replacedWidth.marginRight) <=
mContentArea.Width(wm)) {
if (std::max(floatAvailableSpace.mRect.IStart(wm) -
mContentArea.IStart(wm),
replacedISize.marginIStart) +
replacedISize.borderBoxISize +
std::max(mContentArea.IEnd(wm) -
floatAvailableSpace.mRect.IEnd(wm),
replacedISize.marginIEnd) <=
mContentArea.ISize(wm)) {
break;
}
// See the analogous code for inlines in nsBlockFrame::DoReflowInlineFrames
if (floatAvailableSpace.mRect.height > 0) {
if (floatAvailableSpace.mRect.BSize(wm) > 0) {
// See if there's room in the next band.
newBCoord += floatAvailableSpace.mRect.height;
newBCoord += floatAvailableSpace.mRect.BSize(wm);
} else {
if (mReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE) {
// Stop trying to clear here; we'll just get pushed to the

View File

@ -113,16 +113,16 @@ public:
// Caller must have called GetAvailableSpace for the correct position
// (which need not be the current mBCoord).
void ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
const nsRect& aFloatAvailableSpace,
nscoord& aLeftResult,
nscoord& aRightResult);
const mozilla::LogicalRect& aFloatAvailableSpace,
nscoord& aIStartResult,
nscoord& aIEndResult);
// Caller must have called GetAvailableSpace for the current mBCoord
void ComputeBlockAvailSpace(nsIFrame* aFrame,
const nsStyleDisplay* aDisplay,
const nsFlowAreaRect& aFloatAvailableSpace,
bool aBlockAvoidsFloats,
nsRect& aResult);
mozilla::LogicalRect& aResult);
protected:
void RecoverFloats(nsLineList::iterator aLine, nscoord aDeltaBCoord);

View File

@ -144,11 +144,8 @@ nsFloatManager::GetFlowArea(WritingMode aWM, nscoord aBOffset,
if (floatCount == 0 ||
(mFloats[floatCount-1].mLeftBEnd <= blockStart &&
mFloats[floatCount-1].mRightBEnd <= blockStart)) {
//XXX temporary!
LogicalRect rect(aWM, aContentArea.IStart(aWM), aBOffset,
aContentArea.ISize(aWM), aBSize);
nsRect phys = rect.GetPhysicalRect(aWM, aContainerWidth);
return nsFlowAreaRect(phys.x, phys.y, phys.width, phys.height, false);
return nsFlowAreaRect(aWM, aContentArea.IStart(aWM), aBOffset,
aContentArea.ISize(aWM), aBSize, false);
}
nscoord blockEnd;
@ -238,14 +235,11 @@ nsFloatManager::GetFlowArea(WritingMode aWM, nscoord aBOffset,
}
}
nscoord height = (blockEnd == nscoord_MAX) ?
nscoord_MAX : (blockEnd - blockStart);
//XXX temporary!
LogicalRect rect(aWM,
inlineStart - origin.I(aWM), blockStart - origin.B(aWM),
inlineEnd - inlineStart, height);
nsRect phys = rect.GetPhysicalRect(aWM, aContainerWidth);
return nsFlowAreaRect(phys.x, phys.y, phys.width, phys.height, haveFloats);
nscoord blockSize = (blockEnd == nscoord_MAX) ?
nscoord_MAX : (blockEnd - blockStart);
return nsFlowAreaRect(aWM,
inlineStart - origin.I(aWM), blockStart - origin.B(aWM),
inlineEnd - inlineStart, blockSize, haveFloats);
}
nsresult

View File

@ -30,13 +30,15 @@ class nsPresContext;
* the content rectangle.
*/
struct nsFlowAreaRect {
nsRect mRect;
mozilla::LogicalRect mRect;
bool mHasFloats;
nsFlowAreaRect(nscoord aICoord, nscoord aBCoord,
nsFlowAreaRect(mozilla::WritingMode aWritingMode,
nscoord aICoord, nscoord aBCoord,
nscoord aISize, nscoord aBSize,
bool aHasFloats)
: mRect(aICoord, aBCoord, aISize, aBSize), mHasFloats(aHasFloats) {}
: mRect(aWritingMode, aICoord, aBCoord, aISize, aBSize)
, mHasFloats(aHasFloats) {}
};
#define NS_FLOAT_MANAGER_CACHE_SIZE 4

View File

@ -446,6 +446,12 @@ public:
// used for painting-related things, but should never be used for
// layout (except for handling of 'overflow').
void SetOverflowAreas(const nsOverflowAreas& aOverflowAreas);
mozilla::LogicalRect GetOverflowArea(nsOverflowType aType,
mozilla::WritingMode aWM,
nscoord aContainerWidth)
{
return mozilla::LogicalRect(aWM, GetOverflowArea(aType), aContainerWidth);
}
nsRect GetOverflowArea(nsOverflowType aType) {
return mData ? mData->mOverflowAreas.Overflow(aType) : GetPhysicalBounds();
}

View File

@ -270,13 +270,17 @@ nsLineLayout::EndLineReflow()
// per-span mIStart?
void
nsLineLayout::UpdateBand(const nsRect& aNewAvailSpace,
nsLineLayout::UpdateBand(WritingMode aWM,
const LogicalRect& aNewAvailSpace,
nsIFrame* aFloatFrame)
{
WritingMode lineWM = mRootSpan->mWritingMode;
LogicalRect availSpace(lineWM, aNewAvailSpace, mContainerWidth);
// need to convert to our writing mode, because we might have a different
// mode from the caller due to dir: auto
LogicalRect availSpace = aNewAvailSpace.ConvertTo(lineWM, aWM,
mContainerWidth);
#ifdef REALLY_NOISY_REFLOW
printf("nsLL::UpdateBand %d, %d, %d, %d, (logical %d, %d, %d, %d); frame=%p\n will set mImpacted to true\n",
printf("nsLL::UpdateBand %d, %d, %d, %d, (converted to %d, %d, %d, %d); frame=%p\n will set mImpacted to true\n",
aNewAvailSpace.x, aNewAvailSpace.y,
aNewAvailSpace.width, aNewAvailSpace.height,
availSpace.IStart(lineWM), availSpace.BStart(lineWM),
@ -300,21 +304,22 @@ nsLineLayout::UpdateBand(const nsRect& aNewAvailSpace,
// Compute the difference between last times width and the new width
NS_WARN_IF_FALSE(mRootSpan->mIEnd != NS_UNCONSTRAINEDSIZE &&
aNewAvailSpace.width != NS_UNCONSTRAINEDSIZE,
"have unconstrained width; this should only result from "
"very large sizes, not attempts at intrinsic width "
availSpace.ISize(lineWM) != NS_UNCONSTRAINEDSIZE,
"have unconstrained inline size; this should only result "
"from very large sizes, not attempts at intrinsic width "
"calculation");
// The root span's mIStart moves to aICoord
nscoord deltaICoord = availSpace.IStart(lineWM) - mRootSpan->mIStart;
// The width of all spans changes by this much (the root span's
// mIEnd moves to aICoord + aISize, its new width is aISize)
// The inline size of all spans changes by this much (the root span's
// mIEnd moves to aICoord + aISize, its new inline size is aISize)
nscoord deltaISize = availSpace.ISize(lineWM) -
(mRootSpan->mIEnd - mRootSpan->mIStart);
#ifdef NOISY_REFLOW
nsFrame::ListTag(stdout, mBlockReflowState->frame);
printf(": UpdateBand: %d,%d,%d,%d deltaISize=%d deltaICoord=%d\n",
aNewAvailSpace.IStart(lineWM), aNewAvailSpace.BStart(lineWM),
aNewAvailSpace.ISize(lineWM), aNewAvailSpace.BSize(lineWM), deltaISize, deltaICoord);
availSpace.IStart(lineWM), availSpace.BStart(lineWM),
availSpace.ISize(lineWM), availSpace.BSize(lineWM),
deltaISize, deltaICoord);
#endif
// Update the root span position

View File

@ -62,7 +62,8 @@ public:
* space rectangle, relative to the containing block.
* @param aFloatFrame the float frame that was placed.
*/
void UpdateBand(const nsRect& aNewAvailableSpace,
void UpdateBand(mozilla::WritingMode aWM,
const mozilla::LogicalRect& aNewAvailableSpace,
nsIFrame* aFloatFrame);
void BeginSpan(nsIFrame* aFrame, const nsHTMLReflowState* aSpanReflowState,
@ -150,9 +151,9 @@ public:
//----------------------------------------
// Inform the line-layout about the presence of a floating frame
// XXX get rid of this: use get-frame-type?
bool AddFloat(nsIFrame* aFloat, nscoord aAvailableWidth)
bool AddFloat(nsIFrame* aFloat, nscoord aAvailableISize)
{
return mBlockRS->AddFloat(this, aFloat, aAvailableWidth);
return mBlockRS->AddFloat(this, aFloat, aAvailableISize);
}
void SetTrimmableISize(nscoord aTrimmableISize) {