diff --git a/mozilla/layout/base/public/nsHTMLReflowState.h b/mozilla/layout/base/public/nsHTMLReflowState.h index 714302958e1..2917ee5026c 100644 --- a/mozilla/layout/base/public/nsHTMLReflowState.h +++ b/mozilla/layout/base/public/nsHTMLReflowState.h @@ -170,9 +170,7 @@ struct nsHTMLReflowState { nsLineLayout* mLineLayout; // The appropriate reflow state for the containing block (for - // percentage widths, etc.) of any *children* of this reflow state's - // frame. In other words, this is the nearest containing block reflow - // state that is *either* this frame or an ancestor thereof. + // percentage widths, etc.) of this reflow state's frame. const nsHTMLReflowState *mCBReflowState; // The computed width specifies the frame's content area width, and it does @@ -263,13 +261,9 @@ struct nsHTMLReflowState { static const char* ReasonToString(nsReflowReason aReason); #endif - // A simple copy constructor. (It fixes up |mCBReflowState|, which - // can point to |this|, to point to the copy's |this|.) - nsHTMLReflowState(const nsHTMLReflowState& aOther); - - // A simple assignment operator. It does the same fixups as the - // copy-consturctor. - nsHTMLReflowState& operator=(const nsHTMLReflowState& aOther); + // Note: The copy constructor is written by the compiler automatically. You + // can use that and then override specific values if you want, or you can + // call Init as desired... // Initialize a root reflow state with a rendering context to // use for measuring things. @@ -322,12 +316,10 @@ struct nsHTMLReflowState { nsMargin* aBorder = nsnull, nsMargin* aPadding = nsnull); /** - * First find the containing block's reflow state using - * GetContainingBlockReflowState, then ask the containing block for - * it's content width using GetContentWidth + * Find the content width of the containing block of aReflowState */ static nscoord - GetContainingBlockContentWidth(const nsHTMLReflowState* aParentRS); + GetContainingBlockContentWidth(const nsHTMLReflowState* aReflowState); /** * Get the page box reflow state, starting from a frames @@ -385,7 +377,7 @@ protected: nsIFrame* aPlaceholderFrame, nsIFrame* aBlockFrame, nsMargin& aBlockContentArea, - nsIFrame* aAbsoluteContainingBlockFrame, + const nsHTMLReflowState* cbrs, nsHypotheticalBox& aHypotheticalBox); void InitAbsoluteConstraints(nsIPresContext* aPresContext, diff --git a/mozilla/layout/generic/nsHTMLReflowState.cpp b/mozilla/layout/generic/nsHTMLReflowState.cpp index 71d09568439..876c362b0ec 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.cpp +++ b/mozilla/layout/generic/nsHTMLReflowState.cpp @@ -89,29 +89,6 @@ nsHTMLReflowState::ReasonToString(nsReflowReason aReason) } #endif -nsHTMLReflowState::nsHTMLReflowState(const nsHTMLReflowState& aOther) -{ - // Use assignment operator below. - *this = aOther; -} - -nsHTMLReflowState& -nsHTMLReflowState::operator=(const nsHTMLReflowState &aOther) -{ - // Copy everything. - // XXX This won't work anymore if someone adds member variables that - // have nontrivial constructors or assignment operators (e.g., - // nsCOMPtr). - memcpy(this, &aOther, sizeof(*this)); - - // Fix up the |mCBReflowState| member, which should continue to point - // to |this|. - if (aOther.mCBReflowState == &aOther) - mCBReflowState = this; - - return *this; -} - // Initialize a root reflow state with a rendering context to // use for measuring things. nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext, @@ -338,17 +315,26 @@ nsHTMLReflowState::Init(nsIPresContext* aPresContext, void nsHTMLReflowState::InitCBReflowState() { - if (frame->IsContainingBlock()) { - // a block inside a table cell needs to use the table cell - if (parentReflowState) { - if (IS_TABLE_CELL(parentReflowState->frame->GetType())) { - mCBReflowState = parentReflowState; - return; - } - } - mCBReflowState = this; + if (!parentReflowState) { + mCBReflowState = nsnull; return; } + + if (parentReflowState->frame->IsContainingBlock() || + // Absolutely positioned frames should always be kids of the frames that + // determine their containing block + (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE)) { + // a block inside a table cell needs to use the table cell + if (parentReflowState->parentReflowState && + IS_TABLE_CELL(parentReflowState->parentReflowState->frame->GetType())) { + mCBReflowState = parentReflowState->parentReflowState; + } else { + mCBReflowState = parentReflowState; + } + + return; + } + mCBReflowState = parentReflowState->mCBReflowState; } @@ -360,9 +346,9 @@ nsHTMLReflowState::GetPageBoxReflowState(const nsHTMLReflowState* aParentRS) } nscoord -nsHTMLReflowState::GetContainingBlockContentWidth(const nsHTMLReflowState* aParentRS) +nsHTMLReflowState::GetContainingBlockContentWidth(const nsHTMLReflowState* aReflowState) { - const nsHTMLReflowState* rs = aParentRS->mCBReflowState; + const nsHTMLReflowState* rs = aReflowState->mCBReflowState; if (!rs) return 0; return rs->mComputedWidth; @@ -728,7 +714,7 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, nsIFrame* aPlaceholderFrame, nsIFrame* aBlockFrame, nsMargin& aBlockContentArea, - nsIFrame* aAbsoluteContainingBlockFrame, + const nsHTMLReflowState* cbrs, nsHypotheticalBox& aHypotheticalBox) { NS_ASSERTION(mStyleDisplay->mOriginalDisplay != NS_STYLE_DISPLAY_NONE, @@ -793,6 +779,8 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, // Get the placeholder x-offset and y-offset in the coordinate // space of the block frame that contains it + // XXXbz the placeholder is not fully reflown yet if our containing block is + // relatively positioned... nsPoint placeholderOffset; GetPlaceholderOffset(aPlaceholderFrame, aBlockFrame, placeholderOffset); @@ -815,7 +803,8 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, // the line containing the placeholder frame, unless all the frames // before it are empty. In that case, it would have been just before // this line. - // XXXbz why the special-casing if we are the last line box? + // XXXbz the line box is not fully reflown yet if our containing block is + // relatively positioned... if (lineBox != blockFrame->end_lines()) { nsIFrame * firstFrame = lineBox->mFirstChild; while (firstFrame != aPlaceholderFrame) { @@ -893,8 +882,20 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, // The current coordinate space is that of the nearest block to the placeholder. // Convert to the coordinate space of the absolute containing block - if (aBlockFrame != aAbsoluteContainingBlockFrame) { - nsIFrame* parent = aBlockFrame; + nsIFrame* absoluteContainingBlock = cbrs->frame; + if (aBlockFrame != absoluteContainingBlock) { + nsIFrame* parent; + nsIFrame* stop; + if (NS_FRAME_GET_TYPE(cbrs->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { + // The absolute containing block is an inline frame... so it will be a + // descendant of aBlockFrame + parent = absoluteContainingBlock; + stop = aBlockFrame; + } else { + // aBlockFrame may be a descendant of absoluteContainingBlock + parent = aBlockFrame; + stop = absoluteContainingBlock; + } do { nsPoint origin = parent->GetPosition(); @@ -904,20 +905,25 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, // Move up the tree one level parent = parent->GetParent(); - } while (parent && (parent != aAbsoluteContainingBlockFrame)); + } while (parent && parent != stop); } - // The specified offsets are relative to the absolute containing block's padding - // edge, and our current values are relative to the border edge so translate - const nsStyleBorder* borderStyle = - aAbsoluteContainingBlockFrame->GetStyleBorder(); - nsMargin border; - if (!borderStyle->GetBorder(border)) { - NS_NOTYETIMPLEMENTED("percentage border"); + // The specified offsets are relative to the absolute containing block's + // padding edge or content edge, and our current values are relative to the + // border edge, so translate. + if (NS_FRAME_GET_TYPE(cbrs->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { + // content edge + const nsMargin& borderPadding = cbrs->mComputedBorderPadding; + aHypotheticalBox.mLeft -= borderPadding.left; + aHypotheticalBox.mRight -= borderPadding.right; + aHypotheticalBox.mTop -= borderPadding.top; + } else { + // padding edge + nsMargin border = cbrs->mComputedBorderPadding - cbrs->mComputedPadding; + aHypotheticalBox.mLeft -= border.left; + aHypotheticalBox.mRight -= border.right; + aHypotheticalBox.mTop -= border.top; } - aHypotheticalBox.mLeft -= border.left; - aHypotheticalBox.mRight -= border.left; - aHypotheticalBox.mTop -= border.top; } void @@ -951,7 +957,7 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsIPresContext* aPresContext, (eStyleUnit_Auto == mStylePosition->mOffset.GetBottomUnit()))) { CalculateHypotheticalBox(aPresContext, placeholderFrame, blockFrame, - blockContentArea, cbrs->frame, hypotheticalBox); + blockContentArea, cbrs, hypotheticalBox); } // Initialize the 'left' and 'right' computed offsets @@ -1097,6 +1103,8 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsIPresContext* aPresContext, mComputedBorderPadding.right - mComputedMargin.right - mComputedOffsets.right; + mComputedWidth = PR_MAX(mComputedWidth, 0); + AdjustComputedWidth(PR_FALSE); // XXX If the direction is rtl then we need to reevaluate left... @@ -1246,6 +1254,8 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsIPresContext* aPresContext, mComputedBorderPadding.bottom - mComputedMargin.bottom - mComputedOffsets.bottom; + mComputedHeight = PR_MAX(mComputedHeight, 0); + AdjustComputedHeight(PR_FALSE); } @@ -1271,6 +1281,16 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsIPresContext* aPresContext, } } } + + // Now that we've solved for our auto offsets and so forth, we need to adjust + // the offsets to what the rest of layout actually expects them to be. The + // offsets as computed now are relative to the parent's padding edge if the + // parent is a block and the parent's content edge if the parent is an + // inline. We need them to be relative to the parent's padding edge for + // nsAbsoluteContainer reflow to work right. + if (NS_FRAME_GET_TYPE(cbrs->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { + mComputedOffsets += cbrs->mComputedPadding; + } } static PRBool @@ -1439,37 +1459,22 @@ nsHTMLReflowState::ComputeContainingBlockRectangle(nsIPresContext* aPre if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE) { // See if the ancestor is block-level or inline-level if (NS_FRAME_GET_TYPE(aContainingBlockRS->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { - // The CSS2 spec says that if the ancestor is inline-level, the containing - // block depends on the 'direction' property of the ancestor. For direction - // 'ltr', it's the top and left of the content edges of the first box and - // the bottom and right content edges of the last box - // - // XXX This is a pain because it isn't top-down and it requires that we've - // completely reflowed the ancestor. It also isn't clear what happens when - // a relatively positioned ancestor is split across pages. So instead use - // the computed width and height of the nearest block-level ancestor - const nsHTMLReflowState* cbrs = aContainingBlockRS; - while (cbrs) { - nsCSSFrameType type = NS_FRAME_GET_TYPE(cbrs->mFrameType); - if ((NS_CSS_FRAME_TYPE_BLOCK == type) || - (NS_CSS_FRAME_TYPE_FLOATING == type) || - (NS_CSS_FRAME_TYPE_ABSOLUTE == type)) { - - aContainingBlockWidth = cbrs->mComputedWidth; - aContainingBlockHeight = cbrs->mComputedHeight; - - if (NS_CSS_FRAME_TYPE_ABSOLUTE == type) { - aContainingBlockWidth += cbrs->mComputedPadding.left + - cbrs->mComputedPadding.right; - aContainingBlockHeight += cbrs->mComputedPadding.top + - cbrs->mComputedPadding.bottom; - } - break; - } - - cbrs = (const nsHTMLReflowState*)cbrs->parentReflowState; // XXX cast - } - + // Base our size on the actual size of the frame. In cases when this is + // completely bogus (eg initial reflow), this code shouldn't even be + // called, since the code in nsPositionedInlineFrame::Reflow will pass in + // the containing block dimensions to our constructor. + // XXXbz we should be taking the in-flows into account too, but + // that's very hard. + aContainingBlockWidth = aContainingBlockRS->frame->GetRect().width - + (aContainingBlockRS->mComputedBorderPadding.left + + aContainingBlockRS->mComputedBorderPadding.right); + NS_ASSERTION(aContainingBlockWidth >= 0, + "Negative containing block width!"); + aContainingBlockHeight = aContainingBlockRS->frame->GetRect().height - + (aContainingBlockRS->mComputedBorderPadding.top + + aContainingBlockRS->mComputedBorderPadding.bottom); + NS_ASSERTION(aContainingBlockHeight >= 0, + "Negative containing block height!"); } else { // If the ancestor is block-level, the containing block is formed by the // padding edge of the ancestor @@ -1584,7 +1589,7 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext, mComputedMaxWidth = mComputedMaxHeight = NS_UNCONSTRAINEDSIZE; } else { // Get the containing block reflow state - const nsHTMLReflowState* cbrs = parentReflowState->mCBReflowState; + const nsHTMLReflowState* cbrs = mCBReflowState; NS_ASSERTION(nsnull != cbrs, "no containing block"); // If we weren't given a containing block width and height, then diff --git a/mozilla/layout/generic/nsHTMLReflowState.h b/mozilla/layout/generic/nsHTMLReflowState.h index 714302958e1..2917ee5026c 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.h +++ b/mozilla/layout/generic/nsHTMLReflowState.h @@ -170,9 +170,7 @@ struct nsHTMLReflowState { nsLineLayout* mLineLayout; // The appropriate reflow state for the containing block (for - // percentage widths, etc.) of any *children* of this reflow state's - // frame. In other words, this is the nearest containing block reflow - // state that is *either* this frame or an ancestor thereof. + // percentage widths, etc.) of this reflow state's frame. const nsHTMLReflowState *mCBReflowState; // The computed width specifies the frame's content area width, and it does @@ -263,13 +261,9 @@ struct nsHTMLReflowState { static const char* ReasonToString(nsReflowReason aReason); #endif - // A simple copy constructor. (It fixes up |mCBReflowState|, which - // can point to |this|, to point to the copy's |this|.) - nsHTMLReflowState(const nsHTMLReflowState& aOther); - - // A simple assignment operator. It does the same fixups as the - // copy-consturctor. - nsHTMLReflowState& operator=(const nsHTMLReflowState& aOther); + // Note: The copy constructor is written by the compiler automatically. You + // can use that and then override specific values if you want, or you can + // call Init as desired... // Initialize a root reflow state with a rendering context to // use for measuring things. @@ -322,12 +316,10 @@ struct nsHTMLReflowState { nsMargin* aBorder = nsnull, nsMargin* aPadding = nsnull); /** - * First find the containing block's reflow state using - * GetContainingBlockReflowState, then ask the containing block for - * it's content width using GetContentWidth + * Find the content width of the containing block of aReflowState */ static nscoord - GetContainingBlockContentWidth(const nsHTMLReflowState* aParentRS); + GetContainingBlockContentWidth(const nsHTMLReflowState* aReflowState); /** * Get the page box reflow state, starting from a frames @@ -385,7 +377,7 @@ protected: nsIFrame* aPlaceholderFrame, nsIFrame* aBlockFrame, nsMargin& aBlockContentArea, - nsIFrame* aAbsoluteContainingBlockFrame, + const nsHTMLReflowState* cbrs, nsHypotheticalBox& aHypotheticalBox); void InitAbsoluteConstraints(nsIPresContext* aPresContext, diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp index 0feeb79f89e..6fcfc68455a 100644 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -1286,8 +1286,13 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, (eReflowReason_Incremental != aReflowState.reason || aReflowState.path->mReflowCommand || mRect != oldRect)) { - nscoord containingBlockWidth = -1; - nscoord containingBlockHeight = -1; + // The containing block for the abs pos kids is formed by our content edge. + nscoord containingBlockWidth = aDesiredSize.width - + (aReflowState.mComputedBorderPadding.left + + aReflowState.mComputedBorderPadding.right); + nscoord containingBlockHeight = aDesiredSize.height - + (aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom); nsRect childBounds; rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState, diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp index 19261b15f63..fc2edbffa9c 100644 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ b/mozilla/layout/generic/nsLineLayout.cpp @@ -316,7 +316,7 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY, } else if (eStyleUnit_Percent == unit) { nscoord width = - nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState->parentReflowState); + nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState); if ((0 != width) && (NS_UNCONSTRAINEDSIZE != width)) { indent = nscoord(mStyleText->mTextIndent.GetPercentValue() * width); } diff --git a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp index 71d09568439..876c362b0ec 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp +++ b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp @@ -89,29 +89,6 @@ nsHTMLReflowState::ReasonToString(nsReflowReason aReason) } #endif -nsHTMLReflowState::nsHTMLReflowState(const nsHTMLReflowState& aOther) -{ - // Use assignment operator below. - *this = aOther; -} - -nsHTMLReflowState& -nsHTMLReflowState::operator=(const nsHTMLReflowState &aOther) -{ - // Copy everything. - // XXX This won't work anymore if someone adds member variables that - // have nontrivial constructors or assignment operators (e.g., - // nsCOMPtr). - memcpy(this, &aOther, sizeof(*this)); - - // Fix up the |mCBReflowState| member, which should continue to point - // to |this|. - if (aOther.mCBReflowState == &aOther) - mCBReflowState = this; - - return *this; -} - // Initialize a root reflow state with a rendering context to // use for measuring things. nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext, @@ -338,17 +315,26 @@ nsHTMLReflowState::Init(nsIPresContext* aPresContext, void nsHTMLReflowState::InitCBReflowState() { - if (frame->IsContainingBlock()) { - // a block inside a table cell needs to use the table cell - if (parentReflowState) { - if (IS_TABLE_CELL(parentReflowState->frame->GetType())) { - mCBReflowState = parentReflowState; - return; - } - } - mCBReflowState = this; + if (!parentReflowState) { + mCBReflowState = nsnull; return; } + + if (parentReflowState->frame->IsContainingBlock() || + // Absolutely positioned frames should always be kids of the frames that + // determine their containing block + (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE)) { + // a block inside a table cell needs to use the table cell + if (parentReflowState->parentReflowState && + IS_TABLE_CELL(parentReflowState->parentReflowState->frame->GetType())) { + mCBReflowState = parentReflowState->parentReflowState; + } else { + mCBReflowState = parentReflowState; + } + + return; + } + mCBReflowState = parentReflowState->mCBReflowState; } @@ -360,9 +346,9 @@ nsHTMLReflowState::GetPageBoxReflowState(const nsHTMLReflowState* aParentRS) } nscoord -nsHTMLReflowState::GetContainingBlockContentWidth(const nsHTMLReflowState* aParentRS) +nsHTMLReflowState::GetContainingBlockContentWidth(const nsHTMLReflowState* aReflowState) { - const nsHTMLReflowState* rs = aParentRS->mCBReflowState; + const nsHTMLReflowState* rs = aReflowState->mCBReflowState; if (!rs) return 0; return rs->mComputedWidth; @@ -728,7 +714,7 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, nsIFrame* aPlaceholderFrame, nsIFrame* aBlockFrame, nsMargin& aBlockContentArea, - nsIFrame* aAbsoluteContainingBlockFrame, + const nsHTMLReflowState* cbrs, nsHypotheticalBox& aHypotheticalBox) { NS_ASSERTION(mStyleDisplay->mOriginalDisplay != NS_STYLE_DISPLAY_NONE, @@ -793,6 +779,8 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, // Get the placeholder x-offset and y-offset in the coordinate // space of the block frame that contains it + // XXXbz the placeholder is not fully reflown yet if our containing block is + // relatively positioned... nsPoint placeholderOffset; GetPlaceholderOffset(aPlaceholderFrame, aBlockFrame, placeholderOffset); @@ -815,7 +803,8 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, // the line containing the placeholder frame, unless all the frames // before it are empty. In that case, it would have been just before // this line. - // XXXbz why the special-casing if we are the last line box? + // XXXbz the line box is not fully reflown yet if our containing block is + // relatively positioned... if (lineBox != blockFrame->end_lines()) { nsIFrame * firstFrame = lineBox->mFirstChild; while (firstFrame != aPlaceholderFrame) { @@ -893,8 +882,20 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, // The current coordinate space is that of the nearest block to the placeholder. // Convert to the coordinate space of the absolute containing block - if (aBlockFrame != aAbsoluteContainingBlockFrame) { - nsIFrame* parent = aBlockFrame; + nsIFrame* absoluteContainingBlock = cbrs->frame; + if (aBlockFrame != absoluteContainingBlock) { + nsIFrame* parent; + nsIFrame* stop; + if (NS_FRAME_GET_TYPE(cbrs->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { + // The absolute containing block is an inline frame... so it will be a + // descendant of aBlockFrame + parent = absoluteContainingBlock; + stop = aBlockFrame; + } else { + // aBlockFrame may be a descendant of absoluteContainingBlock + parent = aBlockFrame; + stop = absoluteContainingBlock; + } do { nsPoint origin = parent->GetPosition(); @@ -904,20 +905,25 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsIPresContext* aPresContext, // Move up the tree one level parent = parent->GetParent(); - } while (parent && (parent != aAbsoluteContainingBlockFrame)); + } while (parent && parent != stop); } - // The specified offsets are relative to the absolute containing block's padding - // edge, and our current values are relative to the border edge so translate - const nsStyleBorder* borderStyle = - aAbsoluteContainingBlockFrame->GetStyleBorder(); - nsMargin border; - if (!borderStyle->GetBorder(border)) { - NS_NOTYETIMPLEMENTED("percentage border"); + // The specified offsets are relative to the absolute containing block's + // padding edge or content edge, and our current values are relative to the + // border edge, so translate. + if (NS_FRAME_GET_TYPE(cbrs->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { + // content edge + const nsMargin& borderPadding = cbrs->mComputedBorderPadding; + aHypotheticalBox.mLeft -= borderPadding.left; + aHypotheticalBox.mRight -= borderPadding.right; + aHypotheticalBox.mTop -= borderPadding.top; + } else { + // padding edge + nsMargin border = cbrs->mComputedBorderPadding - cbrs->mComputedPadding; + aHypotheticalBox.mLeft -= border.left; + aHypotheticalBox.mRight -= border.right; + aHypotheticalBox.mTop -= border.top; } - aHypotheticalBox.mLeft -= border.left; - aHypotheticalBox.mRight -= border.left; - aHypotheticalBox.mTop -= border.top; } void @@ -951,7 +957,7 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsIPresContext* aPresContext, (eStyleUnit_Auto == mStylePosition->mOffset.GetBottomUnit()))) { CalculateHypotheticalBox(aPresContext, placeholderFrame, blockFrame, - blockContentArea, cbrs->frame, hypotheticalBox); + blockContentArea, cbrs, hypotheticalBox); } // Initialize the 'left' and 'right' computed offsets @@ -1097,6 +1103,8 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsIPresContext* aPresContext, mComputedBorderPadding.right - mComputedMargin.right - mComputedOffsets.right; + mComputedWidth = PR_MAX(mComputedWidth, 0); + AdjustComputedWidth(PR_FALSE); // XXX If the direction is rtl then we need to reevaluate left... @@ -1246,6 +1254,8 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsIPresContext* aPresContext, mComputedBorderPadding.bottom - mComputedMargin.bottom - mComputedOffsets.bottom; + mComputedHeight = PR_MAX(mComputedHeight, 0); + AdjustComputedHeight(PR_FALSE); } @@ -1271,6 +1281,16 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsIPresContext* aPresContext, } } } + + // Now that we've solved for our auto offsets and so forth, we need to adjust + // the offsets to what the rest of layout actually expects them to be. The + // offsets as computed now are relative to the parent's padding edge if the + // parent is a block and the parent's content edge if the parent is an + // inline. We need them to be relative to the parent's padding edge for + // nsAbsoluteContainer reflow to work right. + if (NS_FRAME_GET_TYPE(cbrs->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { + mComputedOffsets += cbrs->mComputedPadding; + } } static PRBool @@ -1439,37 +1459,22 @@ nsHTMLReflowState::ComputeContainingBlockRectangle(nsIPresContext* aPre if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE) { // See if the ancestor is block-level or inline-level if (NS_FRAME_GET_TYPE(aContainingBlockRS->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { - // The CSS2 spec says that if the ancestor is inline-level, the containing - // block depends on the 'direction' property of the ancestor. For direction - // 'ltr', it's the top and left of the content edges of the first box and - // the bottom and right content edges of the last box - // - // XXX This is a pain because it isn't top-down and it requires that we've - // completely reflowed the ancestor. It also isn't clear what happens when - // a relatively positioned ancestor is split across pages. So instead use - // the computed width and height of the nearest block-level ancestor - const nsHTMLReflowState* cbrs = aContainingBlockRS; - while (cbrs) { - nsCSSFrameType type = NS_FRAME_GET_TYPE(cbrs->mFrameType); - if ((NS_CSS_FRAME_TYPE_BLOCK == type) || - (NS_CSS_FRAME_TYPE_FLOATING == type) || - (NS_CSS_FRAME_TYPE_ABSOLUTE == type)) { - - aContainingBlockWidth = cbrs->mComputedWidth; - aContainingBlockHeight = cbrs->mComputedHeight; - - if (NS_CSS_FRAME_TYPE_ABSOLUTE == type) { - aContainingBlockWidth += cbrs->mComputedPadding.left + - cbrs->mComputedPadding.right; - aContainingBlockHeight += cbrs->mComputedPadding.top + - cbrs->mComputedPadding.bottom; - } - break; - } - - cbrs = (const nsHTMLReflowState*)cbrs->parentReflowState; // XXX cast - } - + // Base our size on the actual size of the frame. In cases when this is + // completely bogus (eg initial reflow), this code shouldn't even be + // called, since the code in nsPositionedInlineFrame::Reflow will pass in + // the containing block dimensions to our constructor. + // XXXbz we should be taking the in-flows into account too, but + // that's very hard. + aContainingBlockWidth = aContainingBlockRS->frame->GetRect().width - + (aContainingBlockRS->mComputedBorderPadding.left + + aContainingBlockRS->mComputedBorderPadding.right); + NS_ASSERTION(aContainingBlockWidth >= 0, + "Negative containing block width!"); + aContainingBlockHeight = aContainingBlockRS->frame->GetRect().height - + (aContainingBlockRS->mComputedBorderPadding.top + + aContainingBlockRS->mComputedBorderPadding.bottom); + NS_ASSERTION(aContainingBlockHeight >= 0, + "Negative containing block height!"); } else { // If the ancestor is block-level, the containing block is formed by the // padding edge of the ancestor @@ -1584,7 +1589,7 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext, mComputedMaxWidth = mComputedMaxHeight = NS_UNCONSTRAINEDSIZE; } else { // Get the containing block reflow state - const nsHTMLReflowState* cbrs = parentReflowState->mCBReflowState; + const nsHTMLReflowState* cbrs = mCBReflowState; NS_ASSERTION(nsnull != cbrs, "no containing block"); // If we weren't given a containing block width and height, then diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp index 0feeb79f89e..6fcfc68455a 100644 --- a/mozilla/layout/html/base/src/nsInlineFrame.cpp +++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp @@ -1286,8 +1286,13 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, (eReflowReason_Incremental != aReflowState.reason || aReflowState.path->mReflowCommand || mRect != oldRect)) { - nscoord containingBlockWidth = -1; - nscoord containingBlockHeight = -1; + // The containing block for the abs pos kids is formed by our content edge. + nscoord containingBlockWidth = aDesiredSize.width - + (aReflowState.mComputedBorderPadding.left + + aReflowState.mComputedBorderPadding.right); + nscoord containingBlockHeight = aDesiredSize.height - + (aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom); nsRect childBounds; rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState, diff --git a/mozilla/layout/html/base/src/nsLineLayout.cpp b/mozilla/layout/html/base/src/nsLineLayout.cpp index 19261b15f63..fc2edbffa9c 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.cpp +++ b/mozilla/layout/html/base/src/nsLineLayout.cpp @@ -316,7 +316,7 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY, } else if (eStyleUnit_Percent == unit) { nscoord width = - nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState->parentReflowState); + nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState); if ((0 != width) && (NS_UNCONSTRAINEDSIZE != width)) { indent = nscoord(mStyleText->mTextIndent.GetPercentValue() * width); } diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp index 7a8f2d2e9f9..7c716889599 100644 --- a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp @@ -525,7 +525,7 @@ GetContainingBlockSize(const nsHTMLReflowState& aOuterRS) { nsSize size(0,0); const nsHTMLReflowState* containRS = - aOuterRS.parentReflowState->mCBReflowState; + aOuterRS.mCBReflowState; if (containRS) { size.width = containRS->mComputedWidth; diff --git a/mozilla/layout/tables/nsTableOuterFrame.cpp b/mozilla/layout/tables/nsTableOuterFrame.cpp index 7a8f2d2e9f9..7c716889599 100644 --- a/mozilla/layout/tables/nsTableOuterFrame.cpp +++ b/mozilla/layout/tables/nsTableOuterFrame.cpp @@ -525,7 +525,7 @@ GetContainingBlockSize(const nsHTMLReflowState& aOuterRS) { nsSize size(0,0); const nsHTMLReflowState* containRS = - aOuterRS.parentReflowState->mCBReflowState; + aOuterRS.mCBReflowState; if (containRS) { size.width = containRS->mComputedWidth;