diff --git a/mozilla/layout/base/public/nsHTMLReflowState.h b/mozilla/layout/base/public/nsHTMLReflowState.h
index 1ceaf6b16d4..c31377197ba 100644
--- a/mozilla/layout/base/public/nsHTMLReflowState.h
+++ b/mozilla/layout/base/public/nsHTMLReflowState.h
@@ -91,59 +91,66 @@ typedef PRUint32 nsCSSFrameType;
#define NS_FRAME_GET_TYPE(_ft) \
((_ft) & ~NS_CSS_FRAME_TYPE_REPLACED)
-#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE
-#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE
-#define NS_AUTOMARGIN NS_UNCONSTRAINEDSIZE
+#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE
+#define NS_SHRINKWRAPWIDTH NS_UNCONSTRAINEDSIZE
+#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE
+#define NS_AUTOMARGIN NS_UNCONSTRAINEDSIZE
/**
- * Reflow state passed to a frame during reflow. The reflow states are linked
- * together. The availableWidth and availableHeight represent the available
- * space in which to reflow your frame, and are computed based on the parent
- * frame's computed width and computed height. The available space is the total
- * space including margins, border, padding, and content area. A value of
- * NS_UNCONSTRAINEDSIZE means you can choose whatever size you want
+ * Reflow state passed to a frame during reflow.
*
- * @see #Reflow()
+ * @see nsIFrame#Reflow()
*/
struct nsHTMLReflowState {
- // pointer to parent's reflow state
+ // the reflow states are linked together. this is the pointer to the
+ // parent's reflow state
const nsHTMLReflowState* parentReflowState;
// the frame being reflowed
- nsIFrame* frame;
+ nsIFrame* frame;
// the reason for the reflow
- nsReflowReason reason;
+ nsReflowReason reason;
- // the reflow command. only set for eReflowReason_Incremental
- nsIReflowCommand* reflowCommand;
+ // the reflow command. only set for a reflow reason of eReflowReason_Incremental
+ nsIReflowCommand* reflowCommand;
- // the available space in which to reflow
+ // the available space in which to reflow the frame. The space represents the
+ // amount of room for the frame's border, padding, and content area (not the
+ // margin area. The parent frame deals with the child frame's margins). The
+ // frame size you choose should fit within the available space.
+ // A value of NS_UNCONSTRAINEDSIZE for the available height means you can
+ // choose whatever size you want. In galley mode the available height is always
+ // NS_UNCONSTRAINEDSIZE, and only page mode involves a constrained height
nscoord availableWidth, availableHeight;
// rendering context to use for measurement
nsIRenderingContext* rendContext;
// is the current context at the top of a page?
- PRPackedBool isTopOfPage;
+ PRPackedBool isTopOfPage;
// The type of frame, from css's perspective. This value is
// initialized by the Init method below.
nsCSSFrameType mFrameType;
+ // pointer to the space manager associated with this area
nsISpaceManager* mSpaceManager;
// LineLayout object (only for inline reflow; set to NULL otherwise)
nsLineLayout* mLineLayout;
- // The computed width specifies the frame's content width, and it does not
- // apply to inline non-replaced elements
+ // The computed width specifies the frame's content area width, and it does
+ // not apply to inline non-replaced elements
//
// For replaced inline frames, a value of NS_INTRINSICSIZE means you should
// use your intrinsic width as the computed width
//
// For block-level frames, the computed width is based on the width of the
- // containing block, the margin/border/padding areas, and the min/max width
+ // containing block, the margin/border/padding areas, and the min/max width.
+ // A value of NS_SHRINKWRAPWIDTH means that you should choose a width based
+ // on your content. The width may be as large as the specified maximum width
+ // (see mComputedMaxWidth).
nscoord mComputedWidth;
// The computed height specifies the frame's content height, and it does
diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp
index 1eef663b005..f4021a10da9 100644
--- a/mozilla/layout/generic/nsBlockFrame.cpp
+++ b/mozilla/layout/generic/nsBlockFrame.cpp
@@ -272,7 +272,8 @@ public:
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics);
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot);
~nsBlockReflowState();
@@ -449,6 +450,10 @@ public:
PRBool mUnconstrainedHeight;
+ PRBool mShrinkWrapWidth;
+
+ PRBool mNeedResizeReflow;
+
// The content area to reflow child frames within. The x/y
// coordinates are known to be mBorderPadding.left and
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
@@ -564,7 +569,8 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics)
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot)
: mBlock(aFrame),
mPresContext(aPresContext),
mReflowState(aReflowState),
@@ -574,8 +580,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mNextRCFrame(nsnull),
mPrevBottomMargin(0),
mFreeLineList(nsnull),
- mLineNumber(0)
+ mLineNumber(0),
+ mNeedResizeReflow(PR_FALSE)
{
+ if (aBlockMarginRoot) {
+ mIsTopMarginRoot = PR_TRUE;
+ mIsBottomMarginRoot = PR_TRUE;
+ }
+ if (mIsTopMarginRoot) {
+ mApplyTopMargin = PR_TRUE;
+ }
+
mSpaceManager = aReflowState.mSpaceManager;
// Translate into our content area and then save the
@@ -593,6 +608,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
// Compute content area width (the content area is inside the border
// and padding)
mUnconstrainedWidth = PR_FALSE;
+ mShrinkWrapWidth = PR_FALSE;
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
mContentArea.width = aReflowState.mComputedWidth;
}
@@ -601,6 +617,12 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mContentArea.width = NS_UNCONSTRAINEDSIZE;
mUnconstrainedWidth = PR_TRUE;
}
+ else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
+ // Choose a width based on the content (shrink wrap width) up
+ // to the maximum width
+ mContentArea.width = aReflowState.mComputedMaxWidth;
+ mShrinkWrapWidth = PR_TRUE;
+ }
else {
nscoord lr = borderPadding.left + borderPadding.right;
mContentArea.width = aReflowState.availableWidth - lr;
@@ -1423,14 +1445,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
reflowState.mSpaceManager = spaceManager.get();
}
- nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics);
- if (NS_BLOCK_MARGIN_ROOT & mState) {
- state.mIsTopMarginRoot = PR_TRUE;
- state.mIsBottomMarginRoot = PR_TRUE;
- }
- if (state.mIsTopMarginRoot) {
- state.mApplyTopMargin = PR_TRUE;
- }
+ nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
if (eReflowReason_Resize != aReflowState.reason) {
RenumberLists();
@@ -1792,7 +1808,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
// contents or we fluff out to the maximum block width. Note:
// We always shrink wrap when given an unconstrained width.
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
- !aState.mUnconstrainedWidth &&
+ !aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
!compact) {
// Set our width to the max width if we aren't already that
// wide. Note that the max-width has nothing to do with our
@@ -1826,7 +1842,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
nscoord computedMaxWidth = aReflowState.mComputedMaxWidth +
borderPadding.left + borderPadding.right;
if (computedWidth > computedMaxWidth) {
- computedWidth = aReflowState.mComputedMaxWidth;
+ computedWidth = computedMaxWidth;
}
}
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) {
@@ -1837,6 +1853,47 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
}
}
aMetrics.width = computedWidth;
+
+ // If we're shrink wrapping, then now that we know our final width we
+ // need to do horizontal alignment of the inline lines and make sure
+ // blocks are correctly sized and positioned. Any lines that need
+ // final adjustment will have been marked as dirty
+ if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
+ // If the parent reflow state is also shrink wrap width, then
+ // we don't need to do this, because it will reflow us after it
+ // calculates the final width
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
+
+ if (!parentIsShrinkWrapWidth) {
+ nsHTMLReflowState reflowState(aReflowState);
+
+ reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
+ borderPadding.right;
+ reflowState.reason = eReflowReason_Resize;
+ reflowState.mSpaceManager->ClearRegions();
+
+ nscoord oldDesiredWidth = aMetrics.width;
+ nsBlockReflowState state(reflowState, aState.mPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
+ ReflowDirtyLines(state);
+ aState.mY = state.mY;
+ NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width");
+ }
+ }
+ }
+
+ if (aState.mShrinkWrapWidth) {
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
}
// Compute final height
@@ -2182,8 +2239,14 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
nsLineBox* line = mLines;
if (tryAndSkipLines) {
// The line's bounds are relative to the border edge of the frame
- nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left +
- aState.mReflowState.mComputedWidth;
+ nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
+
+ if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
+ newAvailWidth += aState.mReflowState.mComputedMaxWidth;
+ } else {
+ newAvailWidth += aState.mReflowState.mComputedWidth;
+ }
+
#ifdef DEBUG
if (gNoisyReflow) {
IndentBy(stdout, gNoiseIndent);
@@ -2685,6 +2748,7 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
}
else {
+ aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// We don't really know what changed in the line, so use the union
@@ -3295,6 +3359,21 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
&collapsedBottomMargin,
aLine->mBounds, combinedArea);
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line as block so once we known the final shrink wrap width
+ // we can reflow the block to the correct size
+ // XXX We don't always need to do this...
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+
+ // Add the right margin to the line's bounnds. That way it will be taken into
+ // account when we compute our shrink wrap size
+ nscoord marginRight = brc.GetMargin().right;
+ if (marginRight != NS_UNCONSTRAINEDSIZE) {
+ aLine->mBounds.width += marginRight;
+ }
+
+ }
aLine->SetCombinedArea(combinedArea);
if (*aKeepReflowGoing) {
// Some of the child block fit
@@ -3703,8 +3782,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
// Reflow the inline frame
nsReflowStatus frameReflowStatus;
+ PRBool pushedFrame;
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
- frameReflowStatus);
+ frameReflowStatus, nsnull, pushedFrame);
if (NS_FAILED(rv)) {
return rv;
}
@@ -3752,6 +3832,13 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+
+ // If we're splitting the line because the frame didn't fit and it
+ // was pushed, then mark the line as having word wrapped. We need to
+ // know that if we're shrink wrapping our width
+ if (pushedFrame) {
+ aLine->SetLineWrapped(PR_TRUE);
+ }
}
}
else {
@@ -3770,6 +3857,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
}
// Split line, but after the frame just reflowed
@@ -3799,6 +3888,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
+
// If we are reflowing the first letter frame then don't split the
// line and don't stop the line reflow...
PRBool splitLine = !reflowingFirstLetter;
@@ -3988,6 +4080,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
}
nsSize maxElementSize;
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
+ // See if we're shrink wrapping the width
+ if (aState.mShrinkWrapWidth) {
+ // When determining the line's width we also need to include any
+ // right floaters that impact us. This represents the shrink wrap
+ // width of the line
+ if (aState.IsImpactedByFloater() && !aLine->IsLineWrapped()) {
+ NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state");
+ aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost();
+ }
+ }
#ifdef DEBUG
{
static nscoord lastHeight = 0;
@@ -4016,8 +4118,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#else
PRBool allowJustify = PR_FALSE;
#endif
- aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
+
+ PRBool successful;
nsRect combinedArea;
+ successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
+ aState.mShrinkWrapWidth);
+ if (!successful) {
+ // Mark the line dirty and then later once we've determined the width
+ // we can do the horizontal alignment
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
aLineLayout.RelativePositionFrames(combinedArea);
aLine->SetCombinedArea(combinedArea);
if (addedBullet) {
@@ -4113,17 +4224,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
- if (aState.mUnconstrainedWidth && aState.mHaveRightFloaters) {
- // We are reflowing in an unconstrained situation and have some
- // right floaters. They were placed at the infinite right edge
+ if (aState.mHaveRightFloaters &&
+ (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
+ // We are reflowing in an unconstrained situation or shrink wrapping and
+ // have some right floaters. They were placed at the infinite right edge
// which will cause the combined area to be unusable.
//
- // To solve this issue, we pretend that the right floaters ended
- // up just past the end of the line. Note that the right floater
- // combined area we computed as we were going will have as its X
- // coordinate the left most edge of all the right
- // floaters. Therefore, to accomplish our goal all we do is set
- // that X value to the lines XMost value.
+ // To solve this issue, we pretend that the right floaters ended up just
+ // past the end of the line. Note that the right floater combined area
+ // we computed as we were going will have as its X coordinate the left
+ // most edge of all the right floaters. Therefore, to accomplish our goal
+ // all we do is set that X value to the lines XMost value.
#ifdef NOISY_COMBINED_AREA
printf(" ==> rightFloaterCA=%d,%d,%d,%d lineXMost=%d\n",
aState.mRightFloaterCombinedArea.x,
@@ -4134,6 +4245,13 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
+
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line dirty so we come back and re-place the floater once
+ // the shrink wrap width is determined
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
}
aLine->SetCombinedArea(lineCombinedArea);
#ifdef NOISY_COMBINED_AREA
@@ -4239,7 +4357,13 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
printf(": line=%p xmost=%d\n", aLine, xmost);
}
#endif
- if (xmost > aState.mKidXMost) {
+ // 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.mShrinkWrapWidth && aLine->IsLineWrapped()) {
+ aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
+
+ }
+ else if (xmost > aState.mKidXMost) {
aState.mKidXMost = xmost;
}
}
@@ -5228,7 +5352,7 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
#ifdef DEBUG
nsresult rv =
#endif
- mSpaceManager->AddRectRegion(floater, region);
+ mSpaceManager->AddRectRegion(floater, region);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad floater placement");
}
@@ -5276,13 +5400,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
nsRect combinedArea = aFloaterCache->mCombinedArea;
combinedArea.x += x;
combinedArea.y += y;
- if (!isLeftFloater && mUnconstrainedWidth) {
- // When we are placing a right floater in an unconstrained
- // situation we don't apply it to the floater combined area
- // immediately. Otherwise we end up with an infinitely wide
- // combined area. Instead, we save it away in
- // mRightFloaterCombinedArea so that later on when we know the
- // width of a line we can compute a better value.
+ if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
+ // When we are placing a right floater in an unconstrained situation or
+ // when shrink wrapping, we don't apply it to the floater combined area
+ // immediately. Otherwise we end up with an infinitely wide combined
+ // area. Instead, we save it away in mRightFloaterCombinedArea so that
+ // later on when we know the width of a line we can compute a better value.
if (!mHaveRightFloaters) {
mRightFloaterCombinedArea = combinedArea;
mHaveRightFloaters = PR_TRUE;
diff --git a/mozilla/layout/generic/nsBlockReflowContext.cpp b/mozilla/layout/generic/nsBlockReflowContext.cpp
index c2f025bf805..5fbfe4f2f6c 100644
--- a/mozilla/layout/generic/nsBlockReflowContext.cpp
+++ b/mozilla/layout/generic/nsBlockReflowContext.cpp
@@ -358,6 +358,63 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
}
}
+ // If the block is shrink wrapping its width, then see if we have percentage
+ // based margins. If so, we can calculate them now that we know the shrink
+ // wrap width
+ if (NS_SHRINKWRAPWIDTH == reflowState.mComputedWidth) {
+ nscoord boxWidth = mMetrics.width;
+ float leftPct = 0.0;
+ float rightPct = 0.0;
+
+ if (eStyleUnit_Percent == reflowState.mStyleSpacing->mMargin.GetLeftUnit()) {
+ nsStyleCoord leftCoord;
+
+ reflowState.mStyleSpacing->mMargin.GetLeft(leftCoord);
+ leftPct = leftCoord.GetPercentValue();
+
+ } else {
+ boxWidth += mMargin.left;
+ }
+
+ if (eStyleUnit_Percent == reflowState.mStyleSpacing->mMargin.GetRightUnit()) {
+ nsStyleCoord rightCoord;
+
+ reflowState.mStyleSpacing->mMargin.GetRight(rightCoord);
+ rightPct = rightCoord.GetPercentValue();
+
+ } else {
+ boxWidth += mMargin.right;
+ }
+
+ // The total shrink wrap width "sww" is calculated by the expression:
+ // sww = bw + (mp * sww)
+ // where "bw" is the box width (frame width plus margins that aren't percentage
+ // based) and "mp" are the total margin percentages (i.e., the left percentage
+ // value plus the right percentage value)
+ // Solving for "sww" gives us:
+ // sww = bw / (1 - mp)
+ // Note that this is only well defined for "mp" less than 100%
+ float marginPct = leftPct + rightPct;
+ if (marginPct >= 1.0) {
+ // Ignore the right percentage and just use the left percentage
+ // XXX Pay attention to direction property...
+ marginPct = leftPct;
+ rightPct = 0.0;
+ }
+
+ if ((marginPct > 0.0) && (marginPct < 1.0)) {
+ double shrinkWrapWidth = float(boxWidth) / (1.0 - marginPct);
+
+ if (eStyleUnit_Percent == reflowState.mStyleSpacing->mMargin.GetLeftUnit()) {
+ mMargin.left = NSToCoordFloor(shrinkWrapWidth * leftPct);
+ mX += mMargin.left;
+ }
+ if (eStyleUnit_Percent == reflowState.mStyleSpacing->mMargin.GetRightUnit()) {
+ mMargin.right = NSToCoordFloor(shrinkWrapWidth * rightPct);
+ }
+ }
+ }
+
return rv;
}
diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp
index 1eef663b005..f4021a10da9 100644
--- a/mozilla/layout/generic/nsBlockReflowState.cpp
+++ b/mozilla/layout/generic/nsBlockReflowState.cpp
@@ -272,7 +272,8 @@ public:
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics);
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot);
~nsBlockReflowState();
@@ -449,6 +450,10 @@ public:
PRBool mUnconstrainedHeight;
+ PRBool mShrinkWrapWidth;
+
+ PRBool mNeedResizeReflow;
+
// The content area to reflow child frames within. The x/y
// coordinates are known to be mBorderPadding.left and
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
@@ -564,7 +569,8 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics)
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot)
: mBlock(aFrame),
mPresContext(aPresContext),
mReflowState(aReflowState),
@@ -574,8 +580,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mNextRCFrame(nsnull),
mPrevBottomMargin(0),
mFreeLineList(nsnull),
- mLineNumber(0)
+ mLineNumber(0),
+ mNeedResizeReflow(PR_FALSE)
{
+ if (aBlockMarginRoot) {
+ mIsTopMarginRoot = PR_TRUE;
+ mIsBottomMarginRoot = PR_TRUE;
+ }
+ if (mIsTopMarginRoot) {
+ mApplyTopMargin = PR_TRUE;
+ }
+
mSpaceManager = aReflowState.mSpaceManager;
// Translate into our content area and then save the
@@ -593,6 +608,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
// Compute content area width (the content area is inside the border
// and padding)
mUnconstrainedWidth = PR_FALSE;
+ mShrinkWrapWidth = PR_FALSE;
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
mContentArea.width = aReflowState.mComputedWidth;
}
@@ -601,6 +617,12 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mContentArea.width = NS_UNCONSTRAINEDSIZE;
mUnconstrainedWidth = PR_TRUE;
}
+ else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
+ // Choose a width based on the content (shrink wrap width) up
+ // to the maximum width
+ mContentArea.width = aReflowState.mComputedMaxWidth;
+ mShrinkWrapWidth = PR_TRUE;
+ }
else {
nscoord lr = borderPadding.left + borderPadding.right;
mContentArea.width = aReflowState.availableWidth - lr;
@@ -1423,14 +1445,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
reflowState.mSpaceManager = spaceManager.get();
}
- nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics);
- if (NS_BLOCK_MARGIN_ROOT & mState) {
- state.mIsTopMarginRoot = PR_TRUE;
- state.mIsBottomMarginRoot = PR_TRUE;
- }
- if (state.mIsTopMarginRoot) {
- state.mApplyTopMargin = PR_TRUE;
- }
+ nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
if (eReflowReason_Resize != aReflowState.reason) {
RenumberLists();
@@ -1792,7 +1808,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
// contents or we fluff out to the maximum block width. Note:
// We always shrink wrap when given an unconstrained width.
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
- !aState.mUnconstrainedWidth &&
+ !aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
!compact) {
// Set our width to the max width if we aren't already that
// wide. Note that the max-width has nothing to do with our
@@ -1826,7 +1842,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
nscoord computedMaxWidth = aReflowState.mComputedMaxWidth +
borderPadding.left + borderPadding.right;
if (computedWidth > computedMaxWidth) {
- computedWidth = aReflowState.mComputedMaxWidth;
+ computedWidth = computedMaxWidth;
}
}
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) {
@@ -1837,6 +1853,47 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
}
}
aMetrics.width = computedWidth;
+
+ // If we're shrink wrapping, then now that we know our final width we
+ // need to do horizontal alignment of the inline lines and make sure
+ // blocks are correctly sized and positioned. Any lines that need
+ // final adjustment will have been marked as dirty
+ if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
+ // If the parent reflow state is also shrink wrap width, then
+ // we don't need to do this, because it will reflow us after it
+ // calculates the final width
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
+
+ if (!parentIsShrinkWrapWidth) {
+ nsHTMLReflowState reflowState(aReflowState);
+
+ reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
+ borderPadding.right;
+ reflowState.reason = eReflowReason_Resize;
+ reflowState.mSpaceManager->ClearRegions();
+
+ nscoord oldDesiredWidth = aMetrics.width;
+ nsBlockReflowState state(reflowState, aState.mPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
+ ReflowDirtyLines(state);
+ aState.mY = state.mY;
+ NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width");
+ }
+ }
+ }
+
+ if (aState.mShrinkWrapWidth) {
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
}
// Compute final height
@@ -2182,8 +2239,14 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
nsLineBox* line = mLines;
if (tryAndSkipLines) {
// The line's bounds are relative to the border edge of the frame
- nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left +
- aState.mReflowState.mComputedWidth;
+ nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
+
+ if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
+ newAvailWidth += aState.mReflowState.mComputedMaxWidth;
+ } else {
+ newAvailWidth += aState.mReflowState.mComputedWidth;
+ }
+
#ifdef DEBUG
if (gNoisyReflow) {
IndentBy(stdout, gNoiseIndent);
@@ -2685,6 +2748,7 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
}
else {
+ aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// We don't really know what changed in the line, so use the union
@@ -3295,6 +3359,21 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
&collapsedBottomMargin,
aLine->mBounds, combinedArea);
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line as block so once we known the final shrink wrap width
+ // we can reflow the block to the correct size
+ // XXX We don't always need to do this...
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+
+ // Add the right margin to the line's bounnds. That way it will be taken into
+ // account when we compute our shrink wrap size
+ nscoord marginRight = brc.GetMargin().right;
+ if (marginRight != NS_UNCONSTRAINEDSIZE) {
+ aLine->mBounds.width += marginRight;
+ }
+
+ }
aLine->SetCombinedArea(combinedArea);
if (*aKeepReflowGoing) {
// Some of the child block fit
@@ -3703,8 +3782,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
// Reflow the inline frame
nsReflowStatus frameReflowStatus;
+ PRBool pushedFrame;
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
- frameReflowStatus);
+ frameReflowStatus, nsnull, pushedFrame);
if (NS_FAILED(rv)) {
return rv;
}
@@ -3752,6 +3832,13 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+
+ // If we're splitting the line because the frame didn't fit and it
+ // was pushed, then mark the line as having word wrapped. We need to
+ // know that if we're shrink wrapping our width
+ if (pushedFrame) {
+ aLine->SetLineWrapped(PR_TRUE);
+ }
}
}
else {
@@ -3770,6 +3857,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
}
// Split line, but after the frame just reflowed
@@ -3799,6 +3888,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
+
// If we are reflowing the first letter frame then don't split the
// line and don't stop the line reflow...
PRBool splitLine = !reflowingFirstLetter;
@@ -3988,6 +4080,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
}
nsSize maxElementSize;
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
+ // See if we're shrink wrapping the width
+ if (aState.mShrinkWrapWidth) {
+ // When determining the line's width we also need to include any
+ // right floaters that impact us. This represents the shrink wrap
+ // width of the line
+ if (aState.IsImpactedByFloater() && !aLine->IsLineWrapped()) {
+ NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state");
+ aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost();
+ }
+ }
#ifdef DEBUG
{
static nscoord lastHeight = 0;
@@ -4016,8 +4118,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#else
PRBool allowJustify = PR_FALSE;
#endif
- aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
+
+ PRBool successful;
nsRect combinedArea;
+ successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
+ aState.mShrinkWrapWidth);
+ if (!successful) {
+ // Mark the line dirty and then later once we've determined the width
+ // we can do the horizontal alignment
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
aLineLayout.RelativePositionFrames(combinedArea);
aLine->SetCombinedArea(combinedArea);
if (addedBullet) {
@@ -4113,17 +4224,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
- if (aState.mUnconstrainedWidth && aState.mHaveRightFloaters) {
- // We are reflowing in an unconstrained situation and have some
- // right floaters. They were placed at the infinite right edge
+ if (aState.mHaveRightFloaters &&
+ (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
+ // We are reflowing in an unconstrained situation or shrink wrapping and
+ // have some right floaters. They were placed at the infinite right edge
// which will cause the combined area to be unusable.
//
- // To solve this issue, we pretend that the right floaters ended
- // up just past the end of the line. Note that the right floater
- // combined area we computed as we were going will have as its X
- // coordinate the left most edge of all the right
- // floaters. Therefore, to accomplish our goal all we do is set
- // that X value to the lines XMost value.
+ // To solve this issue, we pretend that the right floaters ended up just
+ // past the end of the line. Note that the right floater combined area
+ // we computed as we were going will have as its X coordinate the left
+ // most edge of all the right floaters. Therefore, to accomplish our goal
+ // all we do is set that X value to the lines XMost value.
#ifdef NOISY_COMBINED_AREA
printf(" ==> rightFloaterCA=%d,%d,%d,%d lineXMost=%d\n",
aState.mRightFloaterCombinedArea.x,
@@ -4134,6 +4245,13 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
+
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line dirty so we come back and re-place the floater once
+ // the shrink wrap width is determined
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
}
aLine->SetCombinedArea(lineCombinedArea);
#ifdef NOISY_COMBINED_AREA
@@ -4239,7 +4357,13 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
printf(": line=%p xmost=%d\n", aLine, xmost);
}
#endif
- if (xmost > aState.mKidXMost) {
+ // 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.mShrinkWrapWidth && aLine->IsLineWrapped()) {
+ aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
+
+ }
+ else if (xmost > aState.mKidXMost) {
aState.mKidXMost = xmost;
}
}
@@ -5228,7 +5352,7 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
#ifdef DEBUG
nsresult rv =
#endif
- mSpaceManager->AddRectRegion(floater, region);
+ mSpaceManager->AddRectRegion(floater, region);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad floater placement");
}
@@ -5276,13 +5400,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
nsRect combinedArea = aFloaterCache->mCombinedArea;
combinedArea.x += x;
combinedArea.y += y;
- if (!isLeftFloater && mUnconstrainedWidth) {
- // When we are placing a right floater in an unconstrained
- // situation we don't apply it to the floater combined area
- // immediately. Otherwise we end up with an infinitely wide
- // combined area. Instead, we save it away in
- // mRightFloaterCombinedArea so that later on when we know the
- // width of a line we can compute a better value.
+ if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
+ // When we are placing a right floater in an unconstrained situation or
+ // when shrink wrapping, we don't apply it to the floater combined area
+ // immediately. Otherwise we end up with an infinitely wide combined
+ // area. Instead, we save it away in mRightFloaterCombinedArea so that
+ // later on when we know the width of a line we can compute a better value.
if (!mHaveRightFloaters) {
mRightFloaterCombinedArea = combinedArea;
mHaveRightFloaters = PR_TRUE;
diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h
index 1eef663b005..f4021a10da9 100644
--- a/mozilla/layout/generic/nsBlockReflowState.h
+++ b/mozilla/layout/generic/nsBlockReflowState.h
@@ -272,7 +272,8 @@ public:
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics);
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot);
~nsBlockReflowState();
@@ -449,6 +450,10 @@ public:
PRBool mUnconstrainedHeight;
+ PRBool mShrinkWrapWidth;
+
+ PRBool mNeedResizeReflow;
+
// The content area to reflow child frames within. The x/y
// coordinates are known to be mBorderPadding.left and
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
@@ -564,7 +569,8 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics)
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot)
: mBlock(aFrame),
mPresContext(aPresContext),
mReflowState(aReflowState),
@@ -574,8 +580,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mNextRCFrame(nsnull),
mPrevBottomMargin(0),
mFreeLineList(nsnull),
- mLineNumber(0)
+ mLineNumber(0),
+ mNeedResizeReflow(PR_FALSE)
{
+ if (aBlockMarginRoot) {
+ mIsTopMarginRoot = PR_TRUE;
+ mIsBottomMarginRoot = PR_TRUE;
+ }
+ if (mIsTopMarginRoot) {
+ mApplyTopMargin = PR_TRUE;
+ }
+
mSpaceManager = aReflowState.mSpaceManager;
// Translate into our content area and then save the
@@ -593,6 +608,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
// Compute content area width (the content area is inside the border
// and padding)
mUnconstrainedWidth = PR_FALSE;
+ mShrinkWrapWidth = PR_FALSE;
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
mContentArea.width = aReflowState.mComputedWidth;
}
@@ -601,6 +617,12 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mContentArea.width = NS_UNCONSTRAINEDSIZE;
mUnconstrainedWidth = PR_TRUE;
}
+ else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
+ // Choose a width based on the content (shrink wrap width) up
+ // to the maximum width
+ mContentArea.width = aReflowState.mComputedMaxWidth;
+ mShrinkWrapWidth = PR_TRUE;
+ }
else {
nscoord lr = borderPadding.left + borderPadding.right;
mContentArea.width = aReflowState.availableWidth - lr;
@@ -1423,14 +1445,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
reflowState.mSpaceManager = spaceManager.get();
}
- nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics);
- if (NS_BLOCK_MARGIN_ROOT & mState) {
- state.mIsTopMarginRoot = PR_TRUE;
- state.mIsBottomMarginRoot = PR_TRUE;
- }
- if (state.mIsTopMarginRoot) {
- state.mApplyTopMargin = PR_TRUE;
- }
+ nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
if (eReflowReason_Resize != aReflowState.reason) {
RenumberLists();
@@ -1792,7 +1808,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
// contents or we fluff out to the maximum block width. Note:
// We always shrink wrap when given an unconstrained width.
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
- !aState.mUnconstrainedWidth &&
+ !aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
!compact) {
// Set our width to the max width if we aren't already that
// wide. Note that the max-width has nothing to do with our
@@ -1826,7 +1842,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
nscoord computedMaxWidth = aReflowState.mComputedMaxWidth +
borderPadding.left + borderPadding.right;
if (computedWidth > computedMaxWidth) {
- computedWidth = aReflowState.mComputedMaxWidth;
+ computedWidth = computedMaxWidth;
}
}
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) {
@@ -1837,6 +1853,47 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
}
}
aMetrics.width = computedWidth;
+
+ // If we're shrink wrapping, then now that we know our final width we
+ // need to do horizontal alignment of the inline lines and make sure
+ // blocks are correctly sized and positioned. Any lines that need
+ // final adjustment will have been marked as dirty
+ if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
+ // If the parent reflow state is also shrink wrap width, then
+ // we don't need to do this, because it will reflow us after it
+ // calculates the final width
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
+
+ if (!parentIsShrinkWrapWidth) {
+ nsHTMLReflowState reflowState(aReflowState);
+
+ reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
+ borderPadding.right;
+ reflowState.reason = eReflowReason_Resize;
+ reflowState.mSpaceManager->ClearRegions();
+
+ nscoord oldDesiredWidth = aMetrics.width;
+ nsBlockReflowState state(reflowState, aState.mPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
+ ReflowDirtyLines(state);
+ aState.mY = state.mY;
+ NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width");
+ }
+ }
+ }
+
+ if (aState.mShrinkWrapWidth) {
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
}
// Compute final height
@@ -2182,8 +2239,14 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
nsLineBox* line = mLines;
if (tryAndSkipLines) {
// The line's bounds are relative to the border edge of the frame
- nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left +
- aState.mReflowState.mComputedWidth;
+ nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
+
+ if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
+ newAvailWidth += aState.mReflowState.mComputedMaxWidth;
+ } else {
+ newAvailWidth += aState.mReflowState.mComputedWidth;
+ }
+
#ifdef DEBUG
if (gNoisyReflow) {
IndentBy(stdout, gNoiseIndent);
@@ -2685,6 +2748,7 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
}
else {
+ aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// We don't really know what changed in the line, so use the union
@@ -3295,6 +3359,21 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
&collapsedBottomMargin,
aLine->mBounds, combinedArea);
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line as block so once we known the final shrink wrap width
+ // we can reflow the block to the correct size
+ // XXX We don't always need to do this...
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+
+ // Add the right margin to the line's bounnds. That way it will be taken into
+ // account when we compute our shrink wrap size
+ nscoord marginRight = brc.GetMargin().right;
+ if (marginRight != NS_UNCONSTRAINEDSIZE) {
+ aLine->mBounds.width += marginRight;
+ }
+
+ }
aLine->SetCombinedArea(combinedArea);
if (*aKeepReflowGoing) {
// Some of the child block fit
@@ -3703,8 +3782,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
// Reflow the inline frame
nsReflowStatus frameReflowStatus;
+ PRBool pushedFrame;
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
- frameReflowStatus);
+ frameReflowStatus, nsnull, pushedFrame);
if (NS_FAILED(rv)) {
return rv;
}
@@ -3752,6 +3832,13 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+
+ // If we're splitting the line because the frame didn't fit and it
+ // was pushed, then mark the line as having word wrapped. We need to
+ // know that if we're shrink wrapping our width
+ if (pushedFrame) {
+ aLine->SetLineWrapped(PR_TRUE);
+ }
}
}
else {
@@ -3770,6 +3857,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
}
// Split line, but after the frame just reflowed
@@ -3799,6 +3888,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
+
// If we are reflowing the first letter frame then don't split the
// line and don't stop the line reflow...
PRBool splitLine = !reflowingFirstLetter;
@@ -3988,6 +4080,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
}
nsSize maxElementSize;
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
+ // See if we're shrink wrapping the width
+ if (aState.mShrinkWrapWidth) {
+ // When determining the line's width we also need to include any
+ // right floaters that impact us. This represents the shrink wrap
+ // width of the line
+ if (aState.IsImpactedByFloater() && !aLine->IsLineWrapped()) {
+ NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state");
+ aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost();
+ }
+ }
#ifdef DEBUG
{
static nscoord lastHeight = 0;
@@ -4016,8 +4118,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#else
PRBool allowJustify = PR_FALSE;
#endif
- aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
+
+ PRBool successful;
nsRect combinedArea;
+ successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
+ aState.mShrinkWrapWidth);
+ if (!successful) {
+ // Mark the line dirty and then later once we've determined the width
+ // we can do the horizontal alignment
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
aLineLayout.RelativePositionFrames(combinedArea);
aLine->SetCombinedArea(combinedArea);
if (addedBullet) {
@@ -4113,17 +4224,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
- if (aState.mUnconstrainedWidth && aState.mHaveRightFloaters) {
- // We are reflowing in an unconstrained situation and have some
- // right floaters. They were placed at the infinite right edge
+ if (aState.mHaveRightFloaters &&
+ (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
+ // We are reflowing in an unconstrained situation or shrink wrapping and
+ // have some right floaters. They were placed at the infinite right edge
// which will cause the combined area to be unusable.
//
- // To solve this issue, we pretend that the right floaters ended
- // up just past the end of the line. Note that the right floater
- // combined area we computed as we were going will have as its X
- // coordinate the left most edge of all the right
- // floaters. Therefore, to accomplish our goal all we do is set
- // that X value to the lines XMost value.
+ // To solve this issue, we pretend that the right floaters ended up just
+ // past the end of the line. Note that the right floater combined area
+ // we computed as we were going will have as its X coordinate the left
+ // most edge of all the right floaters. Therefore, to accomplish our goal
+ // all we do is set that X value to the lines XMost value.
#ifdef NOISY_COMBINED_AREA
printf(" ==> rightFloaterCA=%d,%d,%d,%d lineXMost=%d\n",
aState.mRightFloaterCombinedArea.x,
@@ -4134,6 +4245,13 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
+
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line dirty so we come back and re-place the floater once
+ // the shrink wrap width is determined
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
}
aLine->SetCombinedArea(lineCombinedArea);
#ifdef NOISY_COMBINED_AREA
@@ -4239,7 +4357,13 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
printf(": line=%p xmost=%d\n", aLine, xmost);
}
#endif
- if (xmost > aState.mKidXMost) {
+ // 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.mShrinkWrapWidth && aLine->IsLineWrapped()) {
+ aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
+
+ }
+ else if (xmost > aState.mKidXMost) {
aState.mKidXMost = xmost;
}
}
@@ -5228,7 +5352,7 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
#ifdef DEBUG
nsresult rv =
#endif
- mSpaceManager->AddRectRegion(floater, region);
+ mSpaceManager->AddRectRegion(floater, region);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad floater placement");
}
@@ -5276,13 +5400,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
nsRect combinedArea = aFloaterCache->mCombinedArea;
combinedArea.x += x;
combinedArea.y += y;
- if (!isLeftFloater && mUnconstrainedWidth) {
- // When we are placing a right floater in an unconstrained
- // situation we don't apply it to the floater combined area
- // immediately. Otherwise we end up with an infinitely wide
- // combined area. Instead, we save it away in
- // mRightFloaterCombinedArea so that later on when we know the
- // width of a line we can compute a better value.
+ if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
+ // When we are placing a right floater in an unconstrained situation or
+ // when shrink wrapping, we don't apply it to the floater combined area
+ // immediately. Otherwise we end up with an infinitely wide combined
+ // area. Instead, we save it away in mRightFloaterCombinedArea so that
+ // later on when we know the width of a line we can compute a better value.
if (!mHaveRightFloaters) {
mRightFloaterCombinedArea = combinedArea;
mHaveRightFloaters = PR_TRUE;
diff --git a/mozilla/layout/generic/nsFirstLetterFrame.cpp b/mozilla/layout/generic/nsFirstLetterFrame.cpp
index 7a040b2b1be..98faa026c9a 100644
--- a/mozilla/layout/generic/nsFirstLetterFrame.cpp
+++ b/mozilla/layout/generic/nsFirstLetterFrame.cpp
@@ -238,8 +238,10 @@ nsFirstLetterFrame::Reflow(nsIPresContext* aPresContext,
else {
// Pretend we are a span and reflow the child frame
nsLineLayout* ll = aReflowState.mLineLayout;
+ PRBool pushedFrame;
+
ll->BeginSpan(this, &aReflowState, bp.left, availSize.width);
- ll->ReflowFrame(kid, &nextRCFrame, aReflowStatus, &aMetrics);
+ ll->ReflowFrame(kid, &nextRCFrame, aReflowStatus, &aMetrics, pushedFrame);
nsSize size;
ll->EndSpan(this, size, aMetrics.maxElementSize);
}
diff --git a/mozilla/layout/generic/nsHTMLReflowState.cpp b/mozilla/layout/generic/nsHTMLReflowState.cpp
index db583a00731..745b8d39145 100644
--- a/mozilla/layout/generic/nsHTMLReflowState.cpp
+++ b/mozilla/layout/generic/nsHTMLReflowState.cpp
@@ -998,8 +998,23 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
if (eStyleUnit_Inherit == widthUnit) {
mComputedWidth = aContainingBlockWidth;
} else if (eStyleUnit_Auto == widthUnit) {
+ // XXX TROY. Once all the frame classes have been converted to the handle
+ // NS_SHRINKWRAPWIDTH. then we should switch to the new code...
+#if 0
+ // Have it shrink wrap the width
+ mComputedWidth = NS_SHRINKWRAPWIDTH;
+
+ // If there's no specified maximum width, then use 1/3 of the containing
+ // block width
+ if (NS_UNCONSTRAINEDSIZE == mComputedMaxWidth) {
+ if (NS_UNCONSTRAINEDSIZE != aContainingBlockWidth) {
+ mComputedMaxWidth = aContainingBlockWidth / 3;
+ }
+ }
+#else
// A specified value of 'auto' becomes a computed width of 0
mComputedWidth = 0;
+#endif
} else {
ComputeHorizontalValue(aContainingBlockWidth, widthUnit,
mStylePosition->mWidth,
@@ -1007,19 +1022,21 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
// Take into account minimum and maximum sizes
- if (mComputedWidth > mComputedMaxWidth) {
- mComputedWidth = mComputedMaxWidth;
- } else if (mComputedWidth < mComputedMinWidth) {
- mComputedWidth = mComputedMinWidth;
- }
-
- // See what edge the width applies to (the default is the content
- // edge)
- if ((mComputedWidth > 0) && (mComputedWidth != NS_UNCONSTRAINEDSIZE)) {
- if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_PADDING) {
- mComputedWidth -= mComputedPadding.left + mComputedPadding.right;
- } else if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_BORDER) {
- mComputedWidth -= mComputedBorderPadding.left + mComputedBorderPadding.right;
+ if (mComputedWidth != NS_SHRINKWRAPWIDTH) {
+ if (mComputedWidth > mComputedMaxWidth) {
+ mComputedWidth = mComputedMaxWidth;
+ } else if (mComputedWidth < mComputedMinWidth) {
+ mComputedWidth = mComputedMinWidth;
+ }
+
+ // See what edge the width applies to (the default is the content
+ // edge)
+ if (mComputedWidth > 0) {
+ if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_PADDING) {
+ mComputedWidth -= mComputedPadding.left + mComputedPadding.right;
+ } else if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_BORDER) {
+ mComputedWidth -= mComputedBorderPadding.left + mComputedBorderPadding.right;
+ }
}
}
@@ -1035,15 +1052,15 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
// Take into account minimum and maximum sizes
- if (mComputedHeight > mComputedMaxHeight) {
- mComputedHeight = mComputedMaxHeight;
- } else if (mComputedHeight < mComputedMinHeight) {
- mComputedHeight = mComputedMinHeight;
- }
-
- // See what edge the height applies to (the default is the content
- // edge)
if (mComputedHeight != NS_AUTOHEIGHT) {
+ if (mComputedHeight > mComputedMaxHeight) {
+ mComputedHeight = mComputedMaxHeight;
+ } else if (mComputedHeight < mComputedMinHeight) {
+ mComputedHeight = mComputedMinHeight;
+ }
+
+ // See what edge the height applies to (the default is the content
+ // edge)
if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_PADDING) {
mComputedHeight -= mComputedPadding.top + mComputedPadding.bottom;
} else if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_BORDER) {
@@ -1150,6 +1167,21 @@ nsHTMLReflowState::ComputeBlockBoxData(nsIPresContext* aPresContext,
// During pass1 table reflow, auto side margin values are
// uncomputable (== 0).
mComputedWidth = NS_UNCONSTRAINEDSIZE;
+ } else if (NS_SHRINKWRAPWIDTH == aContainingBlockWidth) {
+ // The containing block should shrink wrap its width, so have
+ // the child block do the same
+ mComputedWidth = NS_UNCONSTRAINEDSIZE;
+
+ // Let its content area be as wide as the containing block's max width
+ // minus any margin and border/padding
+ nscoord maxWidth = cbrs->mComputedMaxWidth - mComputedMargin.left -
+ mComputedBorderPadding.left - mComputedMargin.right -
+ mComputedBorderPadding.right;
+
+ if (maxWidth < mComputedMaxWidth) {
+ mComputedMaxWidth = maxWidth;
+ }
+
} else {
mComputedWidth = availableWidth - mComputedMargin.left -
mComputedMargin.right - mComputedBorderPadding.left -
@@ -1546,6 +1578,19 @@ nsHTMLReflowState::ComputeMargin(nscoord aContainingBlockWidth,
mComputedMargin.left = 0;
mComputedMargin.right = 0;
+ if (eStyleUnit_Coord == mStyleSpacing->mMargin.GetLeftUnit()) {
+ nsStyleCoord left;
+
+ mStyleSpacing->mMargin.GetLeft(left),
+ mComputedMargin.left = left.GetCoordValue();
+ }
+ if (eStyleUnit_Coord == mStyleSpacing->mMargin.GetRightUnit()) {
+ nsStyleCoord right;
+
+ mStyleSpacing->mMargin.GetRight(right),
+ mComputedMargin.right = right.GetCoordValue();
+ }
+
} else {
nsStyleCoord left, right;
diff --git a/mozilla/layout/generic/nsHTMLReflowState.h b/mozilla/layout/generic/nsHTMLReflowState.h
index 1ceaf6b16d4..c31377197ba 100644
--- a/mozilla/layout/generic/nsHTMLReflowState.h
+++ b/mozilla/layout/generic/nsHTMLReflowState.h
@@ -91,59 +91,66 @@ typedef PRUint32 nsCSSFrameType;
#define NS_FRAME_GET_TYPE(_ft) \
((_ft) & ~NS_CSS_FRAME_TYPE_REPLACED)
-#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE
-#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE
-#define NS_AUTOMARGIN NS_UNCONSTRAINEDSIZE
+#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE
+#define NS_SHRINKWRAPWIDTH NS_UNCONSTRAINEDSIZE
+#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE
+#define NS_AUTOMARGIN NS_UNCONSTRAINEDSIZE
/**
- * Reflow state passed to a frame during reflow. The reflow states are linked
- * together. The availableWidth and availableHeight represent the available
- * space in which to reflow your frame, and are computed based on the parent
- * frame's computed width and computed height. The available space is the total
- * space including margins, border, padding, and content area. A value of
- * NS_UNCONSTRAINEDSIZE means you can choose whatever size you want
+ * Reflow state passed to a frame during reflow.
*
- * @see #Reflow()
+ * @see nsIFrame#Reflow()
*/
struct nsHTMLReflowState {
- // pointer to parent's reflow state
+ // the reflow states are linked together. this is the pointer to the
+ // parent's reflow state
const nsHTMLReflowState* parentReflowState;
// the frame being reflowed
- nsIFrame* frame;
+ nsIFrame* frame;
// the reason for the reflow
- nsReflowReason reason;
+ nsReflowReason reason;
- // the reflow command. only set for eReflowReason_Incremental
- nsIReflowCommand* reflowCommand;
+ // the reflow command. only set for a reflow reason of eReflowReason_Incremental
+ nsIReflowCommand* reflowCommand;
- // the available space in which to reflow
+ // the available space in which to reflow the frame. The space represents the
+ // amount of room for the frame's border, padding, and content area (not the
+ // margin area. The parent frame deals with the child frame's margins). The
+ // frame size you choose should fit within the available space.
+ // A value of NS_UNCONSTRAINEDSIZE for the available height means you can
+ // choose whatever size you want. In galley mode the available height is always
+ // NS_UNCONSTRAINEDSIZE, and only page mode involves a constrained height
nscoord availableWidth, availableHeight;
// rendering context to use for measurement
nsIRenderingContext* rendContext;
// is the current context at the top of a page?
- PRPackedBool isTopOfPage;
+ PRPackedBool isTopOfPage;
// The type of frame, from css's perspective. This value is
// initialized by the Init method below.
nsCSSFrameType mFrameType;
+ // pointer to the space manager associated with this area
nsISpaceManager* mSpaceManager;
// LineLayout object (only for inline reflow; set to NULL otherwise)
nsLineLayout* mLineLayout;
- // The computed width specifies the frame's content width, and it does not
- // apply to inline non-replaced elements
+ // The computed width specifies the frame's content area width, and it does
+ // not apply to inline non-replaced elements
//
// For replaced inline frames, a value of NS_INTRINSICSIZE means you should
// use your intrinsic width as the computed width
//
// For block-level frames, the computed width is based on the width of the
- // containing block, the margin/border/padding areas, and the min/max width
+ // containing block, the margin/border/padding areas, and the min/max width.
+ // A value of NS_SHRINKWRAPWIDTH means that you should choose a width based
+ // on your content. The width may be as large as the specified maximum width
+ // (see mComputedMaxWidth).
nscoord mComputedWidth;
// The computed height specifies the frame's content height, and it does
diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp
index 326470af89b..e29c4c8ace2 100644
--- a/mozilla/layout/generic/nsInlineFrame.cpp
+++ b/mozilla/layout/generic/nsInlineFrame.cpp
@@ -486,7 +486,9 @@ nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext,
{
nsLineLayout* lineLayout = aReflowState.mLineLayout;
PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
- nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus);
+ PRBool pushedFrame;
+ nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus,
+ nsnull, pushedFrame);
if (NS_FAILED(rv)) {
return rv;
}
diff --git a/mozilla/layout/generic/nsLineBox.h b/mozilla/layout/generic/nsLineBox.h
index c51e26224d2..8cfcfc15190 100644
--- a/mozilla/layout/generic/nsLineBox.h
+++ b/mozilla/layout/generic/nsLineBox.h
@@ -189,6 +189,7 @@ public:
return mFlags.mTrimmed;
}
+ // mHasPercentageChild bit
void SetHasPercentageChild(PRBool aOn) {
mFlags.mHasPercentageChild = aOn;
}
@@ -196,6 +197,14 @@ public:
return mFlags.mHasPercentageChild;
}
+ // mLineWrapped bit
+ void SetLineWrapped(PRBool aOn) {
+ mFlags.mLineWrapped = aOn;
+ }
+ PRBool IsLineWrapped() const {
+ return mFlags.mLineWrapped;
+ }
+
// mChildCount value
PRInt32 GetChildCount() const {
return (PRInt32) mFlags.mChildCount;
@@ -299,10 +308,11 @@ public:
PRUint32 mImpactedByFloater : 1;
PRUint32 mTrimmed : 1;
PRUint32 mHasPercentageChild : 1;
+ PRUint32 mLineWrapped: 1;
PRUint32 mBreakType : 4;
- PRUint32 mChildCount : 23;
+ PRUint32 mChildCount : 22;
};
struct ExtraData {
diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp
index 66765a848c5..a9b38e47bd6 100644
--- a/mozilla/layout/generic/nsLineLayout.cpp
+++ b/mozilla/layout/generic/nsLineLayout.cpp
@@ -800,8 +800,12 @@ nsresult
nsLineLayout::ReflowFrame(nsIFrame* aFrame,
nsIFrame** aNextRCFrame,
nsReflowStatus& aReflowStatus,
- nsHTMLReflowMetrics* aMetrics)
+ nsHTMLReflowMetrics* aMetrics,
+ PRBool& aPushedFrame)
{
+ // Initialize OUT parameter
+ aPushedFrame = PR_FALSE;
+
PerFrameData* pfd;
nsresult rv = NewPerFrameData(&pfd);
if (NS_FAILED(rv)) {
@@ -1132,6 +1136,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
}
else {
PushFrame(aFrame);
+ aPushedFrame = PR_TRUE;
}
}
else {
@@ -2354,8 +2359,10 @@ nsLineLayout::TrimTrailingWhiteSpace()
return 0 != deltaWidth;
}
-void
-nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
+PRBool
+nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
+ PRBool aAllowJustify,
+ PRBool aShrinkWrapWidth)
{
PerSpanData* psd = mRootSpan;
nscoord availWidth = psd->mRightEdge;
@@ -2365,7 +2372,7 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
nsFrame::ListTag(stdout, mBlockReflowState->frame);
printf(": skipping horizontal alignment in pass1 table reflow\n");
#endif
- return;
+ return PR_TRUE;
}
availWidth -= psd->mLeftEdge;
nscoord remainingWidth = availWidth - aLineBounds.width;
@@ -2412,6 +2419,12 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
break;
}
if (0 != dx) {
+ // If we need to move the frames but we're shrink wrapping, then
+ // we need to wait until the final width is known
+ if (aShrinkWrapWidth) {
+ return PR_FALSE;
+ }
+
PerFrameData* pfd = psd->mFirstFrame;
while (nsnull != pfd) {
pfd->mBounds.x += dx;
@@ -2426,6 +2439,9 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
psd->mChangedFrameDirection = PR_TRUE;
/* Assume that all frames have been right aligned.*/
+ if (aShrinkWrapWidth) {
+ return PR_FALSE;
+ }
PerFrameData* pfd = psd->mFirstFrame;
PRUint32 maxX = psd->mRightEdge;
while (nsnull != pfd) {
@@ -2436,6 +2452,8 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
}
}
}
+
+ return PR_TRUE;
}
void
diff --git a/mozilla/layout/generic/nsLineLayout.h b/mozilla/layout/generic/nsLineLayout.h
index bf6b985bfea..7e472515c53 100644
--- a/mozilla/layout/generic/nsLineLayout.h
+++ b/mozilla/layout/generic/nsLineLayout.h
@@ -89,10 +89,13 @@ public:
PRBool IsZeroHeight();
+ // Reflows the frame and returns the reflow status. aPushedFrame is PR_TRUE
+ // if the frame is pushed to the next line because it doesn't fit
nsresult ReflowFrame(nsIFrame* aFrame,
nsIFrame** aNextRCFrame,
nsReflowStatus& aReflowStatus,
- nsHTMLReflowMetrics* aMetrics = nsnull);
+ nsHTMLReflowMetrics* aMetrics,
+ PRBool& aPushedFrame);
nscoord GetCarriedOutBottomMargin() const {
return mCarriedOutBottomMargin;
@@ -110,7 +113,9 @@ public:
PRBool TrimTrailingWhiteSpace();
- void HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify);
+ PRBool HorizontalAlignFrames(nsRect& aLineBounds,
+ PRBool aAllowJustify,
+ PRBool aShrinkWrapWidth);
void RelativePositionFrames(nsRect& aCombinedArea);
diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp
index 1eef663b005..f4021a10da9 100644
--- a/mozilla/layout/html/base/src/nsBlockFrame.cpp
+++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp
@@ -272,7 +272,8 @@ public:
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics);
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot);
~nsBlockReflowState();
@@ -449,6 +450,10 @@ public:
PRBool mUnconstrainedHeight;
+ PRBool mShrinkWrapWidth;
+
+ PRBool mNeedResizeReflow;
+
// The content area to reflow child frames within. The x/y
// coordinates are known to be mBorderPadding.left and
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
@@ -564,7 +569,8 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics)
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot)
: mBlock(aFrame),
mPresContext(aPresContext),
mReflowState(aReflowState),
@@ -574,8 +580,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mNextRCFrame(nsnull),
mPrevBottomMargin(0),
mFreeLineList(nsnull),
- mLineNumber(0)
+ mLineNumber(0),
+ mNeedResizeReflow(PR_FALSE)
{
+ if (aBlockMarginRoot) {
+ mIsTopMarginRoot = PR_TRUE;
+ mIsBottomMarginRoot = PR_TRUE;
+ }
+ if (mIsTopMarginRoot) {
+ mApplyTopMargin = PR_TRUE;
+ }
+
mSpaceManager = aReflowState.mSpaceManager;
// Translate into our content area and then save the
@@ -593,6 +608,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
// Compute content area width (the content area is inside the border
// and padding)
mUnconstrainedWidth = PR_FALSE;
+ mShrinkWrapWidth = PR_FALSE;
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
mContentArea.width = aReflowState.mComputedWidth;
}
@@ -601,6 +617,12 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mContentArea.width = NS_UNCONSTRAINEDSIZE;
mUnconstrainedWidth = PR_TRUE;
}
+ else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
+ // Choose a width based on the content (shrink wrap width) up
+ // to the maximum width
+ mContentArea.width = aReflowState.mComputedMaxWidth;
+ mShrinkWrapWidth = PR_TRUE;
+ }
else {
nscoord lr = borderPadding.left + borderPadding.right;
mContentArea.width = aReflowState.availableWidth - lr;
@@ -1423,14 +1445,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
reflowState.mSpaceManager = spaceManager.get();
}
- nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics);
- if (NS_BLOCK_MARGIN_ROOT & mState) {
- state.mIsTopMarginRoot = PR_TRUE;
- state.mIsBottomMarginRoot = PR_TRUE;
- }
- if (state.mIsTopMarginRoot) {
- state.mApplyTopMargin = PR_TRUE;
- }
+ nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
if (eReflowReason_Resize != aReflowState.reason) {
RenumberLists();
@@ -1792,7 +1808,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
// contents or we fluff out to the maximum block width. Note:
// We always shrink wrap when given an unconstrained width.
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
- !aState.mUnconstrainedWidth &&
+ !aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
!compact) {
// Set our width to the max width if we aren't already that
// wide. Note that the max-width has nothing to do with our
@@ -1826,7 +1842,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
nscoord computedMaxWidth = aReflowState.mComputedMaxWidth +
borderPadding.left + borderPadding.right;
if (computedWidth > computedMaxWidth) {
- computedWidth = aReflowState.mComputedMaxWidth;
+ computedWidth = computedMaxWidth;
}
}
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) {
@@ -1837,6 +1853,47 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
}
}
aMetrics.width = computedWidth;
+
+ // If we're shrink wrapping, then now that we know our final width we
+ // need to do horizontal alignment of the inline lines and make sure
+ // blocks are correctly sized and positioned. Any lines that need
+ // final adjustment will have been marked as dirty
+ if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
+ // If the parent reflow state is also shrink wrap width, then
+ // we don't need to do this, because it will reflow us after it
+ // calculates the final width
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
+
+ if (!parentIsShrinkWrapWidth) {
+ nsHTMLReflowState reflowState(aReflowState);
+
+ reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
+ borderPadding.right;
+ reflowState.reason = eReflowReason_Resize;
+ reflowState.mSpaceManager->ClearRegions();
+
+ nscoord oldDesiredWidth = aMetrics.width;
+ nsBlockReflowState state(reflowState, aState.mPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
+ ReflowDirtyLines(state);
+ aState.mY = state.mY;
+ NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width");
+ }
+ }
+ }
+
+ if (aState.mShrinkWrapWidth) {
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
}
// Compute final height
@@ -2182,8 +2239,14 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
nsLineBox* line = mLines;
if (tryAndSkipLines) {
// The line's bounds are relative to the border edge of the frame
- nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left +
- aState.mReflowState.mComputedWidth;
+ nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
+
+ if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
+ newAvailWidth += aState.mReflowState.mComputedMaxWidth;
+ } else {
+ newAvailWidth += aState.mReflowState.mComputedWidth;
+ }
+
#ifdef DEBUG
if (gNoisyReflow) {
IndentBy(stdout, gNoiseIndent);
@@ -2685,6 +2748,7 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
}
else {
+ aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// We don't really know what changed in the line, so use the union
@@ -3295,6 +3359,21 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
&collapsedBottomMargin,
aLine->mBounds, combinedArea);
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line as block so once we known the final shrink wrap width
+ // we can reflow the block to the correct size
+ // XXX We don't always need to do this...
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+
+ // Add the right margin to the line's bounnds. That way it will be taken into
+ // account when we compute our shrink wrap size
+ nscoord marginRight = brc.GetMargin().right;
+ if (marginRight != NS_UNCONSTRAINEDSIZE) {
+ aLine->mBounds.width += marginRight;
+ }
+
+ }
aLine->SetCombinedArea(combinedArea);
if (*aKeepReflowGoing) {
// Some of the child block fit
@@ -3703,8 +3782,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
// Reflow the inline frame
nsReflowStatus frameReflowStatus;
+ PRBool pushedFrame;
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
- frameReflowStatus);
+ frameReflowStatus, nsnull, pushedFrame);
if (NS_FAILED(rv)) {
return rv;
}
@@ -3752,6 +3832,13 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+
+ // If we're splitting the line because the frame didn't fit and it
+ // was pushed, then mark the line as having word wrapped. We need to
+ // know that if we're shrink wrapping our width
+ if (pushedFrame) {
+ aLine->SetLineWrapped(PR_TRUE);
+ }
}
}
else {
@@ -3770,6 +3857,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
}
// Split line, but after the frame just reflowed
@@ -3799,6 +3888,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
+
// If we are reflowing the first letter frame then don't split the
// line and don't stop the line reflow...
PRBool splitLine = !reflowingFirstLetter;
@@ -3988,6 +4080,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
}
nsSize maxElementSize;
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
+ // See if we're shrink wrapping the width
+ if (aState.mShrinkWrapWidth) {
+ // When determining the line's width we also need to include any
+ // right floaters that impact us. This represents the shrink wrap
+ // width of the line
+ if (aState.IsImpactedByFloater() && !aLine->IsLineWrapped()) {
+ NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state");
+ aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost();
+ }
+ }
#ifdef DEBUG
{
static nscoord lastHeight = 0;
@@ -4016,8 +4118,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#else
PRBool allowJustify = PR_FALSE;
#endif
- aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
+
+ PRBool successful;
nsRect combinedArea;
+ successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
+ aState.mShrinkWrapWidth);
+ if (!successful) {
+ // Mark the line dirty and then later once we've determined the width
+ // we can do the horizontal alignment
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
aLineLayout.RelativePositionFrames(combinedArea);
aLine->SetCombinedArea(combinedArea);
if (addedBullet) {
@@ -4113,17 +4224,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
- if (aState.mUnconstrainedWidth && aState.mHaveRightFloaters) {
- // We are reflowing in an unconstrained situation and have some
- // right floaters. They were placed at the infinite right edge
+ if (aState.mHaveRightFloaters &&
+ (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
+ // We are reflowing in an unconstrained situation or shrink wrapping and
+ // have some right floaters. They were placed at the infinite right edge
// which will cause the combined area to be unusable.
//
- // To solve this issue, we pretend that the right floaters ended
- // up just past the end of the line. Note that the right floater
- // combined area we computed as we were going will have as its X
- // coordinate the left most edge of all the right
- // floaters. Therefore, to accomplish our goal all we do is set
- // that X value to the lines XMost value.
+ // To solve this issue, we pretend that the right floaters ended up just
+ // past the end of the line. Note that the right floater combined area
+ // we computed as we were going will have as its X coordinate the left
+ // most edge of all the right floaters. Therefore, to accomplish our goal
+ // all we do is set that X value to the lines XMost value.
#ifdef NOISY_COMBINED_AREA
printf(" ==> rightFloaterCA=%d,%d,%d,%d lineXMost=%d\n",
aState.mRightFloaterCombinedArea.x,
@@ -4134,6 +4245,13 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
+
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line dirty so we come back and re-place the floater once
+ // the shrink wrap width is determined
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
}
aLine->SetCombinedArea(lineCombinedArea);
#ifdef NOISY_COMBINED_AREA
@@ -4239,7 +4357,13 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
printf(": line=%p xmost=%d\n", aLine, xmost);
}
#endif
- if (xmost > aState.mKidXMost) {
+ // 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.mShrinkWrapWidth && aLine->IsLineWrapped()) {
+ aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
+
+ }
+ else if (xmost > aState.mKidXMost) {
aState.mKidXMost = xmost;
}
}
@@ -5228,7 +5352,7 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
#ifdef DEBUG
nsresult rv =
#endif
- mSpaceManager->AddRectRegion(floater, region);
+ mSpaceManager->AddRectRegion(floater, region);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad floater placement");
}
@@ -5276,13 +5400,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
nsRect combinedArea = aFloaterCache->mCombinedArea;
combinedArea.x += x;
combinedArea.y += y;
- if (!isLeftFloater && mUnconstrainedWidth) {
- // When we are placing a right floater in an unconstrained
- // situation we don't apply it to the floater combined area
- // immediately. Otherwise we end up with an infinitely wide
- // combined area. Instead, we save it away in
- // mRightFloaterCombinedArea so that later on when we know the
- // width of a line we can compute a better value.
+ if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
+ // When we are placing a right floater in an unconstrained situation or
+ // when shrink wrapping, we don't apply it to the floater combined area
+ // immediately. Otherwise we end up with an infinitely wide combined
+ // area. Instead, we save it away in mRightFloaterCombinedArea so that
+ // later on when we know the width of a line we can compute a better value.
if (!mHaveRightFloaters) {
mRightFloaterCombinedArea = combinedArea;
mHaveRightFloaters = PR_TRUE;
diff --git a/mozilla/layout/html/base/src/nsBlockReflowContext.cpp b/mozilla/layout/html/base/src/nsBlockReflowContext.cpp
index c2f025bf805..5fbfe4f2f6c 100644
--- a/mozilla/layout/html/base/src/nsBlockReflowContext.cpp
+++ b/mozilla/layout/html/base/src/nsBlockReflowContext.cpp
@@ -358,6 +358,63 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
}
}
+ // If the block is shrink wrapping its width, then see if we have percentage
+ // based margins. If so, we can calculate them now that we know the shrink
+ // wrap width
+ if (NS_SHRINKWRAPWIDTH == reflowState.mComputedWidth) {
+ nscoord boxWidth = mMetrics.width;
+ float leftPct = 0.0;
+ float rightPct = 0.0;
+
+ if (eStyleUnit_Percent == reflowState.mStyleSpacing->mMargin.GetLeftUnit()) {
+ nsStyleCoord leftCoord;
+
+ reflowState.mStyleSpacing->mMargin.GetLeft(leftCoord);
+ leftPct = leftCoord.GetPercentValue();
+
+ } else {
+ boxWidth += mMargin.left;
+ }
+
+ if (eStyleUnit_Percent == reflowState.mStyleSpacing->mMargin.GetRightUnit()) {
+ nsStyleCoord rightCoord;
+
+ reflowState.mStyleSpacing->mMargin.GetRight(rightCoord);
+ rightPct = rightCoord.GetPercentValue();
+
+ } else {
+ boxWidth += mMargin.right;
+ }
+
+ // The total shrink wrap width "sww" is calculated by the expression:
+ // sww = bw + (mp * sww)
+ // where "bw" is the box width (frame width plus margins that aren't percentage
+ // based) and "mp" are the total margin percentages (i.e., the left percentage
+ // value plus the right percentage value)
+ // Solving for "sww" gives us:
+ // sww = bw / (1 - mp)
+ // Note that this is only well defined for "mp" less than 100%
+ float marginPct = leftPct + rightPct;
+ if (marginPct >= 1.0) {
+ // Ignore the right percentage and just use the left percentage
+ // XXX Pay attention to direction property...
+ marginPct = leftPct;
+ rightPct = 0.0;
+ }
+
+ if ((marginPct > 0.0) && (marginPct < 1.0)) {
+ double shrinkWrapWidth = float(boxWidth) / (1.0 - marginPct);
+
+ if (eStyleUnit_Percent == reflowState.mStyleSpacing->mMargin.GetLeftUnit()) {
+ mMargin.left = NSToCoordFloor(shrinkWrapWidth * leftPct);
+ mX += mMargin.left;
+ }
+ if (eStyleUnit_Percent == reflowState.mStyleSpacing->mMargin.GetRightUnit()) {
+ mMargin.right = NSToCoordFloor(shrinkWrapWidth * rightPct);
+ }
+ }
+ }
+
return rv;
}
diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp
index 1eef663b005..f4021a10da9 100644
--- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp
+++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp
@@ -272,7 +272,8 @@ public:
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics);
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot);
~nsBlockReflowState();
@@ -449,6 +450,10 @@ public:
PRBool mUnconstrainedHeight;
+ PRBool mShrinkWrapWidth;
+
+ PRBool mNeedResizeReflow;
+
// The content area to reflow child frames within. The x/y
// coordinates are known to be mBorderPadding.left and
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
@@ -564,7 +569,8 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics)
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot)
: mBlock(aFrame),
mPresContext(aPresContext),
mReflowState(aReflowState),
@@ -574,8 +580,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mNextRCFrame(nsnull),
mPrevBottomMargin(0),
mFreeLineList(nsnull),
- mLineNumber(0)
+ mLineNumber(0),
+ mNeedResizeReflow(PR_FALSE)
{
+ if (aBlockMarginRoot) {
+ mIsTopMarginRoot = PR_TRUE;
+ mIsBottomMarginRoot = PR_TRUE;
+ }
+ if (mIsTopMarginRoot) {
+ mApplyTopMargin = PR_TRUE;
+ }
+
mSpaceManager = aReflowState.mSpaceManager;
// Translate into our content area and then save the
@@ -593,6 +608,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
// Compute content area width (the content area is inside the border
// and padding)
mUnconstrainedWidth = PR_FALSE;
+ mShrinkWrapWidth = PR_FALSE;
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
mContentArea.width = aReflowState.mComputedWidth;
}
@@ -601,6 +617,12 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mContentArea.width = NS_UNCONSTRAINEDSIZE;
mUnconstrainedWidth = PR_TRUE;
}
+ else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
+ // Choose a width based on the content (shrink wrap width) up
+ // to the maximum width
+ mContentArea.width = aReflowState.mComputedMaxWidth;
+ mShrinkWrapWidth = PR_TRUE;
+ }
else {
nscoord lr = borderPadding.left + borderPadding.right;
mContentArea.width = aReflowState.availableWidth - lr;
@@ -1423,14 +1445,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
reflowState.mSpaceManager = spaceManager.get();
}
- nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics);
- if (NS_BLOCK_MARGIN_ROOT & mState) {
- state.mIsTopMarginRoot = PR_TRUE;
- state.mIsBottomMarginRoot = PR_TRUE;
- }
- if (state.mIsTopMarginRoot) {
- state.mApplyTopMargin = PR_TRUE;
- }
+ nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
if (eReflowReason_Resize != aReflowState.reason) {
RenumberLists();
@@ -1792,7 +1808,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
// contents or we fluff out to the maximum block width. Note:
// We always shrink wrap when given an unconstrained width.
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
- !aState.mUnconstrainedWidth &&
+ !aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
!compact) {
// Set our width to the max width if we aren't already that
// wide. Note that the max-width has nothing to do with our
@@ -1826,7 +1842,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
nscoord computedMaxWidth = aReflowState.mComputedMaxWidth +
borderPadding.left + borderPadding.right;
if (computedWidth > computedMaxWidth) {
- computedWidth = aReflowState.mComputedMaxWidth;
+ computedWidth = computedMaxWidth;
}
}
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) {
@@ -1837,6 +1853,47 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
}
}
aMetrics.width = computedWidth;
+
+ // If we're shrink wrapping, then now that we know our final width we
+ // need to do horizontal alignment of the inline lines and make sure
+ // blocks are correctly sized and positioned. Any lines that need
+ // final adjustment will have been marked as dirty
+ if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
+ // If the parent reflow state is also shrink wrap width, then
+ // we don't need to do this, because it will reflow us after it
+ // calculates the final width
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
+
+ if (!parentIsShrinkWrapWidth) {
+ nsHTMLReflowState reflowState(aReflowState);
+
+ reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
+ borderPadding.right;
+ reflowState.reason = eReflowReason_Resize;
+ reflowState.mSpaceManager->ClearRegions();
+
+ nscoord oldDesiredWidth = aMetrics.width;
+ nsBlockReflowState state(reflowState, aState.mPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
+ ReflowDirtyLines(state);
+ aState.mY = state.mY;
+ NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width");
+ }
+ }
+ }
+
+ if (aState.mShrinkWrapWidth) {
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
}
// Compute final height
@@ -2182,8 +2239,14 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
nsLineBox* line = mLines;
if (tryAndSkipLines) {
// The line's bounds are relative to the border edge of the frame
- nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left +
- aState.mReflowState.mComputedWidth;
+ nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
+
+ if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
+ newAvailWidth += aState.mReflowState.mComputedMaxWidth;
+ } else {
+ newAvailWidth += aState.mReflowState.mComputedWidth;
+ }
+
#ifdef DEBUG
if (gNoisyReflow) {
IndentBy(stdout, gNoiseIndent);
@@ -2685,6 +2748,7 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
}
else {
+ aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// We don't really know what changed in the line, so use the union
@@ -3295,6 +3359,21 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
&collapsedBottomMargin,
aLine->mBounds, combinedArea);
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line as block so once we known the final shrink wrap width
+ // we can reflow the block to the correct size
+ // XXX We don't always need to do this...
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+
+ // Add the right margin to the line's bounnds. That way it will be taken into
+ // account when we compute our shrink wrap size
+ nscoord marginRight = brc.GetMargin().right;
+ if (marginRight != NS_UNCONSTRAINEDSIZE) {
+ aLine->mBounds.width += marginRight;
+ }
+
+ }
aLine->SetCombinedArea(combinedArea);
if (*aKeepReflowGoing) {
// Some of the child block fit
@@ -3703,8 +3782,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
// Reflow the inline frame
nsReflowStatus frameReflowStatus;
+ PRBool pushedFrame;
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
- frameReflowStatus);
+ frameReflowStatus, nsnull, pushedFrame);
if (NS_FAILED(rv)) {
return rv;
}
@@ -3752,6 +3832,13 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+
+ // If we're splitting the line because the frame didn't fit and it
+ // was pushed, then mark the line as having word wrapped. We need to
+ // know that if we're shrink wrapping our width
+ if (pushedFrame) {
+ aLine->SetLineWrapped(PR_TRUE);
+ }
}
}
else {
@@ -3770,6 +3857,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
}
// Split line, but after the frame just reflowed
@@ -3799,6 +3888,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
+
// If we are reflowing the first letter frame then don't split the
// line and don't stop the line reflow...
PRBool splitLine = !reflowingFirstLetter;
@@ -3988,6 +4080,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
}
nsSize maxElementSize;
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
+ // See if we're shrink wrapping the width
+ if (aState.mShrinkWrapWidth) {
+ // When determining the line's width we also need to include any
+ // right floaters that impact us. This represents the shrink wrap
+ // width of the line
+ if (aState.IsImpactedByFloater() && !aLine->IsLineWrapped()) {
+ NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state");
+ aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost();
+ }
+ }
#ifdef DEBUG
{
static nscoord lastHeight = 0;
@@ -4016,8 +4118,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#else
PRBool allowJustify = PR_FALSE;
#endif
- aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
+
+ PRBool successful;
nsRect combinedArea;
+ successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
+ aState.mShrinkWrapWidth);
+ if (!successful) {
+ // Mark the line dirty and then later once we've determined the width
+ // we can do the horizontal alignment
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
aLineLayout.RelativePositionFrames(combinedArea);
aLine->SetCombinedArea(combinedArea);
if (addedBullet) {
@@ -4113,17 +4224,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
- if (aState.mUnconstrainedWidth && aState.mHaveRightFloaters) {
- // We are reflowing in an unconstrained situation and have some
- // right floaters. They were placed at the infinite right edge
+ if (aState.mHaveRightFloaters &&
+ (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
+ // We are reflowing in an unconstrained situation or shrink wrapping and
+ // have some right floaters. They were placed at the infinite right edge
// which will cause the combined area to be unusable.
//
- // To solve this issue, we pretend that the right floaters ended
- // up just past the end of the line. Note that the right floater
- // combined area we computed as we were going will have as its X
- // coordinate the left most edge of all the right
- // floaters. Therefore, to accomplish our goal all we do is set
- // that X value to the lines XMost value.
+ // To solve this issue, we pretend that the right floaters ended up just
+ // past the end of the line. Note that the right floater combined area
+ // we computed as we were going will have as its X coordinate the left
+ // most edge of all the right floaters. Therefore, to accomplish our goal
+ // all we do is set that X value to the lines XMost value.
#ifdef NOISY_COMBINED_AREA
printf(" ==> rightFloaterCA=%d,%d,%d,%d lineXMost=%d\n",
aState.mRightFloaterCombinedArea.x,
@@ -4134,6 +4245,13 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
+
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line dirty so we come back and re-place the floater once
+ // the shrink wrap width is determined
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
}
aLine->SetCombinedArea(lineCombinedArea);
#ifdef NOISY_COMBINED_AREA
@@ -4239,7 +4357,13 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
printf(": line=%p xmost=%d\n", aLine, xmost);
}
#endif
- if (xmost > aState.mKidXMost) {
+ // 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.mShrinkWrapWidth && aLine->IsLineWrapped()) {
+ aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
+
+ }
+ else if (xmost > aState.mKidXMost) {
aState.mKidXMost = xmost;
}
}
@@ -5228,7 +5352,7 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
#ifdef DEBUG
nsresult rv =
#endif
- mSpaceManager->AddRectRegion(floater, region);
+ mSpaceManager->AddRectRegion(floater, region);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad floater placement");
}
@@ -5276,13 +5400,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
nsRect combinedArea = aFloaterCache->mCombinedArea;
combinedArea.x += x;
combinedArea.y += y;
- if (!isLeftFloater && mUnconstrainedWidth) {
- // When we are placing a right floater in an unconstrained
- // situation we don't apply it to the floater combined area
- // immediately. Otherwise we end up with an infinitely wide
- // combined area. Instead, we save it away in
- // mRightFloaterCombinedArea so that later on when we know the
- // width of a line we can compute a better value.
+ if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
+ // When we are placing a right floater in an unconstrained situation or
+ // when shrink wrapping, we don't apply it to the floater combined area
+ // immediately. Otherwise we end up with an infinitely wide combined
+ // area. Instead, we save it away in mRightFloaterCombinedArea so that
+ // later on when we know the width of a line we can compute a better value.
if (!mHaveRightFloaters) {
mRightFloaterCombinedArea = combinedArea;
mHaveRightFloaters = PR_TRUE;
diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h
index 1eef663b005..f4021a10da9 100644
--- a/mozilla/layout/html/base/src/nsBlockReflowState.h
+++ b/mozilla/layout/html/base/src/nsBlockReflowState.h
@@ -272,7 +272,8 @@ public:
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics);
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot);
~nsBlockReflowState();
@@ -449,6 +450,10 @@ public:
PRBool mUnconstrainedHeight;
+ PRBool mShrinkWrapWidth;
+
+ PRBool mNeedResizeReflow;
+
// The content area to reflow child frames within. The x/y
// coordinates are known to be mBorderPadding.left and
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
@@ -564,7 +569,8 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
nsIPresContext* aPresContext,
nsBlockFrame* aFrame,
- const nsHTMLReflowMetrics& aMetrics)
+ const nsHTMLReflowMetrics& aMetrics,
+ PRBool aBlockMarginRoot)
: mBlock(aFrame),
mPresContext(aPresContext),
mReflowState(aReflowState),
@@ -574,8 +580,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mNextRCFrame(nsnull),
mPrevBottomMargin(0),
mFreeLineList(nsnull),
- mLineNumber(0)
+ mLineNumber(0),
+ mNeedResizeReflow(PR_FALSE)
{
+ if (aBlockMarginRoot) {
+ mIsTopMarginRoot = PR_TRUE;
+ mIsBottomMarginRoot = PR_TRUE;
+ }
+ if (mIsTopMarginRoot) {
+ mApplyTopMargin = PR_TRUE;
+ }
+
mSpaceManager = aReflowState.mSpaceManager;
// Translate into our content area and then save the
@@ -593,6 +608,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
// Compute content area width (the content area is inside the border
// and padding)
mUnconstrainedWidth = PR_FALSE;
+ mShrinkWrapWidth = PR_FALSE;
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
mContentArea.width = aReflowState.mComputedWidth;
}
@@ -601,6 +617,12 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mContentArea.width = NS_UNCONSTRAINEDSIZE;
mUnconstrainedWidth = PR_TRUE;
}
+ else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
+ // Choose a width based on the content (shrink wrap width) up
+ // to the maximum width
+ mContentArea.width = aReflowState.mComputedMaxWidth;
+ mShrinkWrapWidth = PR_TRUE;
+ }
else {
nscoord lr = borderPadding.left + borderPadding.right;
mContentArea.width = aReflowState.availableWidth - lr;
@@ -1423,14 +1445,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
reflowState.mSpaceManager = spaceManager.get();
}
- nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics);
- if (NS_BLOCK_MARGIN_ROOT & mState) {
- state.mIsTopMarginRoot = PR_TRUE;
- state.mIsBottomMarginRoot = PR_TRUE;
- }
- if (state.mIsTopMarginRoot) {
- state.mApplyTopMargin = PR_TRUE;
- }
+ nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
if (eReflowReason_Resize != aReflowState.reason) {
RenumberLists();
@@ -1792,7 +1808,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
// contents or we fluff out to the maximum block width. Note:
// We always shrink wrap when given an unconstrained width.
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
- !aState.mUnconstrainedWidth &&
+ !aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
!compact) {
// Set our width to the max width if we aren't already that
// wide. Note that the max-width has nothing to do with our
@@ -1826,7 +1842,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
nscoord computedMaxWidth = aReflowState.mComputedMaxWidth +
borderPadding.left + borderPadding.right;
if (computedWidth > computedMaxWidth) {
- computedWidth = aReflowState.mComputedMaxWidth;
+ computedWidth = computedMaxWidth;
}
}
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) {
@@ -1837,6 +1853,47 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
}
}
aMetrics.width = computedWidth;
+
+ // If we're shrink wrapping, then now that we know our final width we
+ // need to do horizontal alignment of the inline lines and make sure
+ // blocks are correctly sized and positioned. Any lines that need
+ // final adjustment will have been marked as dirty
+ if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
+ // If the parent reflow state is also shrink wrap width, then
+ // we don't need to do this, because it will reflow us after it
+ // calculates the final width
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
+
+ if (!parentIsShrinkWrapWidth) {
+ nsHTMLReflowState reflowState(aReflowState);
+
+ reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
+ borderPadding.right;
+ reflowState.reason = eReflowReason_Resize;
+ reflowState.mSpaceManager->ClearRegions();
+
+ nscoord oldDesiredWidth = aMetrics.width;
+ nsBlockReflowState state(reflowState, aState.mPresContext, this, aMetrics,
+ NS_BLOCK_MARGIN_ROOT & mState);
+ ReflowDirtyLines(state);
+ aState.mY = state.mY;
+ NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width");
+ }
+ }
+ }
+
+ if (aState.mShrinkWrapWidth) {
+ PRBool parentIsShrinkWrapWidth = PR_FALSE;
+ if (aReflowState.parentReflowState) {
+ if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
+ parentIsShrinkWrapWidth = PR_TRUE;
+ }
+ }
}
// Compute final height
@@ -2182,8 +2239,14 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
nsLineBox* line = mLines;
if (tryAndSkipLines) {
// The line's bounds are relative to the border edge of the frame
- nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left +
- aState.mReflowState.mComputedWidth;
+ nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
+
+ if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
+ newAvailWidth += aState.mReflowState.mComputedMaxWidth;
+ } else {
+ newAvailWidth += aState.mReflowState.mComputedWidth;
+ }
+
#ifdef DEBUG
if (gNoisyReflow) {
IndentBy(stdout, gNoiseIndent);
@@ -2685,6 +2748,7 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
}
}
else {
+ aLine->SetLineWrapped(PR_FALSE);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// We don't really know what changed in the line, so use the union
@@ -3295,6 +3359,21 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
&collapsedBottomMargin,
aLine->mBounds, combinedArea);
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line as block so once we known the final shrink wrap width
+ // we can reflow the block to the correct size
+ // XXX We don't always need to do this...
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+
+ // Add the right margin to the line's bounnds. That way it will be taken into
+ // account when we compute our shrink wrap size
+ nscoord marginRight = brc.GetMargin().right;
+ if (marginRight != NS_UNCONSTRAINEDSIZE) {
+ aLine->mBounds.width += marginRight;
+ }
+
+ }
aLine->SetCombinedArea(combinedArea);
if (*aKeepReflowGoing) {
// Some of the child block fit
@@ -3703,8 +3782,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
// Reflow the inline frame
nsReflowStatus frameReflowStatus;
+ PRBool pushedFrame;
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
- frameReflowStatus);
+ frameReflowStatus, nsnull, pushedFrame);
if (NS_FAILED(rv)) {
return rv;
}
@@ -3752,6 +3832,13 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+
+ // If we're splitting the line because the frame didn't fit and it
+ // was pushed, then mark the line as having word wrapped. We need to
+ // know that if we're shrink wrapping our width
+ if (pushedFrame) {
+ aLine->SetLineWrapped(PR_TRUE);
+ }
}
}
else {
@@ -3770,6 +3857,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
if (NS_FAILED(rv)) {
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
}
// Split line, but after the frame just reflowed
@@ -3799,6 +3888,9 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
return rv;
}
+ // Remember that the line has wrapped
+ aLine->SetLineWrapped(PR_TRUE);
+
// If we are reflowing the first letter frame then don't split the
// line and don't stop the line reflow...
PRBool splitLine = !reflowingFirstLetter;
@@ -3988,6 +4080,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
}
nsSize maxElementSize;
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
+ // See if we're shrink wrapping the width
+ if (aState.mShrinkWrapWidth) {
+ // When determining the line's width we also need to include any
+ // right floaters that impact us. This represents the shrink wrap
+ // width of the line
+ if (aState.IsImpactedByFloater() && !aLine->IsLineWrapped()) {
+ NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state");
+ aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost();
+ }
+ }
#ifdef DEBUG
{
static nscoord lastHeight = 0;
@@ -4016,8 +4118,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#else
PRBool allowJustify = PR_FALSE;
#endif
- aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
+
+ PRBool successful;
nsRect combinedArea;
+ successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
+ aState.mShrinkWrapWidth);
+ if (!successful) {
+ // Mark the line dirty and then later once we've determined the width
+ // we can do the horizontal alignment
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
aLineLayout.RelativePositionFrames(combinedArea);
aLine->SetCombinedArea(combinedArea);
if (addedBullet) {
@@ -4113,17 +4224,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
- if (aState.mUnconstrainedWidth && aState.mHaveRightFloaters) {
- // We are reflowing in an unconstrained situation and have some
- // right floaters. They were placed at the infinite right edge
+ if (aState.mHaveRightFloaters &&
+ (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
+ // We are reflowing in an unconstrained situation or shrink wrapping and
+ // have some right floaters. They were placed at the infinite right edge
// which will cause the combined area to be unusable.
//
- // To solve this issue, we pretend that the right floaters ended
- // up just past the end of the line. Note that the right floater
- // combined area we computed as we were going will have as its X
- // coordinate the left most edge of all the right
- // floaters. Therefore, to accomplish our goal all we do is set
- // that X value to the lines XMost value.
+ // To solve this issue, we pretend that the right floaters ended up just
+ // past the end of the line. Note that the right floater combined area
+ // we computed as we were going will have as its X coordinate the left
+ // most edge of all the right floaters. Therefore, to accomplish our goal
+ // all we do is set that X value to the lines XMost value.
#ifdef NOISY_COMBINED_AREA
printf(" ==> rightFloaterCA=%d,%d,%d,%d lineXMost=%d\n",
aState.mRightFloaterCombinedArea.x,
@@ -4134,6 +4245,13 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
#endif
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
+
+ if (aState.mShrinkWrapWidth) {
+ // Mark the line dirty so we come back and re-place the floater once
+ // the shrink wrap width is determined
+ aLine->MarkDirty();
+ aState.mNeedResizeReflow = PR_TRUE;
+ }
}
aLine->SetCombinedArea(lineCombinedArea);
#ifdef NOISY_COMBINED_AREA
@@ -4239,7 +4357,13 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
printf(": line=%p xmost=%d\n", aLine, xmost);
}
#endif
- if (xmost > aState.mKidXMost) {
+ // 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.mShrinkWrapWidth && aLine->IsLineWrapped()) {
+ aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
+
+ }
+ else if (xmost > aState.mKidXMost) {
aState.mKidXMost = xmost;
}
}
@@ -5228,7 +5352,7 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
#ifdef DEBUG
nsresult rv =
#endif
- mSpaceManager->AddRectRegion(floater, region);
+ mSpaceManager->AddRectRegion(floater, region);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad floater placement");
}
@@ -5276,13 +5400,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
nsRect combinedArea = aFloaterCache->mCombinedArea;
combinedArea.x += x;
combinedArea.y += y;
- if (!isLeftFloater && mUnconstrainedWidth) {
- // When we are placing a right floater in an unconstrained
- // situation we don't apply it to the floater combined area
- // immediately. Otherwise we end up with an infinitely wide
- // combined area. Instead, we save it away in
- // mRightFloaterCombinedArea so that later on when we know the
- // width of a line we can compute a better value.
+ if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
+ // When we are placing a right floater in an unconstrained situation or
+ // when shrink wrapping, we don't apply it to the floater combined area
+ // immediately. Otherwise we end up with an infinitely wide combined
+ // area. Instead, we save it away in mRightFloaterCombinedArea so that
+ // later on when we know the width of a line we can compute a better value.
if (!mHaveRightFloaters) {
mRightFloaterCombinedArea = combinedArea;
mHaveRightFloaters = PR_TRUE;
diff --git a/mozilla/layout/html/base/src/nsFirstLetterFrame.cpp b/mozilla/layout/html/base/src/nsFirstLetterFrame.cpp
index 7a040b2b1be..98faa026c9a 100644
--- a/mozilla/layout/html/base/src/nsFirstLetterFrame.cpp
+++ b/mozilla/layout/html/base/src/nsFirstLetterFrame.cpp
@@ -238,8 +238,10 @@ nsFirstLetterFrame::Reflow(nsIPresContext* aPresContext,
else {
// Pretend we are a span and reflow the child frame
nsLineLayout* ll = aReflowState.mLineLayout;
+ PRBool pushedFrame;
+
ll->BeginSpan(this, &aReflowState, bp.left, availSize.width);
- ll->ReflowFrame(kid, &nextRCFrame, aReflowStatus, &aMetrics);
+ ll->ReflowFrame(kid, &nextRCFrame, aReflowStatus, &aMetrics, pushedFrame);
nsSize size;
ll->EndSpan(this, size, aMetrics.maxElementSize);
}
diff --git a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp
index db583a00731..745b8d39145 100644
--- a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp
+++ b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp
@@ -998,8 +998,23 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
if (eStyleUnit_Inherit == widthUnit) {
mComputedWidth = aContainingBlockWidth;
} else if (eStyleUnit_Auto == widthUnit) {
+ // XXX TROY. Once all the frame classes have been converted to the handle
+ // NS_SHRINKWRAPWIDTH. then we should switch to the new code...
+#if 0
+ // Have it shrink wrap the width
+ mComputedWidth = NS_SHRINKWRAPWIDTH;
+
+ // If there's no specified maximum width, then use 1/3 of the containing
+ // block width
+ if (NS_UNCONSTRAINEDSIZE == mComputedMaxWidth) {
+ if (NS_UNCONSTRAINEDSIZE != aContainingBlockWidth) {
+ mComputedMaxWidth = aContainingBlockWidth / 3;
+ }
+ }
+#else
// A specified value of 'auto' becomes a computed width of 0
mComputedWidth = 0;
+#endif
} else {
ComputeHorizontalValue(aContainingBlockWidth, widthUnit,
mStylePosition->mWidth,
@@ -1007,19 +1022,21 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
// Take into account minimum and maximum sizes
- if (mComputedWidth > mComputedMaxWidth) {
- mComputedWidth = mComputedMaxWidth;
- } else if (mComputedWidth < mComputedMinWidth) {
- mComputedWidth = mComputedMinWidth;
- }
-
- // See what edge the width applies to (the default is the content
- // edge)
- if ((mComputedWidth > 0) && (mComputedWidth != NS_UNCONSTRAINEDSIZE)) {
- if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_PADDING) {
- mComputedWidth -= mComputedPadding.left + mComputedPadding.right;
- } else if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_BORDER) {
- mComputedWidth -= mComputedBorderPadding.left + mComputedBorderPadding.right;
+ if (mComputedWidth != NS_SHRINKWRAPWIDTH) {
+ if (mComputedWidth > mComputedMaxWidth) {
+ mComputedWidth = mComputedMaxWidth;
+ } else if (mComputedWidth < mComputedMinWidth) {
+ mComputedWidth = mComputedMinWidth;
+ }
+
+ // See what edge the width applies to (the default is the content
+ // edge)
+ if (mComputedWidth > 0) {
+ if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_PADDING) {
+ mComputedWidth -= mComputedPadding.left + mComputedPadding.right;
+ } else if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_BORDER) {
+ mComputedWidth -= mComputedBorderPadding.left + mComputedBorderPadding.right;
+ }
}
}
@@ -1035,15 +1052,15 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
// Take into account minimum and maximum sizes
- if (mComputedHeight > mComputedMaxHeight) {
- mComputedHeight = mComputedMaxHeight;
- } else if (mComputedHeight < mComputedMinHeight) {
- mComputedHeight = mComputedMinHeight;
- }
-
- // See what edge the height applies to (the default is the content
- // edge)
if (mComputedHeight != NS_AUTOHEIGHT) {
+ if (mComputedHeight > mComputedMaxHeight) {
+ mComputedHeight = mComputedMaxHeight;
+ } else if (mComputedHeight < mComputedMinHeight) {
+ mComputedHeight = mComputedMinHeight;
+ }
+
+ // See what edge the height applies to (the default is the content
+ // edge)
if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_PADDING) {
mComputedHeight -= mComputedPadding.top + mComputedPadding.bottom;
} else if (mStylePosition->mBoxSizing == NS_STYLE_BOX_SIZING_BORDER) {
@@ -1150,6 +1167,21 @@ nsHTMLReflowState::ComputeBlockBoxData(nsIPresContext* aPresContext,
// During pass1 table reflow, auto side margin values are
// uncomputable (== 0).
mComputedWidth = NS_UNCONSTRAINEDSIZE;
+ } else if (NS_SHRINKWRAPWIDTH == aContainingBlockWidth) {
+ // The containing block should shrink wrap its width, so have
+ // the child block do the same
+ mComputedWidth = NS_UNCONSTRAINEDSIZE;
+
+ // Let its content area be as wide as the containing block's max width
+ // minus any margin and border/padding
+ nscoord maxWidth = cbrs->mComputedMaxWidth - mComputedMargin.left -
+ mComputedBorderPadding.left - mComputedMargin.right -
+ mComputedBorderPadding.right;
+
+ if (maxWidth < mComputedMaxWidth) {
+ mComputedMaxWidth = maxWidth;
+ }
+
} else {
mComputedWidth = availableWidth - mComputedMargin.left -
mComputedMargin.right - mComputedBorderPadding.left -
@@ -1546,6 +1578,19 @@ nsHTMLReflowState::ComputeMargin(nscoord aContainingBlockWidth,
mComputedMargin.left = 0;
mComputedMargin.right = 0;
+ if (eStyleUnit_Coord == mStyleSpacing->mMargin.GetLeftUnit()) {
+ nsStyleCoord left;
+
+ mStyleSpacing->mMargin.GetLeft(left),
+ mComputedMargin.left = left.GetCoordValue();
+ }
+ if (eStyleUnit_Coord == mStyleSpacing->mMargin.GetRightUnit()) {
+ nsStyleCoord right;
+
+ mStyleSpacing->mMargin.GetRight(right),
+ mComputedMargin.right = right.GetCoordValue();
+ }
+
} else {
nsStyleCoord left, right;
diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp
index 326470af89b..e29c4c8ace2 100644
--- a/mozilla/layout/html/base/src/nsInlineFrame.cpp
+++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp
@@ -486,7 +486,9 @@ nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext,
{
nsLineLayout* lineLayout = aReflowState.mLineLayout;
PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
- nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus);
+ PRBool pushedFrame;
+ nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus,
+ nsnull, pushedFrame);
if (NS_FAILED(rv)) {
return rv;
}
diff --git a/mozilla/layout/html/base/src/nsLineBox.h b/mozilla/layout/html/base/src/nsLineBox.h
index c51e26224d2..8cfcfc15190 100644
--- a/mozilla/layout/html/base/src/nsLineBox.h
+++ b/mozilla/layout/html/base/src/nsLineBox.h
@@ -189,6 +189,7 @@ public:
return mFlags.mTrimmed;
}
+ // mHasPercentageChild bit
void SetHasPercentageChild(PRBool aOn) {
mFlags.mHasPercentageChild = aOn;
}
@@ -196,6 +197,14 @@ public:
return mFlags.mHasPercentageChild;
}
+ // mLineWrapped bit
+ void SetLineWrapped(PRBool aOn) {
+ mFlags.mLineWrapped = aOn;
+ }
+ PRBool IsLineWrapped() const {
+ return mFlags.mLineWrapped;
+ }
+
// mChildCount value
PRInt32 GetChildCount() const {
return (PRInt32) mFlags.mChildCount;
@@ -299,10 +308,11 @@ public:
PRUint32 mImpactedByFloater : 1;
PRUint32 mTrimmed : 1;
PRUint32 mHasPercentageChild : 1;
+ PRUint32 mLineWrapped: 1;
PRUint32 mBreakType : 4;
- PRUint32 mChildCount : 23;
+ PRUint32 mChildCount : 22;
};
struct ExtraData {
diff --git a/mozilla/layout/html/base/src/nsLineLayout.cpp b/mozilla/layout/html/base/src/nsLineLayout.cpp
index 66765a848c5..a9b38e47bd6 100644
--- a/mozilla/layout/html/base/src/nsLineLayout.cpp
+++ b/mozilla/layout/html/base/src/nsLineLayout.cpp
@@ -800,8 +800,12 @@ nsresult
nsLineLayout::ReflowFrame(nsIFrame* aFrame,
nsIFrame** aNextRCFrame,
nsReflowStatus& aReflowStatus,
- nsHTMLReflowMetrics* aMetrics)
+ nsHTMLReflowMetrics* aMetrics,
+ PRBool& aPushedFrame)
{
+ // Initialize OUT parameter
+ aPushedFrame = PR_FALSE;
+
PerFrameData* pfd;
nsresult rv = NewPerFrameData(&pfd);
if (NS_FAILED(rv)) {
@@ -1132,6 +1136,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
}
else {
PushFrame(aFrame);
+ aPushedFrame = PR_TRUE;
}
}
else {
@@ -2354,8 +2359,10 @@ nsLineLayout::TrimTrailingWhiteSpace()
return 0 != deltaWidth;
}
-void
-nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
+PRBool
+nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
+ PRBool aAllowJustify,
+ PRBool aShrinkWrapWidth)
{
PerSpanData* psd = mRootSpan;
nscoord availWidth = psd->mRightEdge;
@@ -2365,7 +2372,7 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
nsFrame::ListTag(stdout, mBlockReflowState->frame);
printf(": skipping horizontal alignment in pass1 table reflow\n");
#endif
- return;
+ return PR_TRUE;
}
availWidth -= psd->mLeftEdge;
nscoord remainingWidth = availWidth - aLineBounds.width;
@@ -2412,6 +2419,12 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
break;
}
if (0 != dx) {
+ // If we need to move the frames but we're shrink wrapping, then
+ // we need to wait until the final width is known
+ if (aShrinkWrapWidth) {
+ return PR_FALSE;
+ }
+
PerFrameData* pfd = psd->mFirstFrame;
while (nsnull != pfd) {
pfd->mBounds.x += dx;
@@ -2426,6 +2439,9 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
psd->mChangedFrameDirection = PR_TRUE;
/* Assume that all frames have been right aligned.*/
+ if (aShrinkWrapWidth) {
+ return PR_FALSE;
+ }
PerFrameData* pfd = psd->mFirstFrame;
PRUint32 maxX = psd->mRightEdge;
while (nsnull != pfd) {
@@ -2436,6 +2452,8 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify)
}
}
}
+
+ return PR_TRUE;
}
void
diff --git a/mozilla/layout/html/base/src/nsLineLayout.h b/mozilla/layout/html/base/src/nsLineLayout.h
index bf6b985bfea..7e472515c53 100644
--- a/mozilla/layout/html/base/src/nsLineLayout.h
+++ b/mozilla/layout/html/base/src/nsLineLayout.h
@@ -89,10 +89,13 @@ public:
PRBool IsZeroHeight();
+ // Reflows the frame and returns the reflow status. aPushedFrame is PR_TRUE
+ // if the frame is pushed to the next line because it doesn't fit
nsresult ReflowFrame(nsIFrame* aFrame,
nsIFrame** aNextRCFrame,
nsReflowStatus& aReflowStatus,
- nsHTMLReflowMetrics* aMetrics = nsnull);
+ nsHTMLReflowMetrics* aMetrics,
+ PRBool& aPushedFrame);
nscoord GetCarriedOutBottomMargin() const {
return mCarriedOutBottomMargin;
@@ -110,7 +113,9 @@ public:
PRBool TrimTrailingWhiteSpace();
- void HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify);
+ PRBool HorizontalAlignFrames(nsRect& aLineBounds,
+ PRBool aAllowJustify,
+ PRBool aShrinkWrapWidth);
void RelativePositionFrames(nsRect& aCombinedArea);