Added new #define NS_SHRINKWRAPWIDTH that specifies that a frame should

shrink wrap its width (paying attention to the maximum computed width). Mostly
complete implementation for block frames
This commit is contained in:
troy%netscape.com 2000-01-03 04:32:13 +00:00
Родитель 117f24ece3
Коммит 1558ba3b1a
22 изменённых файлов: 1340 добавлений и 310 удалений

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

@ -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

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

@ -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;

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

@ -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;
}

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

@ -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;

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

@ -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;

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

@ -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);
}

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

@ -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;

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

@ -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

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

@ -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;
}

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

@ -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 {

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

@ -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

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

@ -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);

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

@ -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;

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

@ -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;
}

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

@ -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;

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

@ -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;

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

@ -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);
}

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

@ -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;

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

@ -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;
}

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

@ -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 {

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

@ -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

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

@ -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);