Bug 59200. Merge floater reflow and placement into FlowAndPlaceFloater() to deal with the fact that a floater may need to be reflowed as its 'pushed' to a new location. For auto-width floaters, ensure that the floater is not flowed at a width less than its max-element-size. Enforce CSS2 section 9.5.1 rule [2] by maintaining mLastFloaterY in the reflow state. r=rbs, sr=attinasi.

This commit is contained in:
waterson%netscape.com 2001-05-21 23:03:46 +00:00
parent 3b89e30362
commit b55568be36
16 changed files with 340 additions and 234 deletions

View File

@ -4122,18 +4122,10 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
printf(": line=%p xmost=%d\n", aLine, xmost);
}
#endif
// If we're shrink wrapping our width and the line was wrapped,
// then make sure we take up all of the available width
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsLineWrapped()) {
aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
#ifdef NOISY_KIDXMOST
printf("%p PostPlaceLine A aState.mKidXMost=%d\n", this, aState.mKidXMost);
#endif
}
else if (xmost > aState.mKidXMost) {
if (xmost > aState.mKidXMost) {
aState.mKidXMost = xmost;
#ifdef NOISY_KIDXMOST
printf("%p PostPlaceLine B aState.mKidXMost=%d\n", this, aState.mKidXMost);
printf("%p PostPlaceLine aState.mKidXMost=%d\n", this, aState.mKidXMost);
#endif
}
}
@ -4778,10 +4770,14 @@ nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext* aPresContext,
nsresult
nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
nsPlaceholderFrame* aPlaceholder,
nsRect& aCombinedRect,
nsRect& aCombinedRectResult,
nsMargin& aMarginResult,
nsMargin& aComputedOffsetsResult)
nsMargin& aComputedOffsetsResult,
nscoord& aMaxElementWidthResult)
{
// Reflow the floater.
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
#ifdef NOISY_FLOATER
printf("Reflow Floater %p in parent %p, availSpace(%d,%d,%d,%d)\n",
aPlaceholder->GetOutOfFlowFrame(), this,
@ -4789,40 +4785,81 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
aState.mAvailSpaceRect.width, aState.mAvailSpaceRect.height
);
#endif
// XXX update this just
aState.GetAvailableSpace();
// Reflow the floater. Since floaters are continued we given them an
// unbounded height. Floaters with an auto width are sized to zero
// according to the css2 spec.
// XXX We also need to take into account whether we should clear any
// preceeding floaters...
// Compute the available width. By default, assume the width of the
// available space rect.
nscoord availWidth = aState.mAvailSpaceRect.width;
// If the floater's width is automatic, we can't let the floater's
// width shrink below its maxElementSize.
const nsStylePosition* position;
GetStyleData(eStyleStruct_Position, NS_REINTERPRET_CAST(const nsStyleStruct*&, position));
PRBool isAutoWidth = (eStyleUnit_Auto == position->mWidth.GetUnit());
if (isAutoWidth) {
// It's auto-width. Have we computed a max element size yet? (If
// not, the floater cache will have NS_UNCONSTRAINEDSIZE as the
// initial value.) If we _have_ computed a max element size, and
// its larger then the available width, pin the avaiable width to
// the maxElementSize.
if ((NS_UNCONSTRAINEDSIZE != aMaxElementWidthResult) &&
(aMaxElementWidthResult > availWidth)) {
availWidth = aMaxElementWidthResult;
}
}
// We'll need to compute the max element size if either 1) we're
// auto-width and we've not yet cached the value, or 2) the state
// wanted us to compute it anyway.
PRBool computeMaxElementSize =
(isAutoWidth && (NS_UNCONSTRAINEDSIZE == aMaxElementWidthResult)) ||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
// XXX Why do we have to add in our border/padding?
nsRect availSpace(aState.mAvailSpaceRect.x + aState.BorderPadding().left,
aState.mAvailSpaceRect.y + aState.BorderPadding().top,
aState.mAvailSpaceRect.width, NS_UNCONSTRAINEDSIZE);
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
availWidth, NS_UNCONSTRAINEDSIZE);
// Setup block reflow state to reflow the floater
// Setup a block reflow state to reflow the floater.
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
computeMaxElementSize,
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
brc.SetNextRCFrame(aState.mNextRCFrame);
// Reflow the floater
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
nsReflowStatus frameReflowStatus;
nsresult rv = brc.ReflowBlock(floater, availSpace, PR_TRUE, 0,
isAdjacentWithTop,
nsresult rv = brc.ReflowBlock(floater, availSpace, PR_TRUE, 0, isAdjacentWithTop,
aComputedOffsetsResult, frameReflowStatus);
if (PR_TRUE==brc.BlockShouldInvalidateItself()) {
if (NS_SUCCEEDED(rv) && isAutoWidth && (NS_UNCONSTRAINEDSIZE == aMaxElementWidthResult)) {
// We've just flowed an auto-width floater, but have not yet cached
// the maxElementSize. Do so now.
nsSize maxElementSize = brc.GetMaxElementSize();
aMaxElementWidthResult = maxElementSize.width;
if (aMaxElementWidthResult > availSpace.width) {
// The floater's maxElementSize is larger than the available
// width. Reflow it again, this time pinning the width to the
// maxElementSize.
availSpace.width = aMaxElementWidthResult;
rv = brc.ReflowBlock(floater, availSpace, PR_TRUE, 0, isAdjacentWithTop,
aComputedOffsetsResult, frameReflowStatus);
}
}
if (brc.BlockShouldInvalidateItself()) {
Invalidate(aState.mPresContext, mRect);
}
if (floater == aState.mNextRCFrame) {
// NULL out mNextRCFrame so if we reflow it again we don't think it's still
// an incremental reflow
// Null out mNextRCFrame so if we reflow it again, we don't think
// it's still an incremental reflow
aState.mNextRCFrame = nsnull;
}
if (NS_FAILED(rv)) {
return rv;
}
@ -4837,7 +4874,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
aMarginResult.left = m.left;
const nsHTMLReflowMetrics& metrics = brc.GetMetrics();
aCombinedRect = metrics.mOverflowArea;
aCombinedRectResult = metrics.mOverflowArea;
// Set the rect, make sure the view is properly sized and positioned,
// and tell the frame we're done reflowing it
floater->SizeTo(aState.mPresContext, metrics.width, metrics.height);

View File

@ -351,9 +351,10 @@ protected:
nsresult ReflowFloater(nsBlockReflowState& aState,
nsPlaceholderFrame* aPlaceholder,
nsRect& aCombinedRect,
nsRect& aCombinedRectResult,
nsMargin& aMarginResult,
nsMargin& aComputedOffsetsResult);
nsMargin& aComputedOffsetsResult,
nscoord& aMaxElementWidthResult);
//----------------------------------------
// Methods for pushing/pulling lines/frames
@ -482,9 +483,5 @@ protected:
#endif
};
// Some #ifdef'd bug fixes
#define FIX_BUG_38157
#define FIX_BUG_37657
#endif /* nsBlockFrame_h___ */

View File

@ -314,8 +314,10 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
(const nsStyleStruct*&)display);
if ((eStyleUnit_Auto == widthUnit) &&
((NS_STYLE_FLOAT_LEFT == display->mFloats) ||
(NS_STYLE_FLOAT_RIGHT == display->mFloats)))
{
(NS_STYLE_FLOAT_RIGHT == display->mFloats))) {
// Construct the reflow state using the ctor that explicitly
// constrains the containing block's width and height to the
// available width and height.
nsHTMLReflowState autoReflowState(mPresContext, mOuterReflowState, aFrame,
availSpace, aSpace.width, aSpace.height);
autoReflowState.reason = reason;
@ -325,8 +327,10 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
aComputedOffsets,
aFrameReflowStatus);
}
else
{
else {
// Construct the reflow state using the ctor that will use the
// containing block's computed width and height (or handle derive
// appropriate values for an absolutely positioned frame).
nsHTMLReflowState normalReflowState(mPresContext, mOuterReflowState, aFrame,
availSpace, reason);
rv = DoReflowBlock(normalReflowState, reason, aFrame, aSpace,

View File

@ -43,6 +43,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
: mBlock(aFrame),
mPresContext(aPresContext),
mReflowState(aReflowState),
mLastFloaterY(0),
mNextRCFrame(nsnull),
mPrevBottomMargin(0),
mLineNumber(0),
@ -93,18 +94,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
// Choose a width based on the content (shrink wrap width) up
// to the maximum width
// Part 2 of a possible fix for 38157
#ifdef FIX_BUG_38157
const nsMargin& margin = Margin();
nscoord availContentWidth = aReflowState.availableWidth;
if (NS_UNCONSTRAINEDSIZE != availContentWidth) {
availContentWidth -= (borderPadding.left + borderPadding.right) +
(margin.left + margin.right);
}
mContentArea.width = PR_MIN(aReflowState.mComputedMaxWidth, availContentWidth);
#else
mContentArea.width = aReflowState.mComputedMaxWidth;
#endif
SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
}
else {
@ -606,6 +596,7 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine,
}
#endif
mSpaceManager->AddRectRegion(floater, fc->mRegion);
mLastFloaterY = fc->mRegion.y;
fc = fc->Next();
}
#ifdef DEBUG
@ -702,13 +693,9 @@ nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
nscoord dy = oy - mSpaceManagerY;
mSpaceManager->Translate(-dx, -dy);
// Reflow the floater
mBlock->ReflowFloater(*this, aPlaceholder, fc->mCombinedArea,
fc->mMargins, fc->mOffsets);
// And then place it
PRBool isLeftFloater;
PlaceFloater(fc, &isLeftFloater);
FlowAndPlaceFloater(fc, &isLeftFloater);
// Pass on updated available space to the current inline reflow engine
GetAvailableSpace();
@ -907,8 +894,8 @@ nsBlockReflowState::CanPlaceFloater(const nsRect& aFloaterRect,
}
void
nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
PRBool* aIsLeftFloater)
nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
PRBool* aIsLeftFloater)
{
// Save away the Y coordinate before placing the floater. We will
// restore mY at the end after placing the floater. This is
@ -916,9 +903,14 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
// placement are for the floater only, not for any non-floating
// content.
nscoord saveY = mY;
// Grab the compatibility mode
nsCompatibility mode;
mPresContext->GetCompatibilityMode(&mode);
nsIFrame* floater = aFloaterCache->mPlaceholder->GetOutOfFlowFrame();
// Get the type of floater
// Grab the floater's display information
const nsStyleDisplay* floaterDisplay;
const nsStylePosition* floaterPosition;
floater->GetStyleData(eStyleStruct_Display,
@ -926,59 +918,72 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
floater->GetStyleData(eStyleStruct_Position,
(const nsStyleStruct*&)floaterPosition);
// See if the floater should clear any preceeding floaters...
if (NS_STYLE_CLEAR_NONE != floaterDisplay->mBreakType) {
ClearFloaters(mY, floaterDisplay->mBreakType);
}
else {
// Get the band of available space
GetAvailableSpace();
}
// Get the floaters bounding box and margin information
// This will hold the floater's geometry when we've found a place
// for it to live.
nsRect region;
floater->GetRect(region);
// Adjust the floater size by its margin. That's the area that will
// impact the space manager.
region.width += aFloaterCache->mMargins.left + aFloaterCache->mMargins.right;
region.height += aFloaterCache->mMargins.top + aFloaterCache->mMargins.bottom;
// Advance mY to mLastFloaterY (if it's not past it already) to
// enforce 9.5.1 rule [2]; i.e., make sure that a float isn't
// ``above'' another float that preceded it in the flow.
mY = NS_MAX(mLastFloaterY, mY);
// Find a place to place the floater. The CSS2 spec doesn't want
// floaters overlapping each other or sticking out of the containing
// block if possible (CSS2 spec section 9.5.1, see the rule list).
NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) ||
(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats),
"invalid float type");
// While there is not enough room for the floater, clear past other
// floaters until there is room (or the band is not impacted by a
// floater).
//
// Note: The CSS2 spec says that floaters should be placed as high
// as possible.
//
#ifdef FIX_BUG_37657
// Also note that in backwards compatibility mode, we skip this step
// for tables, since in old browsers, floating tables are horizontally
// stacked regardless of available space. (See bug 43086 about
// tables vs. non-tables.)
nsCompatibility mode;
mPresContext->GetCompatibilityMode(&mode);
if ((eCompatibility_NavQuirks != mode) ||
(NS_STYLE_DISPLAY_TABLE != floaterDisplay->mDisplay)) {
while (!CanPlaceFloater(region, floaterDisplay->mFloats)) {
mY += mAvailSpaceRect.height;
while (1) {
// See if the floater should clear any preceeding floaters...
if (NS_STYLE_CLEAR_NONE != floaterDisplay->mBreakType) {
ClearFloaters(mY, floaterDisplay->mBreakType);
}
else {
// Get the band of available space
GetAvailableSpace();
}
}
#else
while (!CanPlaceFloater(region, floaterDisplay->mFloats)) {
mY += mAvailSpaceRect.height;
GetAvailableSpace();
}
// Reflow the floater
mBlock->ReflowFloater(*this, aFloaterCache->mPlaceholder, aFloaterCache->mCombinedArea,
aFloaterCache->mMargins, aFloaterCache->mOffsets,
aFloaterCache->mMaxElementWidth);
// Get the floaters bounding box and margin information
floater->GetRect(region);
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow) {
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("flowed floater: ");
nsFrame::ListTag(stdout, floater);
printf(" (%d,%d,%d,%d), max-element-width=%d\n",
region.x, region.y, region.width, region.height,
aFloaterCache->mMaxElementWidth);
}
#endif
// Adjust the floater size by its margin. That's the area that will
// impact the space manager.
region.width += aFloaterCache->mMargins.left + aFloaterCache->mMargins.right;
region.height += aFloaterCache->mMargins.top + aFloaterCache->mMargins.bottom;
// Find a place to place the floater. The CSS2 spec doesn't want
// floaters overlapping each other or sticking out of the containing
// block if possible (CSS2 spec section 9.5.1, see the rule list).
NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) ||
(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats),
"invalid float type");
// In backwards compatibility mode, we don't bother to see if a
// floated table can ``really'' fit: in old browsers, floating
// tables are horizontally stacked regardless of available space.
// (See bug 43086 about tables vs. non-tables.)
if ((eCompatibility_NavQuirks == mode) &&
(NS_STYLE_DISPLAY_TABLE == floaterDisplay->mDisplay))
break;
// Can the floater fit here?
if (CanPlaceFloater(region, floaterDisplay->mFloats))
break;
// Nope. Advance to the next band.
mY += mAvailSpaceRect.height;
}
// Assign an x and y coordinate to the floater. Note that the x,y
// coordinates are computed <b>relative to the translation in the
// spacemanager</b> which means that the impacted region will be
@ -1082,6 +1087,9 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
nsBlockFrame::CombineRects(combinedArea, mFloaterCombinedArea);
}
// Remember the y-coordinate of the floater we've just placed
mLastFloaterY = mY;
// Now restore mY
mY = saveY;
@ -1091,7 +1099,7 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
floater->GetRect(r);
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("placed floater: ");
((nsFrame*)floater)->ListTag(stdout);
nsFrame::ListTag(stdout, floater);
printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
}
#endif
@ -1114,12 +1122,10 @@ nsBlockReflowState::PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aList)
printf("\n");
}
#endif
mBlock->ReflowFloater(*this, fc->mPlaceholder, fc->mCombinedArea,
fc->mMargins, fc->mOffsets);
// Place the floater
PRBool isLeftFloater;
PlaceFloater(fc, &isLeftFloater);
FlowAndPlaceFloater(fc, &isLeftFloater);
}
fc = fc->Next();
}

View File

@ -65,8 +65,8 @@ public:
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
void PlaceFloater(nsFloaterCache* aFloaterCache,
PRBool* aIsLeftFloater);
void FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
PRBool* aIsLeftFloater);
void PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aFloaters);
@ -177,6 +177,10 @@ public:
// The combined area of all floaters placed so far
nsRect mFloaterCombinedArea;
// The y-coordinate of the last floater placed. We keep this around
// to enforce 9.5.1 rule [2]
nscoord mLastFloaterY;
// For unconstained-width reflow, we keep the right floaters
// combined area stored seperately.
PRBool mHaveRightFloaters;

View File

@ -355,20 +355,20 @@ NS_IMETHODIMP
nsInlineFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
{
// The inline container frame does not handle the reflow
// request. It passes it up to its parent container.
// request. It passes it up to its parent container.
// If you don't already have dirty children,
if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) {
if (mParent) {
// Record that you are dirty and have dirty children
// Record that you are dirty and have dirty children
mState |= NS_FRAME_IS_DIRTY;
mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
// Pass the reflow request up to the parent
mParent->ReflowDirtyChild(aPresShell, (nsIFrame*) this);
// Pass the reflow request up to the parent
mParent->ReflowDirtyChild(aPresShell, this);
}
else {
NS_ASSERTION(0, "No parent to pass the reflow request up to.");
NS_ERROR("No parent to pass the reflow request up to.");
}
}

View File

@ -1097,6 +1097,7 @@ nsFloaterCache::nsFloaterCache()
mMargins(0, 0, 0, 0),
mOffsets(0, 0, 0, 0),
mCombinedArea(0, 0, 0, 0),
mMaxElementWidth(NS_UNCONSTRAINEDSIZE),
mNext(nsnull)
{
MOZ_COUNT_CTOR(nsFloaterCache);

View File

@ -67,6 +67,9 @@ public:
// the containing block frame.
nsRect mCombinedArea;
// The max element size for the floater.
nscoord mMaxElementWidth;
protected:
nsFloaterCache* mNext;

View File

@ -4122,18 +4122,10 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
printf(": line=%p xmost=%d\n", aLine, xmost);
}
#endif
// If we're shrink wrapping our width and the line was wrapped,
// then make sure we take up all of the available width
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsLineWrapped()) {
aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
#ifdef NOISY_KIDXMOST
printf("%p PostPlaceLine A aState.mKidXMost=%d\n", this, aState.mKidXMost);
#endif
}
else if (xmost > aState.mKidXMost) {
if (xmost > aState.mKidXMost) {
aState.mKidXMost = xmost;
#ifdef NOISY_KIDXMOST
printf("%p PostPlaceLine B aState.mKidXMost=%d\n", this, aState.mKidXMost);
printf("%p PostPlaceLine aState.mKidXMost=%d\n", this, aState.mKidXMost);
#endif
}
}
@ -4778,10 +4770,14 @@ nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext* aPresContext,
nsresult
nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
nsPlaceholderFrame* aPlaceholder,
nsRect& aCombinedRect,
nsRect& aCombinedRectResult,
nsMargin& aMarginResult,
nsMargin& aComputedOffsetsResult)
nsMargin& aComputedOffsetsResult,
nscoord& aMaxElementWidthResult)
{
// Reflow the floater.
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
#ifdef NOISY_FLOATER
printf("Reflow Floater %p in parent %p, availSpace(%d,%d,%d,%d)\n",
aPlaceholder->GetOutOfFlowFrame(), this,
@ -4789,40 +4785,81 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
aState.mAvailSpaceRect.width, aState.mAvailSpaceRect.height
);
#endif
// XXX update this just
aState.GetAvailableSpace();
// Reflow the floater. Since floaters are continued we given them an
// unbounded height. Floaters with an auto width are sized to zero
// according to the css2 spec.
// XXX We also need to take into account whether we should clear any
// preceeding floaters...
// Compute the available width. By default, assume the width of the
// available space rect.
nscoord availWidth = aState.mAvailSpaceRect.width;
// If the floater's width is automatic, we can't let the floater's
// width shrink below its maxElementSize.
const nsStylePosition* position;
GetStyleData(eStyleStruct_Position, NS_REINTERPRET_CAST(const nsStyleStruct*&, position));
PRBool isAutoWidth = (eStyleUnit_Auto == position->mWidth.GetUnit());
if (isAutoWidth) {
// It's auto-width. Have we computed a max element size yet? (If
// not, the floater cache will have NS_UNCONSTRAINEDSIZE as the
// initial value.) If we _have_ computed a max element size, and
// its larger then the available width, pin the avaiable width to
// the maxElementSize.
if ((NS_UNCONSTRAINEDSIZE != aMaxElementWidthResult) &&
(aMaxElementWidthResult > availWidth)) {
availWidth = aMaxElementWidthResult;
}
}
// We'll need to compute the max element size if either 1) we're
// auto-width and we've not yet cached the value, or 2) the state
// wanted us to compute it anyway.
PRBool computeMaxElementSize =
(isAutoWidth && (NS_UNCONSTRAINEDSIZE == aMaxElementWidthResult)) ||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
// XXX Why do we have to add in our border/padding?
nsRect availSpace(aState.mAvailSpaceRect.x + aState.BorderPadding().left,
aState.mAvailSpaceRect.y + aState.BorderPadding().top,
aState.mAvailSpaceRect.width, NS_UNCONSTRAINEDSIZE);
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
availWidth, NS_UNCONSTRAINEDSIZE);
// Setup block reflow state to reflow the floater
// Setup a block reflow state to reflow the floater.
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
computeMaxElementSize,
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
brc.SetNextRCFrame(aState.mNextRCFrame);
// Reflow the floater
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
nsReflowStatus frameReflowStatus;
nsresult rv = brc.ReflowBlock(floater, availSpace, PR_TRUE, 0,
isAdjacentWithTop,
nsresult rv = brc.ReflowBlock(floater, availSpace, PR_TRUE, 0, isAdjacentWithTop,
aComputedOffsetsResult, frameReflowStatus);
if (PR_TRUE==brc.BlockShouldInvalidateItself()) {
if (NS_SUCCEEDED(rv) && isAutoWidth && (NS_UNCONSTRAINEDSIZE == aMaxElementWidthResult)) {
// We've just flowed an auto-width floater, but have not yet cached
// the maxElementSize. Do so now.
nsSize maxElementSize = brc.GetMaxElementSize();
aMaxElementWidthResult = maxElementSize.width;
if (aMaxElementWidthResult > availSpace.width) {
// The floater's maxElementSize is larger than the available
// width. Reflow it again, this time pinning the width to the
// maxElementSize.
availSpace.width = aMaxElementWidthResult;
rv = brc.ReflowBlock(floater, availSpace, PR_TRUE, 0, isAdjacentWithTop,
aComputedOffsetsResult, frameReflowStatus);
}
}
if (brc.BlockShouldInvalidateItself()) {
Invalidate(aState.mPresContext, mRect);
}
if (floater == aState.mNextRCFrame) {
// NULL out mNextRCFrame so if we reflow it again we don't think it's still
// an incremental reflow
// Null out mNextRCFrame so if we reflow it again, we don't think
// it's still an incremental reflow
aState.mNextRCFrame = nsnull;
}
if (NS_FAILED(rv)) {
return rv;
}
@ -4837,7 +4874,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
aMarginResult.left = m.left;
const nsHTMLReflowMetrics& metrics = brc.GetMetrics();
aCombinedRect = metrics.mOverflowArea;
aCombinedRectResult = metrics.mOverflowArea;
// Set the rect, make sure the view is properly sized and positioned,
// and tell the frame we're done reflowing it
floater->SizeTo(aState.mPresContext, metrics.width, metrics.height);

View File

@ -351,9 +351,10 @@ protected:
nsresult ReflowFloater(nsBlockReflowState& aState,
nsPlaceholderFrame* aPlaceholder,
nsRect& aCombinedRect,
nsRect& aCombinedRectResult,
nsMargin& aMarginResult,
nsMargin& aComputedOffsetsResult);
nsMargin& aComputedOffsetsResult,
nscoord& aMaxElementWidthResult);
//----------------------------------------
// Methods for pushing/pulling lines/frames
@ -482,9 +483,5 @@ protected:
#endif
};
// Some #ifdef'd bug fixes
#define FIX_BUG_38157
#define FIX_BUG_37657
#endif /* nsBlockFrame_h___ */

View File

@ -314,8 +314,10 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
(const nsStyleStruct*&)display);
if ((eStyleUnit_Auto == widthUnit) &&
((NS_STYLE_FLOAT_LEFT == display->mFloats) ||
(NS_STYLE_FLOAT_RIGHT == display->mFloats)))
{
(NS_STYLE_FLOAT_RIGHT == display->mFloats))) {
// Construct the reflow state using the ctor that explicitly
// constrains the containing block's width and height to the
// available width and height.
nsHTMLReflowState autoReflowState(mPresContext, mOuterReflowState, aFrame,
availSpace, aSpace.width, aSpace.height);
autoReflowState.reason = reason;
@ -325,8 +327,10 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
aComputedOffsets,
aFrameReflowStatus);
}
else
{
else {
// Construct the reflow state using the ctor that will use the
// containing block's computed width and height (or handle derive
// appropriate values for an absolutely positioned frame).
nsHTMLReflowState normalReflowState(mPresContext, mOuterReflowState, aFrame,
availSpace, reason);
rv = DoReflowBlock(normalReflowState, reason, aFrame, aSpace,

View File

@ -43,6 +43,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
: mBlock(aFrame),
mPresContext(aPresContext),
mReflowState(aReflowState),
mLastFloaterY(0),
mNextRCFrame(nsnull),
mPrevBottomMargin(0),
mLineNumber(0),
@ -93,18 +94,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
// Choose a width based on the content (shrink wrap width) up
// to the maximum width
// Part 2 of a possible fix for 38157
#ifdef FIX_BUG_38157
const nsMargin& margin = Margin();
nscoord availContentWidth = aReflowState.availableWidth;
if (NS_UNCONSTRAINEDSIZE != availContentWidth) {
availContentWidth -= (borderPadding.left + borderPadding.right) +
(margin.left + margin.right);
}
mContentArea.width = PR_MIN(aReflowState.mComputedMaxWidth, availContentWidth);
#else
mContentArea.width = aReflowState.mComputedMaxWidth;
#endif
SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
}
else {
@ -606,6 +596,7 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine,
}
#endif
mSpaceManager->AddRectRegion(floater, fc->mRegion);
mLastFloaterY = fc->mRegion.y;
fc = fc->Next();
}
#ifdef DEBUG
@ -702,13 +693,9 @@ nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
nscoord dy = oy - mSpaceManagerY;
mSpaceManager->Translate(-dx, -dy);
// Reflow the floater
mBlock->ReflowFloater(*this, aPlaceholder, fc->mCombinedArea,
fc->mMargins, fc->mOffsets);
// And then place it
PRBool isLeftFloater;
PlaceFloater(fc, &isLeftFloater);
FlowAndPlaceFloater(fc, &isLeftFloater);
// Pass on updated available space to the current inline reflow engine
GetAvailableSpace();
@ -907,8 +894,8 @@ nsBlockReflowState::CanPlaceFloater(const nsRect& aFloaterRect,
}
void
nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
PRBool* aIsLeftFloater)
nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
PRBool* aIsLeftFloater)
{
// Save away the Y coordinate before placing the floater. We will
// restore mY at the end after placing the floater. This is
@ -916,9 +903,14 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
// placement are for the floater only, not for any non-floating
// content.
nscoord saveY = mY;
// Grab the compatibility mode
nsCompatibility mode;
mPresContext->GetCompatibilityMode(&mode);
nsIFrame* floater = aFloaterCache->mPlaceholder->GetOutOfFlowFrame();
// Get the type of floater
// Grab the floater's display information
const nsStyleDisplay* floaterDisplay;
const nsStylePosition* floaterPosition;
floater->GetStyleData(eStyleStruct_Display,
@ -926,59 +918,72 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
floater->GetStyleData(eStyleStruct_Position,
(const nsStyleStruct*&)floaterPosition);
// See if the floater should clear any preceeding floaters...
if (NS_STYLE_CLEAR_NONE != floaterDisplay->mBreakType) {
ClearFloaters(mY, floaterDisplay->mBreakType);
}
else {
// Get the band of available space
GetAvailableSpace();
}
// Get the floaters bounding box and margin information
// This will hold the floater's geometry when we've found a place
// for it to live.
nsRect region;
floater->GetRect(region);
// Adjust the floater size by its margin. That's the area that will
// impact the space manager.
region.width += aFloaterCache->mMargins.left + aFloaterCache->mMargins.right;
region.height += aFloaterCache->mMargins.top + aFloaterCache->mMargins.bottom;
// Advance mY to mLastFloaterY (if it's not past it already) to
// enforce 9.5.1 rule [2]; i.e., make sure that a float isn't
// ``above'' another float that preceded it in the flow.
mY = NS_MAX(mLastFloaterY, mY);
// Find a place to place the floater. The CSS2 spec doesn't want
// floaters overlapping each other or sticking out of the containing
// block if possible (CSS2 spec section 9.5.1, see the rule list).
NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) ||
(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats),
"invalid float type");
// While there is not enough room for the floater, clear past other
// floaters until there is room (or the band is not impacted by a
// floater).
//
// Note: The CSS2 spec says that floaters should be placed as high
// as possible.
//
#ifdef FIX_BUG_37657
// Also note that in backwards compatibility mode, we skip this step
// for tables, since in old browsers, floating tables are horizontally
// stacked regardless of available space. (See bug 43086 about
// tables vs. non-tables.)
nsCompatibility mode;
mPresContext->GetCompatibilityMode(&mode);
if ((eCompatibility_NavQuirks != mode) ||
(NS_STYLE_DISPLAY_TABLE != floaterDisplay->mDisplay)) {
while (!CanPlaceFloater(region, floaterDisplay->mFloats)) {
mY += mAvailSpaceRect.height;
while (1) {
// See if the floater should clear any preceeding floaters...
if (NS_STYLE_CLEAR_NONE != floaterDisplay->mBreakType) {
ClearFloaters(mY, floaterDisplay->mBreakType);
}
else {
// Get the band of available space
GetAvailableSpace();
}
}
#else
while (!CanPlaceFloater(region, floaterDisplay->mFloats)) {
mY += mAvailSpaceRect.height;
GetAvailableSpace();
}
// Reflow the floater
mBlock->ReflowFloater(*this, aFloaterCache->mPlaceholder, aFloaterCache->mCombinedArea,
aFloaterCache->mMargins, aFloaterCache->mOffsets,
aFloaterCache->mMaxElementWidth);
// Get the floaters bounding box and margin information
floater->GetRect(region);
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow) {
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("flowed floater: ");
nsFrame::ListTag(stdout, floater);
printf(" (%d,%d,%d,%d), max-element-width=%d\n",
region.x, region.y, region.width, region.height,
aFloaterCache->mMaxElementWidth);
}
#endif
// Adjust the floater size by its margin. That's the area that will
// impact the space manager.
region.width += aFloaterCache->mMargins.left + aFloaterCache->mMargins.right;
region.height += aFloaterCache->mMargins.top + aFloaterCache->mMargins.bottom;
// Find a place to place the floater. The CSS2 spec doesn't want
// floaters overlapping each other or sticking out of the containing
// block if possible (CSS2 spec section 9.5.1, see the rule list).
NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) ||
(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats),
"invalid float type");
// In backwards compatibility mode, we don't bother to see if a
// floated table can ``really'' fit: in old browsers, floating
// tables are horizontally stacked regardless of available space.
// (See bug 43086 about tables vs. non-tables.)
if ((eCompatibility_NavQuirks == mode) &&
(NS_STYLE_DISPLAY_TABLE == floaterDisplay->mDisplay))
break;
// Can the floater fit here?
if (CanPlaceFloater(region, floaterDisplay->mFloats))
break;
// Nope. Advance to the next band.
mY += mAvailSpaceRect.height;
}
// Assign an x and y coordinate to the floater. Note that the x,y
// coordinates are computed <b>relative to the translation in the
// spacemanager</b> which means that the impacted region will be
@ -1082,6 +1087,9 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
nsBlockFrame::CombineRects(combinedArea, mFloaterCombinedArea);
}
// Remember the y-coordinate of the floater we've just placed
mLastFloaterY = mY;
// Now restore mY
mY = saveY;
@ -1091,7 +1099,7 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
floater->GetRect(r);
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("placed floater: ");
((nsFrame*)floater)->ListTag(stdout);
nsFrame::ListTag(stdout, floater);
printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
}
#endif
@ -1114,12 +1122,10 @@ nsBlockReflowState::PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aList)
printf("\n");
}
#endif
mBlock->ReflowFloater(*this, fc->mPlaceholder, fc->mCombinedArea,
fc->mMargins, fc->mOffsets);
// Place the floater
PRBool isLeftFloater;
PlaceFloater(fc, &isLeftFloater);
FlowAndPlaceFloater(fc, &isLeftFloater);
}
fc = fc->Next();
}

View File

@ -65,8 +65,8 @@ public:
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
void PlaceFloater(nsFloaterCache* aFloaterCache,
PRBool* aIsLeftFloater);
void FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
PRBool* aIsLeftFloater);
void PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aFloaters);
@ -177,6 +177,10 @@ public:
// The combined area of all floaters placed so far
nsRect mFloaterCombinedArea;
// The y-coordinate of the last floater placed. We keep this around
// to enforce 9.5.1 rule [2]
nscoord mLastFloaterY;
// For unconstained-width reflow, we keep the right floaters
// combined area stored seperately.
PRBool mHaveRightFloaters;

View File

@ -355,20 +355,20 @@ NS_IMETHODIMP
nsInlineFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
{
// The inline container frame does not handle the reflow
// request. It passes it up to its parent container.
// request. It passes it up to its parent container.
// If you don't already have dirty children,
if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) {
if (mParent) {
// Record that you are dirty and have dirty children
// Record that you are dirty and have dirty children
mState |= NS_FRAME_IS_DIRTY;
mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
// Pass the reflow request up to the parent
mParent->ReflowDirtyChild(aPresShell, (nsIFrame*) this);
// Pass the reflow request up to the parent
mParent->ReflowDirtyChild(aPresShell, this);
}
else {
NS_ASSERTION(0, "No parent to pass the reflow request up to.");
NS_ERROR("No parent to pass the reflow request up to.");
}
}

View File

@ -1097,6 +1097,7 @@ nsFloaterCache::nsFloaterCache()
mMargins(0, 0, 0, 0),
mOffsets(0, 0, 0, 0),
mCombinedArea(0, 0, 0, 0),
mMaxElementWidth(NS_UNCONSTRAINEDSIZE),
mNext(nsnull)
{
MOZ_COUNT_CTOR(nsFloaterCache);

View File

@ -67,6 +67,9 @@ public:
// the containing block frame.
nsRect mCombinedArea;
// The max element size for the floater.
nscoord mMaxElementWidth;
protected:
nsFloaterCache* mNext;