зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
117f24ece3
Коммит
1558ba3b1a
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче