зеркало из https://github.com/mozilla/gecko-dev.git
Reworked vertical margin handling; fixed some issues with floater placement and clearing and block element clearing (bugs #1080, #1808, ...
This commit is contained in:
Родитель
b1b830e9e8
Коммит
0b54ff5195
|
@ -54,9 +54,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
// XXX get rid of the need for this
|
||||
#define SLOW_INCREMENTAL_REFLOW
|
||||
|
||||
// If I can add in IsAPlaceHolder then we can remove the mFloaters
|
||||
// void array from the nsLineBox
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_FIRST_LINE
|
||||
#undef REALLY_NOISY_FIRST_LINE
|
||||
|
@ -68,6 +65,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#else
|
||||
#undef NOISY_FIRST_LINE
|
||||
|
@ -80,6 +78,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#endif
|
||||
|
||||
|
@ -230,10 +229,6 @@ public:
|
|||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
}
|
||||
|
||||
PRBool ShouldApplyTopMargin() const {
|
||||
return mIsMarginRoot || !IsAdjacentWithTop();
|
||||
}
|
||||
|
||||
const nsMargin& BorderPadding() const {
|
||||
return mReflowState.mComputedBorderPadding;
|
||||
}
|
||||
|
@ -290,14 +285,12 @@ public:
|
|||
|
||||
nsIFrame* mNextRCFrame;
|
||||
|
||||
// Is this frame a root for margin collapsing?
|
||||
PRBool mIsMarginRoot;
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRBool mIsTopMarginRoot;
|
||||
PRBool mIsBottomMarginRoot;
|
||||
|
||||
// The computed collapsed top margin value that the frame did not
|
||||
// apply but is passing out to the frames parent so that the parent
|
||||
// can perform generational margin collapsing. This value ends up
|
||||
// being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin.
|
||||
nscoord mCarriedOutTopMargin;
|
||||
// See ShouldApplyTopMargin
|
||||
PRBool mApplyTopMargin;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
|
@ -324,8 +317,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mBlock(aFrame),
|
||||
mPrevBottomMargin(0),
|
||||
mNextRCFrame(nsnull),
|
||||
mIsMarginRoot(PR_FALSE),
|
||||
mCarriedOutTopMargin(0)
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
|
@ -413,8 +407,11 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) {
|
||||
mIsMarginRoot = PR_TRUE;
|
||||
if (0 != borderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,10 +451,7 @@ nsBlockReflowState::GetAvailableSpace()
|
|||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0xa6cf90df, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
static const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
nsresult
|
||||
NS_NewBlockFrame(nsIFrame*& aNewFrame, PRUint32 aFlags)
|
||||
|
@ -691,6 +685,9 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const
|
|||
if (0 != mState) {
|
||||
fprintf(out, " [state=%08x]", mState);
|
||||
}
|
||||
if (0 != mFlags) {
|
||||
fprintf(out, " [flags=%x]", mFlags);
|
||||
}
|
||||
fputs("<\n", out);
|
||||
aIndent++;
|
||||
|
||||
|
@ -821,106 +818,6 @@ nsBlockFrame::IsPercentageBase(PRBool& aBase) const
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Reflow methods
|
||||
|
||||
#if 0
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext,
|
||||
const nsReflowState* aParentReflowState,
|
||||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult)
|
||||
{
|
||||
NS_PRECONDITION((nsnull != aTopMarginResult) &&
|
||||
(nsnull != aBottomMarginResult), "null ptr");
|
||||
if ((nsnull != aTopMarginResult) || (nsnull != aBottomMarginResult)) {
|
||||
nsMargin myMargin(0, 0, 0, 0);
|
||||
if (0 == (BLOCK_IS_INLINE & mFlags)) {
|
||||
nsHTMLReflowState::ComputeMarginFor(this, aParentReflowState, myMargin);
|
||||
}
|
||||
|
||||
// Find the first appropriate line (skipping over an empty line if
|
||||
// present) that contains a block that can be used for a
|
||||
// parent-child margin collapse.
|
||||
nsLineBox* firstLine = nsnull;
|
||||
nscoord firstLineTopMargin = 0;
|
||||
if (nsnull != aTopMarginResult) {
|
||||
nsLineBox* line = mLines;
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = line->mNext;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
firstLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the last appropriate line (skipping over an empty line)...
|
||||
nsLineBox* lastLine = nsnull;
|
||||
nscoord lastLineBottomMargin = 0;
|
||||
if (nsnull != aBottomMarginResult) {
|
||||
// Find the last line (line) and the previous to the last line
|
||||
// (prevLine)
|
||||
nsLineBox* line = mLines;
|
||||
nsLineBox* prevLine = nsnull;
|
||||
while (nsnull != line) {
|
||||
nsLineBox* next = line->mNext;
|
||||
if (nsnull == next) {
|
||||
break;
|
||||
}
|
||||
prevLine = line;
|
||||
line = next;
|
||||
}
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = prevLine;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
lastLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nsnull != firstLine) {
|
||||
if (lastLine == firstLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
else {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
nsnull);
|
||||
}
|
||||
firstLineTopMargin
|
||||
}
|
||||
else if (nsnull != lastLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
nsnull,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
|
||||
if ((nsnull != aTopMarginResult) && (nsnull != aBottomMarginResult)) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
else if (nsnull != aTopMarginResult) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
}
|
||||
else {
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
|
@ -933,7 +830,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsMarginRoot = PR_TRUE;
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (state.mIsTopMarginRoot) {
|
||||
state.mApplyTopMargin = PR_TRUE;
|
||||
}
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
|
@ -1009,11 +910,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d,%d\n",
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d\n",
|
||||
aReflowState.availableWidth, aReflowState.availableHeight,
|
||||
aReflowState.computedWidth, aReflowState.computedHeight,
|
||||
aMetrics.width, aMetrics.height,
|
||||
aMetrics.mCarriedOutTopMargin, aMetrics.mCarriedOutBottomMargin);
|
||||
aMetrics.mCarriedOutBottomMargin);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
@ -1048,7 +949,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.height = 0;
|
||||
aMetrics.ascent = 0;
|
||||
aMetrics.descent = 0;
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = 0;
|
||||
|
@ -1164,9 +1064,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsMarginRoot) {
|
||||
// When we are a margin root make sure that our last childs
|
||||
// bottom margin is fully applied.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
autoHeight += aState.mPrevBottomMargin;
|
||||
}
|
||||
|
@ -1203,15 +1103,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.maxElementSize->height = maxHeight;
|
||||
}
|
||||
|
||||
// Return top and bottom margin information
|
||||
if (aState.mIsMarginRoot) {
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aMetrics.mCarriedOutTopMargin = aState.mCarriedOutTopMargin;
|
||||
aMetrics.mCarriedOutBottomMargin = aState.mPrevBottomMargin;
|
||||
}
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
|
@ -1464,7 +1358,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
// Recover the natural (un-collapsed margins) for the child
|
||||
nsMargin childMargins(0, 0, 0, 0);
|
||||
//XXX nsMargin childMargins(0, 0, 0, 0);
|
||||
if (aLine->IsBlock()) {
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
const nsStyleSpacing* spacing;
|
||||
|
@ -1477,6 +1371,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
#endif
|
||||
}
|
||||
|
||||
aState.mPrevBottomMargin = 0;
|
||||
#if XXX_fix_me
|
||||
// Recompute running margin value (aState.mPrevBottomMargin). Also
|
||||
// recover the aState.carriedOutTopMargin, when appropriate.
|
||||
nscoord topMargin, bottomMargin;
|
||||
|
@ -1487,7 +1383,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin,
|
||||
topMargin, bottomMargin);
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
if (!aState.ShouldApplyTopMargin()) {
|
||||
if (!ShouldApplyTopMargin(aState, aLine)) {
|
||||
aState.mCarriedOutTopMargin = topMargin;
|
||||
}
|
||||
|
||||
|
@ -1497,6 +1393,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, aDeltaY,
|
||||
PR_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
aState.mY = aLine->mBounds.y;
|
||||
aState.PlaceCurrentLineFloaters(aLine->mFloaters);
|
||||
|
@ -2225,6 +2123,111 @@ nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (!aState.IsAdjacentWithTop()) {
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Determine if this line is "essentially" the first line
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
|
||||
// The line being reflowed is "essentially" the first line in the
|
||||
// block. Therefore its top-margin will be collapsed by the
|
||||
// generational collapsing logic with its parent (us).
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
nsIFrame* firstChild = mLines ? mLines->mFirstChild : nsnull;
|
||||
if (firstChild) {
|
||||
if (mLines->IsBlock()) {
|
||||
// Winner
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
// If the first line is not a block line then the second line must
|
||||
// be a block line otherwise the top child can't be a block.
|
||||
nsLineBox* next = mLines->mNext;
|
||||
if ((nsnull == next) || !next->IsBlock()) {
|
||||
// There is no line after the first line or its not a block so
|
||||
// don't bother trying to skip over the first line.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// The only time we can skip over the first line and pretend its
|
||||
// not there is if the line contains only compressed
|
||||
// whitespace. If white-space is significant to this frame then we
|
||||
// can't skip over the line.
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if (NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) {
|
||||
// Whitespace is significant
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// See if each frame is a text frame that contains nothing but
|
||||
// whitespace.
|
||||
PRInt32 n = mLines->mChildCount;
|
||||
while (--n >= 0) {
|
||||
nsIContent* content;
|
||||
nsresult rv = firstChild->GetContent(&content);
|
||||
if (NS_FAILED(rv) || (nsnull == content)) {
|
||||
return nsnull;
|
||||
}
|
||||
nsITextContent* tc;
|
||||
rv = content->QueryInterface(kITextContentIID, (void**) &tc);
|
||||
NS_RELEASE(content);
|
||||
if (NS_FAILED(rv) || (nsnull == tc)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
PRBool isws = PR_FALSE;
|
||||
tc->IsOnlyWhitespace(&isws);
|
||||
NS_RELEASE(tc);
|
||||
if (!isws) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
firstChild->GetNextSibling(&firstChild);
|
||||
}
|
||||
|
||||
// If we make it to this point then every frame on the first line
|
||||
// was compressible white-space. Since we already know that the
|
||||
// second line contains a block, that block is the
|
||||
// top-block-child.
|
||||
return next->mFirstChild;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2276,17 +2279,60 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
brc.SetCompactMarginWidth(compactMarginWidth);
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
// reflowed is a continuation (non-null prev-in-flow) then we don't
|
||||
// apply its top margin because its not significant. Otherwise, dig
|
||||
// deeper.
|
||||
PRBool applyTopMargin = PR_FALSE;
|
||||
nsIFrame* framePrevInFlow;
|
||||
frame->GetPrevInFlow(&framePrevInFlow);
|
||||
if (nsnull == framePrevInFlow) {
|
||||
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
|
||||
}
|
||||
|
||||
// Clear floaters before the block if the clear style is not none
|
||||
aLine->mBreakType = display->mBreakType;
|
||||
if (NS_STYLE_CLEAR_NONE != display->mBreakType) {
|
||||
nscoord saveY, deltaY;
|
||||
switch (display->mBreakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
||||
aState.ClearFloaters(aState.mY, display->mBreakType);
|
||||
// XXX: ?If we just advanced Y then we need to factor that amount
|
||||
// into the next margin calculation and reduce the amount of Y
|
||||
// margin applied by the amount just moved.
|
||||
// Apply the previous margin before clearing
|
||||
saveY = aState.mY + aState.mPrevBottomMargin;
|
||||
aState.ClearFloaters(saveY, display->mBreakType);
|
||||
|
||||
// Determine how far we just moved. If we didn't move then there
|
||||
// was nothing to clear to don't mess with the normal margin
|
||||
// collapsing behavior. In either case we need to restore the Y
|
||||
// coordinate to what it was before the clear.
|
||||
deltaY = aState.mY - saveY;
|
||||
if (0 != deltaY) {
|
||||
// Pretend that the distance we just moved is a previous
|
||||
// blocks bottom margin. Note that GetAvailableSpace has been
|
||||
// done so that the available space calculations will be done
|
||||
// after clearing the appropriate floaters.
|
||||
//
|
||||
// What we are doing here is applying CSS2 section 9.5.2's
|
||||
// rules for clearing - "The top margin of the generated box
|
||||
// is increased enough that the top border edge is below the
|
||||
// bottom outer edge of the floating boxes..."
|
||||
//
|
||||
// What this will do is cause the top-margin of the block
|
||||
// frame we are about to reflow to be collapsed with that
|
||||
// distance.
|
||||
aState.mPrevBottomMargin = deltaY;
|
||||
aState.mY = saveY;
|
||||
|
||||
// Force margin to be applied in this circumstance
|
||||
applyTopMargin = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Put aState.mY back to its original value since no clearing
|
||||
// happened. That way the previous blocks bottom margin will
|
||||
// be applied properly.
|
||||
aState.mY = saveY - aState.mPrevBottomMargin;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2331,29 +2377,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
WillReflowFrame(aState, aLine, frame);
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsMargin computedOffsets;
|
||||
PRBool applyTopMargin = aState.ShouldApplyTopMargin();
|
||||
if (!applyTopMargin) {
|
||||
// XXX clarify the IsAdjacentWithTop
|
||||
|
||||
// XXX rationalize this with the box model....
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
rv = brc.ReflowBlock(frame, availSpace,
|
||||
#ifdef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin, aState.mPrevBottomMargin,
|
||||
#endif
|
||||
aState.IsAdjacentWithTop(),
|
||||
rv = brc.ReflowBlock(frame, availSpace, applyTopMargin,
|
||||
aState.mPrevBottomMargin, aState.IsAdjacentWithTop(),
|
||||
computedOffsets, frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -2375,21 +2400,13 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
|
||||
// Try to place the child block
|
||||
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop,
|
||||
#ifndef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin,
|
||||
aState.mPrevBottomMargin,
|
||||
#endif
|
||||
computedOffsets,
|
||||
nscoord collapsedBottomMargin;
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, aLine->mCombinedArea);
|
||||
if (*aKeepReflowGoing) {
|
||||
// Some of the child block fit
|
||||
|
||||
// Set carry out top margin value when margin is not being applied
|
||||
if (!applyTopMargin) {
|
||||
aState.mCarriedOutTopMargin = brc.GetCollapsedTopMargin();
|
||||
}
|
||||
|
||||
// Advance to new Y position
|
||||
nscoord newY = aLine->mBounds.YMost();
|
||||
if (isCompactFrame) {
|
||||
|
@ -2406,7 +2423,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
aState.mY = newY;
|
||||
aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
//XXX aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
aLine->mCarriedOutBottomMargin = brc.GetCarriedOutBottomMargin();
|
||||
|
||||
// Continue the block frame now if it didn't completely fit in
|
||||
|
@ -2448,8 +2465,16 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aState.mPrevBottomMargin = brc.GetCollapsedBottomMargin();
|
||||
aState.mPrevBottomMargin = collapsedBottomMargin;
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
ListTag(stdout);
|
||||
printf(": frame=");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
|
||||
aLine->mCarriedOutBottomMargin, collapsedBottomMargin,
|
||||
aState.mPrevBottomMargin);
|
||||
#endif
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(brc.GetMaxElementSize());
|
||||
|
@ -2501,9 +2526,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Tall bullets won't look particularly nice here...
|
||||
nsRect bbox;
|
||||
mBullet->GetRect(bbox);
|
||||
nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent +
|
||||
topMargin;
|
||||
nscoord topMargin = applyTopMargin ? collapsedBottomMargin : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
}
|
||||
}
|
||||
|
@ -2553,8 +2577,10 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into.
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
|
@ -2568,7 +2594,8 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mCurrentBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight,
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
|
||||
|
@ -3023,11 +3050,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// Calculate the bottom margin for the line.
|
||||
nscoord lineBottomMargin = 0;
|
||||
if (0 == aLine->mBounds.height) {
|
||||
// XXX I don't think that this is necessary anymore because of the
|
||||
// way that min-line-height is applied in the vertical alignment
|
||||
// code; since we always have a line-height, a BR on its own line
|
||||
// will get at least the default line-height amount of vertical
|
||||
// space.
|
||||
nsIFrame* brFrame = lineLayout->GetBRFrame();
|
||||
if (nsnull != brFrame) {
|
||||
// If a line ends in a BR, and the line is empty of height, then
|
||||
|
@ -3051,6 +3073,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Calculate the lines top and bottom margin values. The margin will
|
||||
// come from an embedded block frame, not from inline
|
||||
// frames. Because this is an "inline" line, the child margins are
|
||||
|
@ -3068,14 +3091,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mCarriedOutTopMargin = topMargin;
|
||||
topMargin = 0;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
lineLayout = nsnull;
|
||||
//XXX aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = lineLayout->GetCarriedOutBottomMargin();
|
||||
#endif
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
// impacted by prior block margins. If this line ends up having some
|
||||
// height then we zero out the previous bottom margin value that was
|
||||
// already applied to the line's starting Y coordinate. Otherwise we
|
||||
// leave it be so that the previous blocks bottom margin can be
|
||||
// collapsed with a block that follows.
|
||||
nscoord newY;
|
||||
if (aLine->mBounds.height > 0) {
|
||||
// This line has some height. Therefore the application of the
|
||||
// previous-bottom-margin should stick.
|
||||
aState.mPrevBottomMargin = 0;
|
||||
newY = aLine->mBounds.YMost() + lineBottomMargin;
|
||||
}
|
||||
else {
|
||||
// Don't let the previous-bottom-margin value affect the newY
|
||||
// coordinate (it was applied in ReflowInlineFrames speculatively)
|
||||
// since the line is empty.
|
||||
newY = aState.mY - aState.mPrevBottomMargin + lineBottomMargin;
|
||||
}
|
||||
aLine->mCarriedOutBottomMargin = 0;/* XXX ib */
|
||||
|
||||
// See if the line fit. If it doesn't we need to push it. Our first
|
||||
// line will always fit.
|
||||
nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin;
|
||||
if ((mLines != aLine) && (newY > aState.mBottomEdge)) {
|
||||
// Push this line and all of it's children and anything else that
|
||||
// follows to our next-in-flow
|
||||
|
@ -3089,18 +3130,18 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = cobm;
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
#if 0
|
||||
if (0 != topMargin) {
|
||||
// Apply collapsed top-margin value
|
||||
SlideFrames(aState.mPresContext, aState.mSpaceManager, aLine, topMargin);
|
||||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, topMargin,
|
||||
PR_TRUE);
|
||||
}
|
||||
#endif
|
||||
aState.mY = newY;
|
||||
|
||||
if (0 != aState.mCurrentBand.GetFloaterCount()) {
|
||||
|
@ -3135,6 +3176,8 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4170,12 +4213,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
mBlock->ReflowFloater(*this, aPlaceholder, metrics);
|
||||
|
||||
// Flush out pending bottom margin before placing floater
|
||||
if (0 != mPrevBottomMargin) {
|
||||
mY += mPrevBottomMargin;
|
||||
mPrevBottomMargin = 0;
|
||||
}
|
||||
|
||||
// Because we are in the middle of reflowing a placeholder frame
|
||||
// within a line (and possibly nested in an inline frame or two
|
||||
// that's a child of our block) we need to restore the space
|
||||
|
@ -4191,7 +4228,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
PlaceFloater(aPlaceholder, &isLeftFloater, &origin);
|
||||
|
||||
// Update the floater combined-area
|
||||
// XXX SlideFrames will muck this up!
|
||||
metrics.mCombinedArea.x += origin.x;
|
||||
metrics.mCombinedArea.y += origin.y;
|
||||
CombineRects(metrics.mCombinedArea, mFloaterCombinedArea);
|
||||
|
|
|
@ -54,9 +54,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
// XXX get rid of the need for this
|
||||
#define SLOW_INCREMENTAL_REFLOW
|
||||
|
||||
// If I can add in IsAPlaceHolder then we can remove the mFloaters
|
||||
// void array from the nsLineBox
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_FIRST_LINE
|
||||
#undef REALLY_NOISY_FIRST_LINE
|
||||
|
@ -68,6 +65,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#else
|
||||
#undef NOISY_FIRST_LINE
|
||||
|
@ -80,6 +78,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#endif
|
||||
|
||||
|
@ -230,10 +229,6 @@ public:
|
|||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
}
|
||||
|
||||
PRBool ShouldApplyTopMargin() const {
|
||||
return mIsMarginRoot || !IsAdjacentWithTop();
|
||||
}
|
||||
|
||||
const nsMargin& BorderPadding() const {
|
||||
return mReflowState.mComputedBorderPadding;
|
||||
}
|
||||
|
@ -290,14 +285,12 @@ public:
|
|||
|
||||
nsIFrame* mNextRCFrame;
|
||||
|
||||
// Is this frame a root for margin collapsing?
|
||||
PRBool mIsMarginRoot;
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRBool mIsTopMarginRoot;
|
||||
PRBool mIsBottomMarginRoot;
|
||||
|
||||
// The computed collapsed top margin value that the frame did not
|
||||
// apply but is passing out to the frames parent so that the parent
|
||||
// can perform generational margin collapsing. This value ends up
|
||||
// being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin.
|
||||
nscoord mCarriedOutTopMargin;
|
||||
// See ShouldApplyTopMargin
|
||||
PRBool mApplyTopMargin;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
|
@ -324,8 +317,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mBlock(aFrame),
|
||||
mPrevBottomMargin(0),
|
||||
mNextRCFrame(nsnull),
|
||||
mIsMarginRoot(PR_FALSE),
|
||||
mCarriedOutTopMargin(0)
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
|
@ -413,8 +407,11 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) {
|
||||
mIsMarginRoot = PR_TRUE;
|
||||
if (0 != borderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,10 +451,7 @@ nsBlockReflowState::GetAvailableSpace()
|
|||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0xa6cf90df, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
static const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
nsresult
|
||||
NS_NewBlockFrame(nsIFrame*& aNewFrame, PRUint32 aFlags)
|
||||
|
@ -691,6 +685,9 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const
|
|||
if (0 != mState) {
|
||||
fprintf(out, " [state=%08x]", mState);
|
||||
}
|
||||
if (0 != mFlags) {
|
||||
fprintf(out, " [flags=%x]", mFlags);
|
||||
}
|
||||
fputs("<\n", out);
|
||||
aIndent++;
|
||||
|
||||
|
@ -821,106 +818,6 @@ nsBlockFrame::IsPercentageBase(PRBool& aBase) const
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Reflow methods
|
||||
|
||||
#if 0
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext,
|
||||
const nsReflowState* aParentReflowState,
|
||||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult)
|
||||
{
|
||||
NS_PRECONDITION((nsnull != aTopMarginResult) &&
|
||||
(nsnull != aBottomMarginResult), "null ptr");
|
||||
if ((nsnull != aTopMarginResult) || (nsnull != aBottomMarginResult)) {
|
||||
nsMargin myMargin(0, 0, 0, 0);
|
||||
if (0 == (BLOCK_IS_INLINE & mFlags)) {
|
||||
nsHTMLReflowState::ComputeMarginFor(this, aParentReflowState, myMargin);
|
||||
}
|
||||
|
||||
// Find the first appropriate line (skipping over an empty line if
|
||||
// present) that contains a block that can be used for a
|
||||
// parent-child margin collapse.
|
||||
nsLineBox* firstLine = nsnull;
|
||||
nscoord firstLineTopMargin = 0;
|
||||
if (nsnull != aTopMarginResult) {
|
||||
nsLineBox* line = mLines;
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = line->mNext;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
firstLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the last appropriate line (skipping over an empty line)...
|
||||
nsLineBox* lastLine = nsnull;
|
||||
nscoord lastLineBottomMargin = 0;
|
||||
if (nsnull != aBottomMarginResult) {
|
||||
// Find the last line (line) and the previous to the last line
|
||||
// (prevLine)
|
||||
nsLineBox* line = mLines;
|
||||
nsLineBox* prevLine = nsnull;
|
||||
while (nsnull != line) {
|
||||
nsLineBox* next = line->mNext;
|
||||
if (nsnull == next) {
|
||||
break;
|
||||
}
|
||||
prevLine = line;
|
||||
line = next;
|
||||
}
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = prevLine;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
lastLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nsnull != firstLine) {
|
||||
if (lastLine == firstLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
else {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
nsnull);
|
||||
}
|
||||
firstLineTopMargin
|
||||
}
|
||||
else if (nsnull != lastLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
nsnull,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
|
||||
if ((nsnull != aTopMarginResult) && (nsnull != aBottomMarginResult)) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
else if (nsnull != aTopMarginResult) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
}
|
||||
else {
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
|
@ -933,7 +830,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsMarginRoot = PR_TRUE;
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (state.mIsTopMarginRoot) {
|
||||
state.mApplyTopMargin = PR_TRUE;
|
||||
}
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
|
@ -1009,11 +910,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d,%d\n",
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d\n",
|
||||
aReflowState.availableWidth, aReflowState.availableHeight,
|
||||
aReflowState.computedWidth, aReflowState.computedHeight,
|
||||
aMetrics.width, aMetrics.height,
|
||||
aMetrics.mCarriedOutTopMargin, aMetrics.mCarriedOutBottomMargin);
|
||||
aMetrics.mCarriedOutBottomMargin);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
@ -1048,7 +949,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.height = 0;
|
||||
aMetrics.ascent = 0;
|
||||
aMetrics.descent = 0;
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = 0;
|
||||
|
@ -1164,9 +1064,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsMarginRoot) {
|
||||
// When we are a margin root make sure that our last childs
|
||||
// bottom margin is fully applied.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
autoHeight += aState.mPrevBottomMargin;
|
||||
}
|
||||
|
@ -1203,15 +1103,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.maxElementSize->height = maxHeight;
|
||||
}
|
||||
|
||||
// Return top and bottom margin information
|
||||
if (aState.mIsMarginRoot) {
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aMetrics.mCarriedOutTopMargin = aState.mCarriedOutTopMargin;
|
||||
aMetrics.mCarriedOutBottomMargin = aState.mPrevBottomMargin;
|
||||
}
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
|
@ -1464,7 +1358,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
// Recover the natural (un-collapsed margins) for the child
|
||||
nsMargin childMargins(0, 0, 0, 0);
|
||||
//XXX nsMargin childMargins(0, 0, 0, 0);
|
||||
if (aLine->IsBlock()) {
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
const nsStyleSpacing* spacing;
|
||||
|
@ -1477,6 +1371,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
#endif
|
||||
}
|
||||
|
||||
aState.mPrevBottomMargin = 0;
|
||||
#if XXX_fix_me
|
||||
// Recompute running margin value (aState.mPrevBottomMargin). Also
|
||||
// recover the aState.carriedOutTopMargin, when appropriate.
|
||||
nscoord topMargin, bottomMargin;
|
||||
|
@ -1487,7 +1383,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin,
|
||||
topMargin, bottomMargin);
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
if (!aState.ShouldApplyTopMargin()) {
|
||||
if (!ShouldApplyTopMargin(aState, aLine)) {
|
||||
aState.mCarriedOutTopMargin = topMargin;
|
||||
}
|
||||
|
||||
|
@ -1497,6 +1393,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, aDeltaY,
|
||||
PR_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
aState.mY = aLine->mBounds.y;
|
||||
aState.PlaceCurrentLineFloaters(aLine->mFloaters);
|
||||
|
@ -2225,6 +2123,111 @@ nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (!aState.IsAdjacentWithTop()) {
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Determine if this line is "essentially" the first line
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
|
||||
// The line being reflowed is "essentially" the first line in the
|
||||
// block. Therefore its top-margin will be collapsed by the
|
||||
// generational collapsing logic with its parent (us).
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
nsIFrame* firstChild = mLines ? mLines->mFirstChild : nsnull;
|
||||
if (firstChild) {
|
||||
if (mLines->IsBlock()) {
|
||||
// Winner
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
// If the first line is not a block line then the second line must
|
||||
// be a block line otherwise the top child can't be a block.
|
||||
nsLineBox* next = mLines->mNext;
|
||||
if ((nsnull == next) || !next->IsBlock()) {
|
||||
// There is no line after the first line or its not a block so
|
||||
// don't bother trying to skip over the first line.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// The only time we can skip over the first line and pretend its
|
||||
// not there is if the line contains only compressed
|
||||
// whitespace. If white-space is significant to this frame then we
|
||||
// can't skip over the line.
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if (NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) {
|
||||
// Whitespace is significant
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// See if each frame is a text frame that contains nothing but
|
||||
// whitespace.
|
||||
PRInt32 n = mLines->mChildCount;
|
||||
while (--n >= 0) {
|
||||
nsIContent* content;
|
||||
nsresult rv = firstChild->GetContent(&content);
|
||||
if (NS_FAILED(rv) || (nsnull == content)) {
|
||||
return nsnull;
|
||||
}
|
||||
nsITextContent* tc;
|
||||
rv = content->QueryInterface(kITextContentIID, (void**) &tc);
|
||||
NS_RELEASE(content);
|
||||
if (NS_FAILED(rv) || (nsnull == tc)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
PRBool isws = PR_FALSE;
|
||||
tc->IsOnlyWhitespace(&isws);
|
||||
NS_RELEASE(tc);
|
||||
if (!isws) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
firstChild->GetNextSibling(&firstChild);
|
||||
}
|
||||
|
||||
// If we make it to this point then every frame on the first line
|
||||
// was compressible white-space. Since we already know that the
|
||||
// second line contains a block, that block is the
|
||||
// top-block-child.
|
||||
return next->mFirstChild;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2276,17 +2279,60 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
brc.SetCompactMarginWidth(compactMarginWidth);
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
// reflowed is a continuation (non-null prev-in-flow) then we don't
|
||||
// apply its top margin because its not significant. Otherwise, dig
|
||||
// deeper.
|
||||
PRBool applyTopMargin = PR_FALSE;
|
||||
nsIFrame* framePrevInFlow;
|
||||
frame->GetPrevInFlow(&framePrevInFlow);
|
||||
if (nsnull == framePrevInFlow) {
|
||||
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
|
||||
}
|
||||
|
||||
// Clear floaters before the block if the clear style is not none
|
||||
aLine->mBreakType = display->mBreakType;
|
||||
if (NS_STYLE_CLEAR_NONE != display->mBreakType) {
|
||||
nscoord saveY, deltaY;
|
||||
switch (display->mBreakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
||||
aState.ClearFloaters(aState.mY, display->mBreakType);
|
||||
// XXX: ?If we just advanced Y then we need to factor that amount
|
||||
// into the next margin calculation and reduce the amount of Y
|
||||
// margin applied by the amount just moved.
|
||||
// Apply the previous margin before clearing
|
||||
saveY = aState.mY + aState.mPrevBottomMargin;
|
||||
aState.ClearFloaters(saveY, display->mBreakType);
|
||||
|
||||
// Determine how far we just moved. If we didn't move then there
|
||||
// was nothing to clear to don't mess with the normal margin
|
||||
// collapsing behavior. In either case we need to restore the Y
|
||||
// coordinate to what it was before the clear.
|
||||
deltaY = aState.mY - saveY;
|
||||
if (0 != deltaY) {
|
||||
// Pretend that the distance we just moved is a previous
|
||||
// blocks bottom margin. Note that GetAvailableSpace has been
|
||||
// done so that the available space calculations will be done
|
||||
// after clearing the appropriate floaters.
|
||||
//
|
||||
// What we are doing here is applying CSS2 section 9.5.2's
|
||||
// rules for clearing - "The top margin of the generated box
|
||||
// is increased enough that the top border edge is below the
|
||||
// bottom outer edge of the floating boxes..."
|
||||
//
|
||||
// What this will do is cause the top-margin of the block
|
||||
// frame we are about to reflow to be collapsed with that
|
||||
// distance.
|
||||
aState.mPrevBottomMargin = deltaY;
|
||||
aState.mY = saveY;
|
||||
|
||||
// Force margin to be applied in this circumstance
|
||||
applyTopMargin = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Put aState.mY back to its original value since no clearing
|
||||
// happened. That way the previous blocks bottom margin will
|
||||
// be applied properly.
|
||||
aState.mY = saveY - aState.mPrevBottomMargin;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2331,29 +2377,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
WillReflowFrame(aState, aLine, frame);
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsMargin computedOffsets;
|
||||
PRBool applyTopMargin = aState.ShouldApplyTopMargin();
|
||||
if (!applyTopMargin) {
|
||||
// XXX clarify the IsAdjacentWithTop
|
||||
|
||||
// XXX rationalize this with the box model....
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
rv = brc.ReflowBlock(frame, availSpace,
|
||||
#ifdef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin, aState.mPrevBottomMargin,
|
||||
#endif
|
||||
aState.IsAdjacentWithTop(),
|
||||
rv = brc.ReflowBlock(frame, availSpace, applyTopMargin,
|
||||
aState.mPrevBottomMargin, aState.IsAdjacentWithTop(),
|
||||
computedOffsets, frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -2375,21 +2400,13 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
|
||||
// Try to place the child block
|
||||
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop,
|
||||
#ifndef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin,
|
||||
aState.mPrevBottomMargin,
|
||||
#endif
|
||||
computedOffsets,
|
||||
nscoord collapsedBottomMargin;
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, aLine->mCombinedArea);
|
||||
if (*aKeepReflowGoing) {
|
||||
// Some of the child block fit
|
||||
|
||||
// Set carry out top margin value when margin is not being applied
|
||||
if (!applyTopMargin) {
|
||||
aState.mCarriedOutTopMargin = brc.GetCollapsedTopMargin();
|
||||
}
|
||||
|
||||
// Advance to new Y position
|
||||
nscoord newY = aLine->mBounds.YMost();
|
||||
if (isCompactFrame) {
|
||||
|
@ -2406,7 +2423,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
aState.mY = newY;
|
||||
aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
//XXX aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
aLine->mCarriedOutBottomMargin = brc.GetCarriedOutBottomMargin();
|
||||
|
||||
// Continue the block frame now if it didn't completely fit in
|
||||
|
@ -2448,8 +2465,16 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aState.mPrevBottomMargin = brc.GetCollapsedBottomMargin();
|
||||
aState.mPrevBottomMargin = collapsedBottomMargin;
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
ListTag(stdout);
|
||||
printf(": frame=");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
|
||||
aLine->mCarriedOutBottomMargin, collapsedBottomMargin,
|
||||
aState.mPrevBottomMargin);
|
||||
#endif
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(brc.GetMaxElementSize());
|
||||
|
@ -2501,9 +2526,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Tall bullets won't look particularly nice here...
|
||||
nsRect bbox;
|
||||
mBullet->GetRect(bbox);
|
||||
nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent +
|
||||
topMargin;
|
||||
nscoord topMargin = applyTopMargin ? collapsedBottomMargin : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
}
|
||||
}
|
||||
|
@ -2553,8 +2577,10 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into.
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
|
@ -2568,7 +2594,8 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mCurrentBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight,
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
|
||||
|
@ -3023,11 +3050,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// Calculate the bottom margin for the line.
|
||||
nscoord lineBottomMargin = 0;
|
||||
if (0 == aLine->mBounds.height) {
|
||||
// XXX I don't think that this is necessary anymore because of the
|
||||
// way that min-line-height is applied in the vertical alignment
|
||||
// code; since we always have a line-height, a BR on its own line
|
||||
// will get at least the default line-height amount of vertical
|
||||
// space.
|
||||
nsIFrame* brFrame = lineLayout->GetBRFrame();
|
||||
if (nsnull != brFrame) {
|
||||
// If a line ends in a BR, and the line is empty of height, then
|
||||
|
@ -3051,6 +3073,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Calculate the lines top and bottom margin values. The margin will
|
||||
// come from an embedded block frame, not from inline
|
||||
// frames. Because this is an "inline" line, the child margins are
|
||||
|
@ -3068,14 +3091,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mCarriedOutTopMargin = topMargin;
|
||||
topMargin = 0;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
lineLayout = nsnull;
|
||||
//XXX aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = lineLayout->GetCarriedOutBottomMargin();
|
||||
#endif
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
// impacted by prior block margins. If this line ends up having some
|
||||
// height then we zero out the previous bottom margin value that was
|
||||
// already applied to the line's starting Y coordinate. Otherwise we
|
||||
// leave it be so that the previous blocks bottom margin can be
|
||||
// collapsed with a block that follows.
|
||||
nscoord newY;
|
||||
if (aLine->mBounds.height > 0) {
|
||||
// This line has some height. Therefore the application of the
|
||||
// previous-bottom-margin should stick.
|
||||
aState.mPrevBottomMargin = 0;
|
||||
newY = aLine->mBounds.YMost() + lineBottomMargin;
|
||||
}
|
||||
else {
|
||||
// Don't let the previous-bottom-margin value affect the newY
|
||||
// coordinate (it was applied in ReflowInlineFrames speculatively)
|
||||
// since the line is empty.
|
||||
newY = aState.mY - aState.mPrevBottomMargin + lineBottomMargin;
|
||||
}
|
||||
aLine->mCarriedOutBottomMargin = 0;/* XXX ib */
|
||||
|
||||
// See if the line fit. If it doesn't we need to push it. Our first
|
||||
// line will always fit.
|
||||
nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin;
|
||||
if ((mLines != aLine) && (newY > aState.mBottomEdge)) {
|
||||
// Push this line and all of it's children and anything else that
|
||||
// follows to our next-in-flow
|
||||
|
@ -3089,18 +3130,18 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = cobm;
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
#if 0
|
||||
if (0 != topMargin) {
|
||||
// Apply collapsed top-margin value
|
||||
SlideFrames(aState.mPresContext, aState.mSpaceManager, aLine, topMargin);
|
||||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, topMargin,
|
||||
PR_TRUE);
|
||||
}
|
||||
#endif
|
||||
aState.mY = newY;
|
||||
|
||||
if (0 != aState.mCurrentBand.GetFloaterCount()) {
|
||||
|
@ -3135,6 +3176,8 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4170,12 +4213,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
mBlock->ReflowFloater(*this, aPlaceholder, metrics);
|
||||
|
||||
// Flush out pending bottom margin before placing floater
|
||||
if (0 != mPrevBottomMargin) {
|
||||
mY += mPrevBottomMargin;
|
||||
mPrevBottomMargin = 0;
|
||||
}
|
||||
|
||||
// Because we are in the middle of reflowing a placeholder frame
|
||||
// within a line (and possibly nested in an inline frame or two
|
||||
// that's a child of our block) we need to restore the space
|
||||
|
@ -4191,7 +4228,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
PlaceFloater(aPlaceholder, &isLeftFloater, &origin);
|
||||
|
||||
// Update the floater combined-area
|
||||
// XXX SlideFrames will muck this up!
|
||||
metrics.mCombinedArea.x += origin.x;
|
||||
metrics.mCombinedArea.y += origin.y;
|
||||
CombineRects(metrics.mCombinedArea, mFloaterCombinedArea);
|
||||
|
|
|
@ -54,9 +54,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
// XXX get rid of the need for this
|
||||
#define SLOW_INCREMENTAL_REFLOW
|
||||
|
||||
// If I can add in IsAPlaceHolder then we can remove the mFloaters
|
||||
// void array from the nsLineBox
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_FIRST_LINE
|
||||
#undef REALLY_NOISY_FIRST_LINE
|
||||
|
@ -68,6 +65,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#else
|
||||
#undef NOISY_FIRST_LINE
|
||||
|
@ -80,6 +78,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#endif
|
||||
|
||||
|
@ -230,10 +229,6 @@ public:
|
|||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
}
|
||||
|
||||
PRBool ShouldApplyTopMargin() const {
|
||||
return mIsMarginRoot || !IsAdjacentWithTop();
|
||||
}
|
||||
|
||||
const nsMargin& BorderPadding() const {
|
||||
return mReflowState.mComputedBorderPadding;
|
||||
}
|
||||
|
@ -290,14 +285,12 @@ public:
|
|||
|
||||
nsIFrame* mNextRCFrame;
|
||||
|
||||
// Is this frame a root for margin collapsing?
|
||||
PRBool mIsMarginRoot;
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRBool mIsTopMarginRoot;
|
||||
PRBool mIsBottomMarginRoot;
|
||||
|
||||
// The computed collapsed top margin value that the frame did not
|
||||
// apply but is passing out to the frames parent so that the parent
|
||||
// can perform generational margin collapsing. This value ends up
|
||||
// being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin.
|
||||
nscoord mCarriedOutTopMargin;
|
||||
// See ShouldApplyTopMargin
|
||||
PRBool mApplyTopMargin;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
|
@ -324,8 +317,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mBlock(aFrame),
|
||||
mPrevBottomMargin(0),
|
||||
mNextRCFrame(nsnull),
|
||||
mIsMarginRoot(PR_FALSE),
|
||||
mCarriedOutTopMargin(0)
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
|
@ -413,8 +407,11 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) {
|
||||
mIsMarginRoot = PR_TRUE;
|
||||
if (0 != borderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,10 +451,7 @@ nsBlockReflowState::GetAvailableSpace()
|
|||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0xa6cf90df, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
static const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
nsresult
|
||||
NS_NewBlockFrame(nsIFrame*& aNewFrame, PRUint32 aFlags)
|
||||
|
@ -691,6 +685,9 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const
|
|||
if (0 != mState) {
|
||||
fprintf(out, " [state=%08x]", mState);
|
||||
}
|
||||
if (0 != mFlags) {
|
||||
fprintf(out, " [flags=%x]", mFlags);
|
||||
}
|
||||
fputs("<\n", out);
|
||||
aIndent++;
|
||||
|
||||
|
@ -821,106 +818,6 @@ nsBlockFrame::IsPercentageBase(PRBool& aBase) const
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Reflow methods
|
||||
|
||||
#if 0
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext,
|
||||
const nsReflowState* aParentReflowState,
|
||||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult)
|
||||
{
|
||||
NS_PRECONDITION((nsnull != aTopMarginResult) &&
|
||||
(nsnull != aBottomMarginResult), "null ptr");
|
||||
if ((nsnull != aTopMarginResult) || (nsnull != aBottomMarginResult)) {
|
||||
nsMargin myMargin(0, 0, 0, 0);
|
||||
if (0 == (BLOCK_IS_INLINE & mFlags)) {
|
||||
nsHTMLReflowState::ComputeMarginFor(this, aParentReflowState, myMargin);
|
||||
}
|
||||
|
||||
// Find the first appropriate line (skipping over an empty line if
|
||||
// present) that contains a block that can be used for a
|
||||
// parent-child margin collapse.
|
||||
nsLineBox* firstLine = nsnull;
|
||||
nscoord firstLineTopMargin = 0;
|
||||
if (nsnull != aTopMarginResult) {
|
||||
nsLineBox* line = mLines;
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = line->mNext;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
firstLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the last appropriate line (skipping over an empty line)...
|
||||
nsLineBox* lastLine = nsnull;
|
||||
nscoord lastLineBottomMargin = 0;
|
||||
if (nsnull != aBottomMarginResult) {
|
||||
// Find the last line (line) and the previous to the last line
|
||||
// (prevLine)
|
||||
nsLineBox* line = mLines;
|
||||
nsLineBox* prevLine = nsnull;
|
||||
while (nsnull != line) {
|
||||
nsLineBox* next = line->mNext;
|
||||
if (nsnull == next) {
|
||||
break;
|
||||
}
|
||||
prevLine = line;
|
||||
line = next;
|
||||
}
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = prevLine;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
lastLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nsnull != firstLine) {
|
||||
if (lastLine == firstLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
else {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
nsnull);
|
||||
}
|
||||
firstLineTopMargin
|
||||
}
|
||||
else if (nsnull != lastLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
nsnull,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
|
||||
if ((nsnull != aTopMarginResult) && (nsnull != aBottomMarginResult)) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
else if (nsnull != aTopMarginResult) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
}
|
||||
else {
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
|
@ -933,7 +830,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsMarginRoot = PR_TRUE;
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (state.mIsTopMarginRoot) {
|
||||
state.mApplyTopMargin = PR_TRUE;
|
||||
}
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
|
@ -1009,11 +910,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d,%d\n",
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d\n",
|
||||
aReflowState.availableWidth, aReflowState.availableHeight,
|
||||
aReflowState.computedWidth, aReflowState.computedHeight,
|
||||
aMetrics.width, aMetrics.height,
|
||||
aMetrics.mCarriedOutTopMargin, aMetrics.mCarriedOutBottomMargin);
|
||||
aMetrics.mCarriedOutBottomMargin);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
@ -1048,7 +949,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.height = 0;
|
||||
aMetrics.ascent = 0;
|
||||
aMetrics.descent = 0;
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = 0;
|
||||
|
@ -1164,9 +1064,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsMarginRoot) {
|
||||
// When we are a margin root make sure that our last childs
|
||||
// bottom margin is fully applied.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
autoHeight += aState.mPrevBottomMargin;
|
||||
}
|
||||
|
@ -1203,15 +1103,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.maxElementSize->height = maxHeight;
|
||||
}
|
||||
|
||||
// Return top and bottom margin information
|
||||
if (aState.mIsMarginRoot) {
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aMetrics.mCarriedOutTopMargin = aState.mCarriedOutTopMargin;
|
||||
aMetrics.mCarriedOutBottomMargin = aState.mPrevBottomMargin;
|
||||
}
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
|
@ -1464,7 +1358,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
// Recover the natural (un-collapsed margins) for the child
|
||||
nsMargin childMargins(0, 0, 0, 0);
|
||||
//XXX nsMargin childMargins(0, 0, 0, 0);
|
||||
if (aLine->IsBlock()) {
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
const nsStyleSpacing* spacing;
|
||||
|
@ -1477,6 +1371,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
#endif
|
||||
}
|
||||
|
||||
aState.mPrevBottomMargin = 0;
|
||||
#if XXX_fix_me
|
||||
// Recompute running margin value (aState.mPrevBottomMargin). Also
|
||||
// recover the aState.carriedOutTopMargin, when appropriate.
|
||||
nscoord topMargin, bottomMargin;
|
||||
|
@ -1487,7 +1383,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin,
|
||||
topMargin, bottomMargin);
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
if (!aState.ShouldApplyTopMargin()) {
|
||||
if (!ShouldApplyTopMargin(aState, aLine)) {
|
||||
aState.mCarriedOutTopMargin = topMargin;
|
||||
}
|
||||
|
||||
|
@ -1497,6 +1393,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, aDeltaY,
|
||||
PR_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
aState.mY = aLine->mBounds.y;
|
||||
aState.PlaceCurrentLineFloaters(aLine->mFloaters);
|
||||
|
@ -2225,6 +2123,111 @@ nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (!aState.IsAdjacentWithTop()) {
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Determine if this line is "essentially" the first line
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
|
||||
// The line being reflowed is "essentially" the first line in the
|
||||
// block. Therefore its top-margin will be collapsed by the
|
||||
// generational collapsing logic with its parent (us).
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
nsIFrame* firstChild = mLines ? mLines->mFirstChild : nsnull;
|
||||
if (firstChild) {
|
||||
if (mLines->IsBlock()) {
|
||||
// Winner
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
// If the first line is not a block line then the second line must
|
||||
// be a block line otherwise the top child can't be a block.
|
||||
nsLineBox* next = mLines->mNext;
|
||||
if ((nsnull == next) || !next->IsBlock()) {
|
||||
// There is no line after the first line or its not a block so
|
||||
// don't bother trying to skip over the first line.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// The only time we can skip over the first line and pretend its
|
||||
// not there is if the line contains only compressed
|
||||
// whitespace. If white-space is significant to this frame then we
|
||||
// can't skip over the line.
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if (NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) {
|
||||
// Whitespace is significant
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// See if each frame is a text frame that contains nothing but
|
||||
// whitespace.
|
||||
PRInt32 n = mLines->mChildCount;
|
||||
while (--n >= 0) {
|
||||
nsIContent* content;
|
||||
nsresult rv = firstChild->GetContent(&content);
|
||||
if (NS_FAILED(rv) || (nsnull == content)) {
|
||||
return nsnull;
|
||||
}
|
||||
nsITextContent* tc;
|
||||
rv = content->QueryInterface(kITextContentIID, (void**) &tc);
|
||||
NS_RELEASE(content);
|
||||
if (NS_FAILED(rv) || (nsnull == tc)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
PRBool isws = PR_FALSE;
|
||||
tc->IsOnlyWhitespace(&isws);
|
||||
NS_RELEASE(tc);
|
||||
if (!isws) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
firstChild->GetNextSibling(&firstChild);
|
||||
}
|
||||
|
||||
// If we make it to this point then every frame on the first line
|
||||
// was compressible white-space. Since we already know that the
|
||||
// second line contains a block, that block is the
|
||||
// top-block-child.
|
||||
return next->mFirstChild;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2276,17 +2279,60 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
brc.SetCompactMarginWidth(compactMarginWidth);
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
// reflowed is a continuation (non-null prev-in-flow) then we don't
|
||||
// apply its top margin because its not significant. Otherwise, dig
|
||||
// deeper.
|
||||
PRBool applyTopMargin = PR_FALSE;
|
||||
nsIFrame* framePrevInFlow;
|
||||
frame->GetPrevInFlow(&framePrevInFlow);
|
||||
if (nsnull == framePrevInFlow) {
|
||||
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
|
||||
}
|
||||
|
||||
// Clear floaters before the block if the clear style is not none
|
||||
aLine->mBreakType = display->mBreakType;
|
||||
if (NS_STYLE_CLEAR_NONE != display->mBreakType) {
|
||||
nscoord saveY, deltaY;
|
||||
switch (display->mBreakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
||||
aState.ClearFloaters(aState.mY, display->mBreakType);
|
||||
// XXX: ?If we just advanced Y then we need to factor that amount
|
||||
// into the next margin calculation and reduce the amount of Y
|
||||
// margin applied by the amount just moved.
|
||||
// Apply the previous margin before clearing
|
||||
saveY = aState.mY + aState.mPrevBottomMargin;
|
||||
aState.ClearFloaters(saveY, display->mBreakType);
|
||||
|
||||
// Determine how far we just moved. If we didn't move then there
|
||||
// was nothing to clear to don't mess with the normal margin
|
||||
// collapsing behavior. In either case we need to restore the Y
|
||||
// coordinate to what it was before the clear.
|
||||
deltaY = aState.mY - saveY;
|
||||
if (0 != deltaY) {
|
||||
// Pretend that the distance we just moved is a previous
|
||||
// blocks bottom margin. Note that GetAvailableSpace has been
|
||||
// done so that the available space calculations will be done
|
||||
// after clearing the appropriate floaters.
|
||||
//
|
||||
// What we are doing here is applying CSS2 section 9.5.2's
|
||||
// rules for clearing - "The top margin of the generated box
|
||||
// is increased enough that the top border edge is below the
|
||||
// bottom outer edge of the floating boxes..."
|
||||
//
|
||||
// What this will do is cause the top-margin of the block
|
||||
// frame we are about to reflow to be collapsed with that
|
||||
// distance.
|
||||
aState.mPrevBottomMargin = deltaY;
|
||||
aState.mY = saveY;
|
||||
|
||||
// Force margin to be applied in this circumstance
|
||||
applyTopMargin = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Put aState.mY back to its original value since no clearing
|
||||
// happened. That way the previous blocks bottom margin will
|
||||
// be applied properly.
|
||||
aState.mY = saveY - aState.mPrevBottomMargin;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2331,29 +2377,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
WillReflowFrame(aState, aLine, frame);
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsMargin computedOffsets;
|
||||
PRBool applyTopMargin = aState.ShouldApplyTopMargin();
|
||||
if (!applyTopMargin) {
|
||||
// XXX clarify the IsAdjacentWithTop
|
||||
|
||||
// XXX rationalize this with the box model....
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
rv = brc.ReflowBlock(frame, availSpace,
|
||||
#ifdef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin, aState.mPrevBottomMargin,
|
||||
#endif
|
||||
aState.IsAdjacentWithTop(),
|
||||
rv = brc.ReflowBlock(frame, availSpace, applyTopMargin,
|
||||
aState.mPrevBottomMargin, aState.IsAdjacentWithTop(),
|
||||
computedOffsets, frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -2375,21 +2400,13 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
|
||||
// Try to place the child block
|
||||
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop,
|
||||
#ifndef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin,
|
||||
aState.mPrevBottomMargin,
|
||||
#endif
|
||||
computedOffsets,
|
||||
nscoord collapsedBottomMargin;
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, aLine->mCombinedArea);
|
||||
if (*aKeepReflowGoing) {
|
||||
// Some of the child block fit
|
||||
|
||||
// Set carry out top margin value when margin is not being applied
|
||||
if (!applyTopMargin) {
|
||||
aState.mCarriedOutTopMargin = brc.GetCollapsedTopMargin();
|
||||
}
|
||||
|
||||
// Advance to new Y position
|
||||
nscoord newY = aLine->mBounds.YMost();
|
||||
if (isCompactFrame) {
|
||||
|
@ -2406,7 +2423,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
aState.mY = newY;
|
||||
aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
//XXX aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
aLine->mCarriedOutBottomMargin = brc.GetCarriedOutBottomMargin();
|
||||
|
||||
// Continue the block frame now if it didn't completely fit in
|
||||
|
@ -2448,8 +2465,16 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aState.mPrevBottomMargin = brc.GetCollapsedBottomMargin();
|
||||
aState.mPrevBottomMargin = collapsedBottomMargin;
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
ListTag(stdout);
|
||||
printf(": frame=");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
|
||||
aLine->mCarriedOutBottomMargin, collapsedBottomMargin,
|
||||
aState.mPrevBottomMargin);
|
||||
#endif
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(brc.GetMaxElementSize());
|
||||
|
@ -2501,9 +2526,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Tall bullets won't look particularly nice here...
|
||||
nsRect bbox;
|
||||
mBullet->GetRect(bbox);
|
||||
nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent +
|
||||
topMargin;
|
||||
nscoord topMargin = applyTopMargin ? collapsedBottomMargin : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
}
|
||||
}
|
||||
|
@ -2553,8 +2577,10 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into.
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
|
@ -2568,7 +2594,8 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mCurrentBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight,
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
|
||||
|
@ -3023,11 +3050,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// Calculate the bottom margin for the line.
|
||||
nscoord lineBottomMargin = 0;
|
||||
if (0 == aLine->mBounds.height) {
|
||||
// XXX I don't think that this is necessary anymore because of the
|
||||
// way that min-line-height is applied in the vertical alignment
|
||||
// code; since we always have a line-height, a BR on its own line
|
||||
// will get at least the default line-height amount of vertical
|
||||
// space.
|
||||
nsIFrame* brFrame = lineLayout->GetBRFrame();
|
||||
if (nsnull != brFrame) {
|
||||
// If a line ends in a BR, and the line is empty of height, then
|
||||
|
@ -3051,6 +3073,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Calculate the lines top and bottom margin values. The margin will
|
||||
// come from an embedded block frame, not from inline
|
||||
// frames. Because this is an "inline" line, the child margins are
|
||||
|
@ -3068,14 +3091,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mCarriedOutTopMargin = topMargin;
|
||||
topMargin = 0;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
lineLayout = nsnull;
|
||||
//XXX aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = lineLayout->GetCarriedOutBottomMargin();
|
||||
#endif
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
// impacted by prior block margins. If this line ends up having some
|
||||
// height then we zero out the previous bottom margin value that was
|
||||
// already applied to the line's starting Y coordinate. Otherwise we
|
||||
// leave it be so that the previous blocks bottom margin can be
|
||||
// collapsed with a block that follows.
|
||||
nscoord newY;
|
||||
if (aLine->mBounds.height > 0) {
|
||||
// This line has some height. Therefore the application of the
|
||||
// previous-bottom-margin should stick.
|
||||
aState.mPrevBottomMargin = 0;
|
||||
newY = aLine->mBounds.YMost() + lineBottomMargin;
|
||||
}
|
||||
else {
|
||||
// Don't let the previous-bottom-margin value affect the newY
|
||||
// coordinate (it was applied in ReflowInlineFrames speculatively)
|
||||
// since the line is empty.
|
||||
newY = aState.mY - aState.mPrevBottomMargin + lineBottomMargin;
|
||||
}
|
||||
aLine->mCarriedOutBottomMargin = 0;/* XXX ib */
|
||||
|
||||
// See if the line fit. If it doesn't we need to push it. Our first
|
||||
// line will always fit.
|
||||
nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin;
|
||||
if ((mLines != aLine) && (newY > aState.mBottomEdge)) {
|
||||
// Push this line and all of it's children and anything else that
|
||||
// follows to our next-in-flow
|
||||
|
@ -3089,18 +3130,18 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = cobm;
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
#if 0
|
||||
if (0 != topMargin) {
|
||||
// Apply collapsed top-margin value
|
||||
SlideFrames(aState.mPresContext, aState.mSpaceManager, aLine, topMargin);
|
||||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, topMargin,
|
||||
PR_TRUE);
|
||||
}
|
||||
#endif
|
||||
aState.mY = newY;
|
||||
|
||||
if (0 != aState.mCurrentBand.GetFloaterCount()) {
|
||||
|
@ -3135,6 +3176,8 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4170,12 +4213,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
mBlock->ReflowFloater(*this, aPlaceholder, metrics);
|
||||
|
||||
// Flush out pending bottom margin before placing floater
|
||||
if (0 != mPrevBottomMargin) {
|
||||
mY += mPrevBottomMargin;
|
||||
mPrevBottomMargin = 0;
|
||||
}
|
||||
|
||||
// Because we are in the middle of reflowing a placeholder frame
|
||||
// within a line (and possibly nested in an inline frame or two
|
||||
// that's a child of our block) we need to restore the space
|
||||
|
@ -4191,7 +4228,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
PlaceFloater(aPlaceholder, &isLeftFloater, &origin);
|
||||
|
||||
// Update the floater combined-area
|
||||
// XXX SlideFrames will muck this up!
|
||||
metrics.mCombinedArea.x += origin.x;
|
||||
metrics.mCombinedArea.y += origin.y;
|
||||
CombineRects(metrics.mCombinedArea, mFloaterCombinedArea);
|
||||
|
|
|
@ -54,9 +54,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
// XXX get rid of the need for this
|
||||
#define SLOW_INCREMENTAL_REFLOW
|
||||
|
||||
// If I can add in IsAPlaceHolder then we can remove the mFloaters
|
||||
// void array from the nsLineBox
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_FIRST_LINE
|
||||
#undef REALLY_NOISY_FIRST_LINE
|
||||
|
@ -68,6 +65,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#else
|
||||
#undef NOISY_FIRST_LINE
|
||||
|
@ -80,6 +78,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#endif
|
||||
|
||||
|
@ -230,10 +229,6 @@ public:
|
|||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
}
|
||||
|
||||
PRBool ShouldApplyTopMargin() const {
|
||||
return mIsMarginRoot || !IsAdjacentWithTop();
|
||||
}
|
||||
|
||||
const nsMargin& BorderPadding() const {
|
||||
return mReflowState.mComputedBorderPadding;
|
||||
}
|
||||
|
@ -290,14 +285,12 @@ public:
|
|||
|
||||
nsIFrame* mNextRCFrame;
|
||||
|
||||
// Is this frame a root for margin collapsing?
|
||||
PRBool mIsMarginRoot;
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRBool mIsTopMarginRoot;
|
||||
PRBool mIsBottomMarginRoot;
|
||||
|
||||
// The computed collapsed top margin value that the frame did not
|
||||
// apply but is passing out to the frames parent so that the parent
|
||||
// can perform generational margin collapsing. This value ends up
|
||||
// being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin.
|
||||
nscoord mCarriedOutTopMargin;
|
||||
// See ShouldApplyTopMargin
|
||||
PRBool mApplyTopMargin;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
|
@ -324,8 +317,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mBlock(aFrame),
|
||||
mPrevBottomMargin(0),
|
||||
mNextRCFrame(nsnull),
|
||||
mIsMarginRoot(PR_FALSE),
|
||||
mCarriedOutTopMargin(0)
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
|
@ -413,8 +407,11 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) {
|
||||
mIsMarginRoot = PR_TRUE;
|
||||
if (0 != borderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,10 +451,7 @@ nsBlockReflowState::GetAvailableSpace()
|
|||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0xa6cf90df, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
static const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
nsresult
|
||||
NS_NewBlockFrame(nsIFrame*& aNewFrame, PRUint32 aFlags)
|
||||
|
@ -691,6 +685,9 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const
|
|||
if (0 != mState) {
|
||||
fprintf(out, " [state=%08x]", mState);
|
||||
}
|
||||
if (0 != mFlags) {
|
||||
fprintf(out, " [flags=%x]", mFlags);
|
||||
}
|
||||
fputs("<\n", out);
|
||||
aIndent++;
|
||||
|
||||
|
@ -821,106 +818,6 @@ nsBlockFrame::IsPercentageBase(PRBool& aBase) const
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Reflow methods
|
||||
|
||||
#if 0
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext,
|
||||
const nsReflowState* aParentReflowState,
|
||||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult)
|
||||
{
|
||||
NS_PRECONDITION((nsnull != aTopMarginResult) &&
|
||||
(nsnull != aBottomMarginResult), "null ptr");
|
||||
if ((nsnull != aTopMarginResult) || (nsnull != aBottomMarginResult)) {
|
||||
nsMargin myMargin(0, 0, 0, 0);
|
||||
if (0 == (BLOCK_IS_INLINE & mFlags)) {
|
||||
nsHTMLReflowState::ComputeMarginFor(this, aParentReflowState, myMargin);
|
||||
}
|
||||
|
||||
// Find the first appropriate line (skipping over an empty line if
|
||||
// present) that contains a block that can be used for a
|
||||
// parent-child margin collapse.
|
||||
nsLineBox* firstLine = nsnull;
|
||||
nscoord firstLineTopMargin = 0;
|
||||
if (nsnull != aTopMarginResult) {
|
||||
nsLineBox* line = mLines;
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = line->mNext;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
firstLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the last appropriate line (skipping over an empty line)...
|
||||
nsLineBox* lastLine = nsnull;
|
||||
nscoord lastLineBottomMargin = 0;
|
||||
if (nsnull != aBottomMarginResult) {
|
||||
// Find the last line (line) and the previous to the last line
|
||||
// (prevLine)
|
||||
nsLineBox* line = mLines;
|
||||
nsLineBox* prevLine = nsnull;
|
||||
while (nsnull != line) {
|
||||
nsLineBox* next = line->mNext;
|
||||
if (nsnull == next) {
|
||||
break;
|
||||
}
|
||||
prevLine = line;
|
||||
line = next;
|
||||
}
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = prevLine;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
lastLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nsnull != firstLine) {
|
||||
if (lastLine == firstLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
else {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
nsnull);
|
||||
}
|
||||
firstLineTopMargin
|
||||
}
|
||||
else if (nsnull != lastLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
nsnull,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
|
||||
if ((nsnull != aTopMarginResult) && (nsnull != aBottomMarginResult)) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
else if (nsnull != aTopMarginResult) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
}
|
||||
else {
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
|
@ -933,7 +830,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsMarginRoot = PR_TRUE;
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (state.mIsTopMarginRoot) {
|
||||
state.mApplyTopMargin = PR_TRUE;
|
||||
}
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
|
@ -1009,11 +910,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d,%d\n",
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d\n",
|
||||
aReflowState.availableWidth, aReflowState.availableHeight,
|
||||
aReflowState.computedWidth, aReflowState.computedHeight,
|
||||
aMetrics.width, aMetrics.height,
|
||||
aMetrics.mCarriedOutTopMargin, aMetrics.mCarriedOutBottomMargin);
|
||||
aMetrics.mCarriedOutBottomMargin);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
@ -1048,7 +949,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.height = 0;
|
||||
aMetrics.ascent = 0;
|
||||
aMetrics.descent = 0;
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = 0;
|
||||
|
@ -1164,9 +1064,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsMarginRoot) {
|
||||
// When we are a margin root make sure that our last childs
|
||||
// bottom margin is fully applied.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
autoHeight += aState.mPrevBottomMargin;
|
||||
}
|
||||
|
@ -1203,15 +1103,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.maxElementSize->height = maxHeight;
|
||||
}
|
||||
|
||||
// Return top and bottom margin information
|
||||
if (aState.mIsMarginRoot) {
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aMetrics.mCarriedOutTopMargin = aState.mCarriedOutTopMargin;
|
||||
aMetrics.mCarriedOutBottomMargin = aState.mPrevBottomMargin;
|
||||
}
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
|
@ -1464,7 +1358,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
// Recover the natural (un-collapsed margins) for the child
|
||||
nsMargin childMargins(0, 0, 0, 0);
|
||||
//XXX nsMargin childMargins(0, 0, 0, 0);
|
||||
if (aLine->IsBlock()) {
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
const nsStyleSpacing* spacing;
|
||||
|
@ -1477,6 +1371,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
#endif
|
||||
}
|
||||
|
||||
aState.mPrevBottomMargin = 0;
|
||||
#if XXX_fix_me
|
||||
// Recompute running margin value (aState.mPrevBottomMargin). Also
|
||||
// recover the aState.carriedOutTopMargin, when appropriate.
|
||||
nscoord topMargin, bottomMargin;
|
||||
|
@ -1487,7 +1383,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin,
|
||||
topMargin, bottomMargin);
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
if (!aState.ShouldApplyTopMargin()) {
|
||||
if (!ShouldApplyTopMargin(aState, aLine)) {
|
||||
aState.mCarriedOutTopMargin = topMargin;
|
||||
}
|
||||
|
||||
|
@ -1497,6 +1393,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, aDeltaY,
|
||||
PR_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
aState.mY = aLine->mBounds.y;
|
||||
aState.PlaceCurrentLineFloaters(aLine->mFloaters);
|
||||
|
@ -2225,6 +2123,111 @@ nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (!aState.IsAdjacentWithTop()) {
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Determine if this line is "essentially" the first line
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
|
||||
// The line being reflowed is "essentially" the first line in the
|
||||
// block. Therefore its top-margin will be collapsed by the
|
||||
// generational collapsing logic with its parent (us).
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
nsIFrame* firstChild = mLines ? mLines->mFirstChild : nsnull;
|
||||
if (firstChild) {
|
||||
if (mLines->IsBlock()) {
|
||||
// Winner
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
// If the first line is not a block line then the second line must
|
||||
// be a block line otherwise the top child can't be a block.
|
||||
nsLineBox* next = mLines->mNext;
|
||||
if ((nsnull == next) || !next->IsBlock()) {
|
||||
// There is no line after the first line or its not a block so
|
||||
// don't bother trying to skip over the first line.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// The only time we can skip over the first line and pretend its
|
||||
// not there is if the line contains only compressed
|
||||
// whitespace. If white-space is significant to this frame then we
|
||||
// can't skip over the line.
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if (NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) {
|
||||
// Whitespace is significant
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// See if each frame is a text frame that contains nothing but
|
||||
// whitespace.
|
||||
PRInt32 n = mLines->mChildCount;
|
||||
while (--n >= 0) {
|
||||
nsIContent* content;
|
||||
nsresult rv = firstChild->GetContent(&content);
|
||||
if (NS_FAILED(rv) || (nsnull == content)) {
|
||||
return nsnull;
|
||||
}
|
||||
nsITextContent* tc;
|
||||
rv = content->QueryInterface(kITextContentIID, (void**) &tc);
|
||||
NS_RELEASE(content);
|
||||
if (NS_FAILED(rv) || (nsnull == tc)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
PRBool isws = PR_FALSE;
|
||||
tc->IsOnlyWhitespace(&isws);
|
||||
NS_RELEASE(tc);
|
||||
if (!isws) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
firstChild->GetNextSibling(&firstChild);
|
||||
}
|
||||
|
||||
// If we make it to this point then every frame on the first line
|
||||
// was compressible white-space. Since we already know that the
|
||||
// second line contains a block, that block is the
|
||||
// top-block-child.
|
||||
return next->mFirstChild;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2276,17 +2279,60 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
brc.SetCompactMarginWidth(compactMarginWidth);
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
// reflowed is a continuation (non-null prev-in-flow) then we don't
|
||||
// apply its top margin because its not significant. Otherwise, dig
|
||||
// deeper.
|
||||
PRBool applyTopMargin = PR_FALSE;
|
||||
nsIFrame* framePrevInFlow;
|
||||
frame->GetPrevInFlow(&framePrevInFlow);
|
||||
if (nsnull == framePrevInFlow) {
|
||||
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
|
||||
}
|
||||
|
||||
// Clear floaters before the block if the clear style is not none
|
||||
aLine->mBreakType = display->mBreakType;
|
||||
if (NS_STYLE_CLEAR_NONE != display->mBreakType) {
|
||||
nscoord saveY, deltaY;
|
||||
switch (display->mBreakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
||||
aState.ClearFloaters(aState.mY, display->mBreakType);
|
||||
// XXX: ?If we just advanced Y then we need to factor that amount
|
||||
// into the next margin calculation and reduce the amount of Y
|
||||
// margin applied by the amount just moved.
|
||||
// Apply the previous margin before clearing
|
||||
saveY = aState.mY + aState.mPrevBottomMargin;
|
||||
aState.ClearFloaters(saveY, display->mBreakType);
|
||||
|
||||
// Determine how far we just moved. If we didn't move then there
|
||||
// was nothing to clear to don't mess with the normal margin
|
||||
// collapsing behavior. In either case we need to restore the Y
|
||||
// coordinate to what it was before the clear.
|
||||
deltaY = aState.mY - saveY;
|
||||
if (0 != deltaY) {
|
||||
// Pretend that the distance we just moved is a previous
|
||||
// blocks bottom margin. Note that GetAvailableSpace has been
|
||||
// done so that the available space calculations will be done
|
||||
// after clearing the appropriate floaters.
|
||||
//
|
||||
// What we are doing here is applying CSS2 section 9.5.2's
|
||||
// rules for clearing - "The top margin of the generated box
|
||||
// is increased enough that the top border edge is below the
|
||||
// bottom outer edge of the floating boxes..."
|
||||
//
|
||||
// What this will do is cause the top-margin of the block
|
||||
// frame we are about to reflow to be collapsed with that
|
||||
// distance.
|
||||
aState.mPrevBottomMargin = deltaY;
|
||||
aState.mY = saveY;
|
||||
|
||||
// Force margin to be applied in this circumstance
|
||||
applyTopMargin = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Put aState.mY back to its original value since no clearing
|
||||
// happened. That way the previous blocks bottom margin will
|
||||
// be applied properly.
|
||||
aState.mY = saveY - aState.mPrevBottomMargin;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2331,29 +2377,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
WillReflowFrame(aState, aLine, frame);
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsMargin computedOffsets;
|
||||
PRBool applyTopMargin = aState.ShouldApplyTopMargin();
|
||||
if (!applyTopMargin) {
|
||||
// XXX clarify the IsAdjacentWithTop
|
||||
|
||||
// XXX rationalize this with the box model....
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
rv = brc.ReflowBlock(frame, availSpace,
|
||||
#ifdef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin, aState.mPrevBottomMargin,
|
||||
#endif
|
||||
aState.IsAdjacentWithTop(),
|
||||
rv = brc.ReflowBlock(frame, availSpace, applyTopMargin,
|
||||
aState.mPrevBottomMargin, aState.IsAdjacentWithTop(),
|
||||
computedOffsets, frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -2375,21 +2400,13 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
|
||||
// Try to place the child block
|
||||
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop,
|
||||
#ifndef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin,
|
||||
aState.mPrevBottomMargin,
|
||||
#endif
|
||||
computedOffsets,
|
||||
nscoord collapsedBottomMargin;
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, aLine->mCombinedArea);
|
||||
if (*aKeepReflowGoing) {
|
||||
// Some of the child block fit
|
||||
|
||||
// Set carry out top margin value when margin is not being applied
|
||||
if (!applyTopMargin) {
|
||||
aState.mCarriedOutTopMargin = brc.GetCollapsedTopMargin();
|
||||
}
|
||||
|
||||
// Advance to new Y position
|
||||
nscoord newY = aLine->mBounds.YMost();
|
||||
if (isCompactFrame) {
|
||||
|
@ -2406,7 +2423,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
aState.mY = newY;
|
||||
aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
//XXX aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
aLine->mCarriedOutBottomMargin = brc.GetCarriedOutBottomMargin();
|
||||
|
||||
// Continue the block frame now if it didn't completely fit in
|
||||
|
@ -2448,8 +2465,16 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aState.mPrevBottomMargin = brc.GetCollapsedBottomMargin();
|
||||
aState.mPrevBottomMargin = collapsedBottomMargin;
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
ListTag(stdout);
|
||||
printf(": frame=");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
|
||||
aLine->mCarriedOutBottomMargin, collapsedBottomMargin,
|
||||
aState.mPrevBottomMargin);
|
||||
#endif
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(brc.GetMaxElementSize());
|
||||
|
@ -2501,9 +2526,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Tall bullets won't look particularly nice here...
|
||||
nsRect bbox;
|
||||
mBullet->GetRect(bbox);
|
||||
nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent +
|
||||
topMargin;
|
||||
nscoord topMargin = applyTopMargin ? collapsedBottomMargin : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
}
|
||||
}
|
||||
|
@ -2553,8 +2577,10 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into.
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
|
@ -2568,7 +2594,8 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mCurrentBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight,
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
|
||||
|
@ -3023,11 +3050,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// Calculate the bottom margin for the line.
|
||||
nscoord lineBottomMargin = 0;
|
||||
if (0 == aLine->mBounds.height) {
|
||||
// XXX I don't think that this is necessary anymore because of the
|
||||
// way that min-line-height is applied in the vertical alignment
|
||||
// code; since we always have a line-height, a BR on its own line
|
||||
// will get at least the default line-height amount of vertical
|
||||
// space.
|
||||
nsIFrame* brFrame = lineLayout->GetBRFrame();
|
||||
if (nsnull != brFrame) {
|
||||
// If a line ends in a BR, and the line is empty of height, then
|
||||
|
@ -3051,6 +3073,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Calculate the lines top and bottom margin values. The margin will
|
||||
// come from an embedded block frame, not from inline
|
||||
// frames. Because this is an "inline" line, the child margins are
|
||||
|
@ -3068,14 +3091,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mCarriedOutTopMargin = topMargin;
|
||||
topMargin = 0;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
lineLayout = nsnull;
|
||||
//XXX aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = lineLayout->GetCarriedOutBottomMargin();
|
||||
#endif
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
// impacted by prior block margins. If this line ends up having some
|
||||
// height then we zero out the previous bottom margin value that was
|
||||
// already applied to the line's starting Y coordinate. Otherwise we
|
||||
// leave it be so that the previous blocks bottom margin can be
|
||||
// collapsed with a block that follows.
|
||||
nscoord newY;
|
||||
if (aLine->mBounds.height > 0) {
|
||||
// This line has some height. Therefore the application of the
|
||||
// previous-bottom-margin should stick.
|
||||
aState.mPrevBottomMargin = 0;
|
||||
newY = aLine->mBounds.YMost() + lineBottomMargin;
|
||||
}
|
||||
else {
|
||||
// Don't let the previous-bottom-margin value affect the newY
|
||||
// coordinate (it was applied in ReflowInlineFrames speculatively)
|
||||
// since the line is empty.
|
||||
newY = aState.mY - aState.mPrevBottomMargin + lineBottomMargin;
|
||||
}
|
||||
aLine->mCarriedOutBottomMargin = 0;/* XXX ib */
|
||||
|
||||
// See if the line fit. If it doesn't we need to push it. Our first
|
||||
// line will always fit.
|
||||
nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin;
|
||||
if ((mLines != aLine) && (newY > aState.mBottomEdge)) {
|
||||
// Push this line and all of it's children and anything else that
|
||||
// follows to our next-in-flow
|
||||
|
@ -3089,18 +3130,18 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = cobm;
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
#if 0
|
||||
if (0 != topMargin) {
|
||||
// Apply collapsed top-margin value
|
||||
SlideFrames(aState.mPresContext, aState.mSpaceManager, aLine, topMargin);
|
||||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, topMargin,
|
||||
PR_TRUE);
|
||||
}
|
||||
#endif
|
||||
aState.mY = newY;
|
||||
|
||||
if (0 != aState.mCurrentBand.GetFloaterCount()) {
|
||||
|
@ -3135,6 +3176,8 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4170,12 +4213,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
mBlock->ReflowFloater(*this, aPlaceholder, metrics);
|
||||
|
||||
// Flush out pending bottom margin before placing floater
|
||||
if (0 != mPrevBottomMargin) {
|
||||
mY += mPrevBottomMargin;
|
||||
mPrevBottomMargin = 0;
|
||||
}
|
||||
|
||||
// Because we are in the middle of reflowing a placeholder frame
|
||||
// within a line (and possibly nested in an inline frame or two
|
||||
// that's a child of our block) we need to restore the space
|
||||
|
@ -4191,7 +4228,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
PlaceFloater(aPlaceholder, &isLeftFloater, &origin);
|
||||
|
||||
// Update the floater combined-area
|
||||
// XXX SlideFrames will muck this up!
|
||||
metrics.mCombinedArea.x += origin.x;
|
||||
metrics.mCombinedArea.y += origin.y;
|
||||
CombineRects(metrics.mCombinedArea, mFloaterCombinedArea);
|
||||
|
|
|
@ -54,9 +54,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
// XXX get rid of the need for this
|
||||
#define SLOW_INCREMENTAL_REFLOW
|
||||
|
||||
// If I can add in IsAPlaceHolder then we can remove the mFloaters
|
||||
// void array from the nsLineBox
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_FIRST_LINE
|
||||
#undef REALLY_NOISY_FIRST_LINE
|
||||
|
@ -68,6 +65,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#else
|
||||
#undef NOISY_FIRST_LINE
|
||||
|
@ -80,6 +78,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#endif
|
||||
|
||||
|
@ -230,10 +229,6 @@ public:
|
|||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
}
|
||||
|
||||
PRBool ShouldApplyTopMargin() const {
|
||||
return mIsMarginRoot || !IsAdjacentWithTop();
|
||||
}
|
||||
|
||||
const nsMargin& BorderPadding() const {
|
||||
return mReflowState.mComputedBorderPadding;
|
||||
}
|
||||
|
@ -290,14 +285,12 @@ public:
|
|||
|
||||
nsIFrame* mNextRCFrame;
|
||||
|
||||
// Is this frame a root for margin collapsing?
|
||||
PRBool mIsMarginRoot;
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRBool mIsTopMarginRoot;
|
||||
PRBool mIsBottomMarginRoot;
|
||||
|
||||
// The computed collapsed top margin value that the frame did not
|
||||
// apply but is passing out to the frames parent so that the parent
|
||||
// can perform generational margin collapsing. This value ends up
|
||||
// being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin.
|
||||
nscoord mCarriedOutTopMargin;
|
||||
// See ShouldApplyTopMargin
|
||||
PRBool mApplyTopMargin;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
|
@ -324,8 +317,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mBlock(aFrame),
|
||||
mPrevBottomMargin(0),
|
||||
mNextRCFrame(nsnull),
|
||||
mIsMarginRoot(PR_FALSE),
|
||||
mCarriedOutTopMargin(0)
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
|
@ -413,8 +407,11 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) {
|
||||
mIsMarginRoot = PR_TRUE;
|
||||
if (0 != borderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,10 +451,7 @@ nsBlockReflowState::GetAvailableSpace()
|
|||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0xa6cf90df, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
static const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
nsresult
|
||||
NS_NewBlockFrame(nsIFrame*& aNewFrame, PRUint32 aFlags)
|
||||
|
@ -691,6 +685,9 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const
|
|||
if (0 != mState) {
|
||||
fprintf(out, " [state=%08x]", mState);
|
||||
}
|
||||
if (0 != mFlags) {
|
||||
fprintf(out, " [flags=%x]", mFlags);
|
||||
}
|
||||
fputs("<\n", out);
|
||||
aIndent++;
|
||||
|
||||
|
@ -821,106 +818,6 @@ nsBlockFrame::IsPercentageBase(PRBool& aBase) const
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Reflow methods
|
||||
|
||||
#if 0
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext,
|
||||
const nsReflowState* aParentReflowState,
|
||||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult)
|
||||
{
|
||||
NS_PRECONDITION((nsnull != aTopMarginResult) &&
|
||||
(nsnull != aBottomMarginResult), "null ptr");
|
||||
if ((nsnull != aTopMarginResult) || (nsnull != aBottomMarginResult)) {
|
||||
nsMargin myMargin(0, 0, 0, 0);
|
||||
if (0 == (BLOCK_IS_INLINE & mFlags)) {
|
||||
nsHTMLReflowState::ComputeMarginFor(this, aParentReflowState, myMargin);
|
||||
}
|
||||
|
||||
// Find the first appropriate line (skipping over an empty line if
|
||||
// present) that contains a block that can be used for a
|
||||
// parent-child margin collapse.
|
||||
nsLineBox* firstLine = nsnull;
|
||||
nscoord firstLineTopMargin = 0;
|
||||
if (nsnull != aTopMarginResult) {
|
||||
nsLineBox* line = mLines;
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = line->mNext;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
firstLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the last appropriate line (skipping over an empty line)...
|
||||
nsLineBox* lastLine = nsnull;
|
||||
nscoord lastLineBottomMargin = 0;
|
||||
if (nsnull != aBottomMarginResult) {
|
||||
// Find the last line (line) and the previous to the last line
|
||||
// (prevLine)
|
||||
nsLineBox* line = mLines;
|
||||
nsLineBox* prevLine = nsnull;
|
||||
while (nsnull != line) {
|
||||
nsLineBox* next = line->mNext;
|
||||
if (nsnull == next) {
|
||||
break;
|
||||
}
|
||||
prevLine = line;
|
||||
line = next;
|
||||
}
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = prevLine;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
lastLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nsnull != firstLine) {
|
||||
if (lastLine == firstLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
else {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
nsnull);
|
||||
}
|
||||
firstLineTopMargin
|
||||
}
|
||||
else if (nsnull != lastLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
nsnull,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
|
||||
if ((nsnull != aTopMarginResult) && (nsnull != aBottomMarginResult)) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
else if (nsnull != aTopMarginResult) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
}
|
||||
else {
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
|
@ -933,7 +830,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsMarginRoot = PR_TRUE;
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (state.mIsTopMarginRoot) {
|
||||
state.mApplyTopMargin = PR_TRUE;
|
||||
}
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
|
@ -1009,11 +910,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d,%d\n",
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d\n",
|
||||
aReflowState.availableWidth, aReflowState.availableHeight,
|
||||
aReflowState.computedWidth, aReflowState.computedHeight,
|
||||
aMetrics.width, aMetrics.height,
|
||||
aMetrics.mCarriedOutTopMargin, aMetrics.mCarriedOutBottomMargin);
|
||||
aMetrics.mCarriedOutBottomMargin);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
@ -1048,7 +949,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.height = 0;
|
||||
aMetrics.ascent = 0;
|
||||
aMetrics.descent = 0;
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = 0;
|
||||
|
@ -1164,9 +1064,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsMarginRoot) {
|
||||
// When we are a margin root make sure that our last childs
|
||||
// bottom margin is fully applied.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
autoHeight += aState.mPrevBottomMargin;
|
||||
}
|
||||
|
@ -1203,15 +1103,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.maxElementSize->height = maxHeight;
|
||||
}
|
||||
|
||||
// Return top and bottom margin information
|
||||
if (aState.mIsMarginRoot) {
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aMetrics.mCarriedOutTopMargin = aState.mCarriedOutTopMargin;
|
||||
aMetrics.mCarriedOutBottomMargin = aState.mPrevBottomMargin;
|
||||
}
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
|
@ -1464,7 +1358,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
// Recover the natural (un-collapsed margins) for the child
|
||||
nsMargin childMargins(0, 0, 0, 0);
|
||||
//XXX nsMargin childMargins(0, 0, 0, 0);
|
||||
if (aLine->IsBlock()) {
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
const nsStyleSpacing* spacing;
|
||||
|
@ -1477,6 +1371,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
#endif
|
||||
}
|
||||
|
||||
aState.mPrevBottomMargin = 0;
|
||||
#if XXX_fix_me
|
||||
// Recompute running margin value (aState.mPrevBottomMargin). Also
|
||||
// recover the aState.carriedOutTopMargin, when appropriate.
|
||||
nscoord topMargin, bottomMargin;
|
||||
|
@ -1487,7 +1383,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin,
|
||||
topMargin, bottomMargin);
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
if (!aState.ShouldApplyTopMargin()) {
|
||||
if (!ShouldApplyTopMargin(aState, aLine)) {
|
||||
aState.mCarriedOutTopMargin = topMargin;
|
||||
}
|
||||
|
||||
|
@ -1497,6 +1393,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, aDeltaY,
|
||||
PR_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
aState.mY = aLine->mBounds.y;
|
||||
aState.PlaceCurrentLineFloaters(aLine->mFloaters);
|
||||
|
@ -2225,6 +2123,111 @@ nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (!aState.IsAdjacentWithTop()) {
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Determine if this line is "essentially" the first line
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
|
||||
// The line being reflowed is "essentially" the first line in the
|
||||
// block. Therefore its top-margin will be collapsed by the
|
||||
// generational collapsing logic with its parent (us).
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
nsIFrame* firstChild = mLines ? mLines->mFirstChild : nsnull;
|
||||
if (firstChild) {
|
||||
if (mLines->IsBlock()) {
|
||||
// Winner
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
// If the first line is not a block line then the second line must
|
||||
// be a block line otherwise the top child can't be a block.
|
||||
nsLineBox* next = mLines->mNext;
|
||||
if ((nsnull == next) || !next->IsBlock()) {
|
||||
// There is no line after the first line or its not a block so
|
||||
// don't bother trying to skip over the first line.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// The only time we can skip over the first line and pretend its
|
||||
// not there is if the line contains only compressed
|
||||
// whitespace. If white-space is significant to this frame then we
|
||||
// can't skip over the line.
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if (NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) {
|
||||
// Whitespace is significant
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// See if each frame is a text frame that contains nothing but
|
||||
// whitespace.
|
||||
PRInt32 n = mLines->mChildCount;
|
||||
while (--n >= 0) {
|
||||
nsIContent* content;
|
||||
nsresult rv = firstChild->GetContent(&content);
|
||||
if (NS_FAILED(rv) || (nsnull == content)) {
|
||||
return nsnull;
|
||||
}
|
||||
nsITextContent* tc;
|
||||
rv = content->QueryInterface(kITextContentIID, (void**) &tc);
|
||||
NS_RELEASE(content);
|
||||
if (NS_FAILED(rv) || (nsnull == tc)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
PRBool isws = PR_FALSE;
|
||||
tc->IsOnlyWhitespace(&isws);
|
||||
NS_RELEASE(tc);
|
||||
if (!isws) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
firstChild->GetNextSibling(&firstChild);
|
||||
}
|
||||
|
||||
// If we make it to this point then every frame on the first line
|
||||
// was compressible white-space. Since we already know that the
|
||||
// second line contains a block, that block is the
|
||||
// top-block-child.
|
||||
return next->mFirstChild;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2276,17 +2279,60 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
brc.SetCompactMarginWidth(compactMarginWidth);
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
// reflowed is a continuation (non-null prev-in-flow) then we don't
|
||||
// apply its top margin because its not significant. Otherwise, dig
|
||||
// deeper.
|
||||
PRBool applyTopMargin = PR_FALSE;
|
||||
nsIFrame* framePrevInFlow;
|
||||
frame->GetPrevInFlow(&framePrevInFlow);
|
||||
if (nsnull == framePrevInFlow) {
|
||||
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
|
||||
}
|
||||
|
||||
// Clear floaters before the block if the clear style is not none
|
||||
aLine->mBreakType = display->mBreakType;
|
||||
if (NS_STYLE_CLEAR_NONE != display->mBreakType) {
|
||||
nscoord saveY, deltaY;
|
||||
switch (display->mBreakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
||||
aState.ClearFloaters(aState.mY, display->mBreakType);
|
||||
// XXX: ?If we just advanced Y then we need to factor that amount
|
||||
// into the next margin calculation and reduce the amount of Y
|
||||
// margin applied by the amount just moved.
|
||||
// Apply the previous margin before clearing
|
||||
saveY = aState.mY + aState.mPrevBottomMargin;
|
||||
aState.ClearFloaters(saveY, display->mBreakType);
|
||||
|
||||
// Determine how far we just moved. If we didn't move then there
|
||||
// was nothing to clear to don't mess with the normal margin
|
||||
// collapsing behavior. In either case we need to restore the Y
|
||||
// coordinate to what it was before the clear.
|
||||
deltaY = aState.mY - saveY;
|
||||
if (0 != deltaY) {
|
||||
// Pretend that the distance we just moved is a previous
|
||||
// blocks bottom margin. Note that GetAvailableSpace has been
|
||||
// done so that the available space calculations will be done
|
||||
// after clearing the appropriate floaters.
|
||||
//
|
||||
// What we are doing here is applying CSS2 section 9.5.2's
|
||||
// rules for clearing - "The top margin of the generated box
|
||||
// is increased enough that the top border edge is below the
|
||||
// bottom outer edge of the floating boxes..."
|
||||
//
|
||||
// What this will do is cause the top-margin of the block
|
||||
// frame we are about to reflow to be collapsed with that
|
||||
// distance.
|
||||
aState.mPrevBottomMargin = deltaY;
|
||||
aState.mY = saveY;
|
||||
|
||||
// Force margin to be applied in this circumstance
|
||||
applyTopMargin = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Put aState.mY back to its original value since no clearing
|
||||
// happened. That way the previous blocks bottom margin will
|
||||
// be applied properly.
|
||||
aState.mY = saveY - aState.mPrevBottomMargin;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2331,29 +2377,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
WillReflowFrame(aState, aLine, frame);
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsMargin computedOffsets;
|
||||
PRBool applyTopMargin = aState.ShouldApplyTopMargin();
|
||||
if (!applyTopMargin) {
|
||||
// XXX clarify the IsAdjacentWithTop
|
||||
|
||||
// XXX rationalize this with the box model....
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
rv = brc.ReflowBlock(frame, availSpace,
|
||||
#ifdef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin, aState.mPrevBottomMargin,
|
||||
#endif
|
||||
aState.IsAdjacentWithTop(),
|
||||
rv = brc.ReflowBlock(frame, availSpace, applyTopMargin,
|
||||
aState.mPrevBottomMargin, aState.IsAdjacentWithTop(),
|
||||
computedOffsets, frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -2375,21 +2400,13 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
|
||||
// Try to place the child block
|
||||
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop,
|
||||
#ifndef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin,
|
||||
aState.mPrevBottomMargin,
|
||||
#endif
|
||||
computedOffsets,
|
||||
nscoord collapsedBottomMargin;
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, aLine->mCombinedArea);
|
||||
if (*aKeepReflowGoing) {
|
||||
// Some of the child block fit
|
||||
|
||||
// Set carry out top margin value when margin is not being applied
|
||||
if (!applyTopMargin) {
|
||||
aState.mCarriedOutTopMargin = brc.GetCollapsedTopMargin();
|
||||
}
|
||||
|
||||
// Advance to new Y position
|
||||
nscoord newY = aLine->mBounds.YMost();
|
||||
if (isCompactFrame) {
|
||||
|
@ -2406,7 +2423,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
aState.mY = newY;
|
||||
aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
//XXX aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
aLine->mCarriedOutBottomMargin = brc.GetCarriedOutBottomMargin();
|
||||
|
||||
// Continue the block frame now if it didn't completely fit in
|
||||
|
@ -2448,8 +2465,16 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aState.mPrevBottomMargin = brc.GetCollapsedBottomMargin();
|
||||
aState.mPrevBottomMargin = collapsedBottomMargin;
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
ListTag(stdout);
|
||||
printf(": frame=");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
|
||||
aLine->mCarriedOutBottomMargin, collapsedBottomMargin,
|
||||
aState.mPrevBottomMargin);
|
||||
#endif
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(brc.GetMaxElementSize());
|
||||
|
@ -2501,9 +2526,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Tall bullets won't look particularly nice here...
|
||||
nsRect bbox;
|
||||
mBullet->GetRect(bbox);
|
||||
nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent +
|
||||
topMargin;
|
||||
nscoord topMargin = applyTopMargin ? collapsedBottomMargin : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
}
|
||||
}
|
||||
|
@ -2553,8 +2577,10 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into.
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
|
@ -2568,7 +2594,8 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mCurrentBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight,
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
|
||||
|
@ -3023,11 +3050,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// Calculate the bottom margin for the line.
|
||||
nscoord lineBottomMargin = 0;
|
||||
if (0 == aLine->mBounds.height) {
|
||||
// XXX I don't think that this is necessary anymore because of the
|
||||
// way that min-line-height is applied in the vertical alignment
|
||||
// code; since we always have a line-height, a BR on its own line
|
||||
// will get at least the default line-height amount of vertical
|
||||
// space.
|
||||
nsIFrame* brFrame = lineLayout->GetBRFrame();
|
||||
if (nsnull != brFrame) {
|
||||
// If a line ends in a BR, and the line is empty of height, then
|
||||
|
@ -3051,6 +3073,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Calculate the lines top and bottom margin values. The margin will
|
||||
// come from an embedded block frame, not from inline
|
||||
// frames. Because this is an "inline" line, the child margins are
|
||||
|
@ -3068,14 +3091,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mCarriedOutTopMargin = topMargin;
|
||||
topMargin = 0;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
lineLayout = nsnull;
|
||||
//XXX aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = lineLayout->GetCarriedOutBottomMargin();
|
||||
#endif
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
// impacted by prior block margins. If this line ends up having some
|
||||
// height then we zero out the previous bottom margin value that was
|
||||
// already applied to the line's starting Y coordinate. Otherwise we
|
||||
// leave it be so that the previous blocks bottom margin can be
|
||||
// collapsed with a block that follows.
|
||||
nscoord newY;
|
||||
if (aLine->mBounds.height > 0) {
|
||||
// This line has some height. Therefore the application of the
|
||||
// previous-bottom-margin should stick.
|
||||
aState.mPrevBottomMargin = 0;
|
||||
newY = aLine->mBounds.YMost() + lineBottomMargin;
|
||||
}
|
||||
else {
|
||||
// Don't let the previous-bottom-margin value affect the newY
|
||||
// coordinate (it was applied in ReflowInlineFrames speculatively)
|
||||
// since the line is empty.
|
||||
newY = aState.mY - aState.mPrevBottomMargin + lineBottomMargin;
|
||||
}
|
||||
aLine->mCarriedOutBottomMargin = 0;/* XXX ib */
|
||||
|
||||
// See if the line fit. If it doesn't we need to push it. Our first
|
||||
// line will always fit.
|
||||
nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin;
|
||||
if ((mLines != aLine) && (newY > aState.mBottomEdge)) {
|
||||
// Push this line and all of it's children and anything else that
|
||||
// follows to our next-in-flow
|
||||
|
@ -3089,18 +3130,18 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = cobm;
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
#if 0
|
||||
if (0 != topMargin) {
|
||||
// Apply collapsed top-margin value
|
||||
SlideFrames(aState.mPresContext, aState.mSpaceManager, aLine, topMargin);
|
||||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, topMargin,
|
||||
PR_TRUE);
|
||||
}
|
||||
#endif
|
||||
aState.mY = newY;
|
||||
|
||||
if (0 != aState.mCurrentBand.GetFloaterCount()) {
|
||||
|
@ -3135,6 +3176,8 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4170,12 +4213,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
mBlock->ReflowFloater(*this, aPlaceholder, metrics);
|
||||
|
||||
// Flush out pending bottom margin before placing floater
|
||||
if (0 != mPrevBottomMargin) {
|
||||
mY += mPrevBottomMargin;
|
||||
mPrevBottomMargin = 0;
|
||||
}
|
||||
|
||||
// Because we are in the middle of reflowing a placeholder frame
|
||||
// within a line (and possibly nested in an inline frame or two
|
||||
// that's a child of our block) we need to restore the space
|
||||
|
@ -4191,7 +4228,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
PlaceFloater(aPlaceholder, &isLeftFloater, &origin);
|
||||
|
||||
// Update the floater combined-area
|
||||
// XXX SlideFrames will muck this up!
|
||||
metrics.mCombinedArea.x += origin.x;
|
||||
metrics.mCombinedArea.y += origin.y;
|
||||
CombineRects(metrics.mCombinedArea, mFloaterCombinedArea);
|
||||
|
|
|
@ -54,9 +54,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
// XXX get rid of the need for this
|
||||
#define SLOW_INCREMENTAL_REFLOW
|
||||
|
||||
// If I can add in IsAPlaceHolder then we can remove the mFloaters
|
||||
// void array from the nsLineBox
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_FIRST_LINE
|
||||
#undef REALLY_NOISY_FIRST_LINE
|
||||
|
@ -68,6 +65,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#else
|
||||
#undef NOISY_FIRST_LINE
|
||||
|
@ -80,6 +78,7 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */
|
|||
#undef NOISY_REMOVE_FRAME
|
||||
#undef NOISY_DAMAGE_REPAIR
|
||||
#undef NOISY_COMBINED_AREA
|
||||
#undef NOISY_VERTICAL_MARGINS
|
||||
#undef REFLOW_STATUS_COVERAGE
|
||||
#endif
|
||||
|
||||
|
@ -230,10 +229,6 @@ public:
|
|||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
}
|
||||
|
||||
PRBool ShouldApplyTopMargin() const {
|
||||
return mIsMarginRoot || !IsAdjacentWithTop();
|
||||
}
|
||||
|
||||
const nsMargin& BorderPadding() const {
|
||||
return mReflowState.mComputedBorderPadding;
|
||||
}
|
||||
|
@ -290,14 +285,12 @@ public:
|
|||
|
||||
nsIFrame* mNextRCFrame;
|
||||
|
||||
// Is this frame a root for margin collapsing?
|
||||
PRBool mIsMarginRoot;
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRBool mIsTopMarginRoot;
|
||||
PRBool mIsBottomMarginRoot;
|
||||
|
||||
// The computed collapsed top margin value that the frame did not
|
||||
// apply but is passing out to the frames parent so that the parent
|
||||
// can perform generational margin collapsing. This value ends up
|
||||
// being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin.
|
||||
nscoord mCarriedOutTopMargin;
|
||||
// See ShouldApplyTopMargin
|
||||
PRBool mApplyTopMargin;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
|
@ -324,8 +317,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mBlock(aFrame),
|
||||
mPrevBottomMargin(0),
|
||||
mNextRCFrame(nsnull),
|
||||
mIsMarginRoot(PR_FALSE),
|
||||
mCarriedOutTopMargin(0)
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
|
@ -413,8 +407,11 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) {
|
||||
mIsMarginRoot = PR_TRUE;
|
||||
if (0 != borderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,10 +451,7 @@ nsBlockReflowState::GetAvailableSpace()
|
|||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0xa6cf90df, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
static const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
nsresult
|
||||
NS_NewBlockFrame(nsIFrame*& aNewFrame, PRUint32 aFlags)
|
||||
|
@ -691,6 +685,9 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const
|
|||
if (0 != mState) {
|
||||
fprintf(out, " [state=%08x]", mState);
|
||||
}
|
||||
if (0 != mFlags) {
|
||||
fprintf(out, " [flags=%x]", mFlags);
|
||||
}
|
||||
fputs("<\n", out);
|
||||
aIndent++;
|
||||
|
||||
|
@ -821,106 +818,6 @@ nsBlockFrame::IsPercentageBase(PRBool& aBase) const
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// Reflow methods
|
||||
|
||||
#if 0
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext,
|
||||
const nsReflowState* aParentReflowState,
|
||||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult)
|
||||
{
|
||||
NS_PRECONDITION((nsnull != aTopMarginResult) &&
|
||||
(nsnull != aBottomMarginResult), "null ptr");
|
||||
if ((nsnull != aTopMarginResult) || (nsnull != aBottomMarginResult)) {
|
||||
nsMargin myMargin(0, 0, 0, 0);
|
||||
if (0 == (BLOCK_IS_INLINE & mFlags)) {
|
||||
nsHTMLReflowState::ComputeMarginFor(this, aParentReflowState, myMargin);
|
||||
}
|
||||
|
||||
// Find the first appropriate line (skipping over an empty line if
|
||||
// present) that contains a block that can be used for a
|
||||
// parent-child margin collapse.
|
||||
nsLineBox* firstLine = nsnull;
|
||||
nscoord firstLineTopMargin = 0;
|
||||
if (nsnull != aTopMarginResult) {
|
||||
nsLineBox* line = mLines;
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = line->mNext;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
firstLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the last appropriate line (skipping over an empty line)...
|
||||
nsLineBox* lastLine = nsnull;
|
||||
nscoord lastLineBottomMargin = 0;
|
||||
if (nsnull != aBottomMarginResult) {
|
||||
// Find the last line (line) and the previous to the last line
|
||||
// (prevLine)
|
||||
nsLineBox* line = mLines;
|
||||
nsLineBox* prevLine = nsnull;
|
||||
while (nsnull != line) {
|
||||
nsLineBox* next = line->mNext;
|
||||
if (nsnull == next) {
|
||||
break;
|
||||
}
|
||||
prevLine = line;
|
||||
line = next;
|
||||
}
|
||||
if (nsnull != line) {
|
||||
if (line->IsEmptyLine()) {
|
||||
line = prevLine;
|
||||
}
|
||||
if ((nsnull != line) && line->IsBlock()) {
|
||||
lastLine = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nsnull != firstLine) {
|
||||
if (lastLine == firstLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
else {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
&firstLineTopMargin,
|
||||
nsnull);
|
||||
}
|
||||
firstLineTopMargin
|
||||
}
|
||||
else if (nsnull != lastLine) {
|
||||
ComputeCollapsedMargins(aPresContext, nsnull,
|
||||
nsnull,
|
||||
&lastLineBottomMargin);
|
||||
}
|
||||
|
||||
if ((nsnull != aTopMarginResult) && (nsnull != aBottomMarginResult)) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
else if (nsnull != aTopMarginResult) {
|
||||
nscoord topMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.top, firstLineTopMargin);
|
||||
*aTopMarginResult = topMargin;
|
||||
}
|
||||
else {
|
||||
nscoord bottomMargin =
|
||||
nsBlockReflowContext::MaxMargin(myMargin.bottom, lastLineBottomMargin);
|
||||
*aBottomMarginResult = bottomMargin;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
|
@ -933,7 +830,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsMarginRoot = PR_TRUE;
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
if (state.mIsTopMarginRoot) {
|
||||
state.mApplyTopMargin = PR_TRUE;
|
||||
}
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
|
@ -1009,11 +910,11 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d,%d\n",
|
||||
printf(": availSize=%d,%d computed=%d,%d metrics=%d,%d carriedMargin=%d\n",
|
||||
aReflowState.availableWidth, aReflowState.availableHeight,
|
||||
aReflowState.computedWidth, aReflowState.computedHeight,
|
||||
aMetrics.width, aMetrics.height,
|
||||
aMetrics.mCarriedOutTopMargin, aMetrics.mCarriedOutBottomMargin);
|
||||
aMetrics.mCarriedOutBottomMargin);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
@ -1048,7 +949,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.height = 0;
|
||||
aMetrics.ascent = 0;
|
||||
aMetrics.descent = 0;
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = 0;
|
||||
|
@ -1164,9 +1064,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsMarginRoot) {
|
||||
// When we are a margin root make sure that our last childs
|
||||
// bottom margin is fully applied.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
autoHeight += aState.mPrevBottomMargin;
|
||||
}
|
||||
|
@ -1203,15 +1103,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
aMetrics.maxElementSize->height = maxHeight;
|
||||
}
|
||||
|
||||
// Return top and bottom margin information
|
||||
if (aState.mIsMarginRoot) {
|
||||
aMetrics.mCarriedOutTopMargin = 0;
|
||||
aMetrics.mCarriedOutBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aMetrics.mCarriedOutTopMargin = aState.mCarriedOutTopMargin;
|
||||
aMetrics.mCarriedOutBottomMargin = aState.mPrevBottomMargin;
|
||||
}
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
|
@ -1464,7 +1358,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
// Recover the natural (un-collapsed margins) for the child
|
||||
nsMargin childMargins(0, 0, 0, 0);
|
||||
//XXX nsMargin childMargins(0, 0, 0, 0);
|
||||
if (aLine->IsBlock()) {
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
const nsStyleSpacing* spacing;
|
||||
|
@ -1477,6 +1371,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
#endif
|
||||
}
|
||||
|
||||
aState.mPrevBottomMargin = 0;
|
||||
#if XXX_fix_me
|
||||
// Recompute running margin value (aState.mPrevBottomMargin). Also
|
||||
// recover the aState.carriedOutTopMargin, when appropriate.
|
||||
nscoord topMargin, bottomMargin;
|
||||
|
@ -1487,7 +1383,7 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin,
|
||||
topMargin, bottomMargin);
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
if (!aState.ShouldApplyTopMargin()) {
|
||||
if (!ShouldApplyTopMargin(aState, aLine)) {
|
||||
aState.mCarriedOutTopMargin = topMargin;
|
||||
}
|
||||
|
||||
|
@ -1497,6 +1393,8 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
|||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, aDeltaY,
|
||||
PR_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
aState.mY = aLine->mBounds.y;
|
||||
aState.PlaceCurrentLineFloaters(aLine->mFloaters);
|
||||
|
@ -2225,6 +2123,111 @@ nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (!aState.IsAdjacentWithTop()) {
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Determine if this line is "essentially" the first line
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
|
||||
// The line being reflowed is "essentially" the first line in the
|
||||
// block. Therefore its top-margin will be collapsed by the
|
||||
// generational collapsing logic with its parent (us).
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
nsIFrame* firstChild = mLines ? mLines->mFirstChild : nsnull;
|
||||
if (firstChild) {
|
||||
if (mLines->IsBlock()) {
|
||||
// Winner
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
// If the first line is not a block line then the second line must
|
||||
// be a block line otherwise the top child can't be a block.
|
||||
nsLineBox* next = mLines->mNext;
|
||||
if ((nsnull == next) || !next->IsBlock()) {
|
||||
// There is no line after the first line or its not a block so
|
||||
// don't bother trying to skip over the first line.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// The only time we can skip over the first line and pretend its
|
||||
// not there is if the line contains only compressed
|
||||
// whitespace. If white-space is significant to this frame then we
|
||||
// can't skip over the line.
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if (NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) {
|
||||
// Whitespace is significant
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// See if each frame is a text frame that contains nothing but
|
||||
// whitespace.
|
||||
PRInt32 n = mLines->mChildCount;
|
||||
while (--n >= 0) {
|
||||
nsIContent* content;
|
||||
nsresult rv = firstChild->GetContent(&content);
|
||||
if (NS_FAILED(rv) || (nsnull == content)) {
|
||||
return nsnull;
|
||||
}
|
||||
nsITextContent* tc;
|
||||
rv = content->QueryInterface(kITextContentIID, (void**) &tc);
|
||||
NS_RELEASE(content);
|
||||
if (NS_FAILED(rv) || (nsnull == tc)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
PRBool isws = PR_FALSE;
|
||||
tc->IsOnlyWhitespace(&isws);
|
||||
NS_RELEASE(tc);
|
||||
if (!isws) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
firstChild->GetNextSibling(&firstChild);
|
||||
}
|
||||
|
||||
// If we make it to this point then every frame on the first line
|
||||
// was compressible white-space. Since we already know that the
|
||||
// second line contains a block, that block is the
|
||||
// top-block-child.
|
||||
return next->mFirstChild;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2276,17 +2279,60 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
brc.SetCompactMarginWidth(compactMarginWidth);
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
// reflowed is a continuation (non-null prev-in-flow) then we don't
|
||||
// apply its top margin because its not significant. Otherwise, dig
|
||||
// deeper.
|
||||
PRBool applyTopMargin = PR_FALSE;
|
||||
nsIFrame* framePrevInFlow;
|
||||
frame->GetPrevInFlow(&framePrevInFlow);
|
||||
if (nsnull == framePrevInFlow) {
|
||||
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
|
||||
}
|
||||
|
||||
// Clear floaters before the block if the clear style is not none
|
||||
aLine->mBreakType = display->mBreakType;
|
||||
if (NS_STYLE_CLEAR_NONE != display->mBreakType) {
|
||||
nscoord saveY, deltaY;
|
||||
switch (display->mBreakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
||||
aState.ClearFloaters(aState.mY, display->mBreakType);
|
||||
// XXX: ?If we just advanced Y then we need to factor that amount
|
||||
// into the next margin calculation and reduce the amount of Y
|
||||
// margin applied by the amount just moved.
|
||||
// Apply the previous margin before clearing
|
||||
saveY = aState.mY + aState.mPrevBottomMargin;
|
||||
aState.ClearFloaters(saveY, display->mBreakType);
|
||||
|
||||
// Determine how far we just moved. If we didn't move then there
|
||||
// was nothing to clear to don't mess with the normal margin
|
||||
// collapsing behavior. In either case we need to restore the Y
|
||||
// coordinate to what it was before the clear.
|
||||
deltaY = aState.mY - saveY;
|
||||
if (0 != deltaY) {
|
||||
// Pretend that the distance we just moved is a previous
|
||||
// blocks bottom margin. Note that GetAvailableSpace has been
|
||||
// done so that the available space calculations will be done
|
||||
// after clearing the appropriate floaters.
|
||||
//
|
||||
// What we are doing here is applying CSS2 section 9.5.2's
|
||||
// rules for clearing - "The top margin of the generated box
|
||||
// is increased enough that the top border edge is below the
|
||||
// bottom outer edge of the floating boxes..."
|
||||
//
|
||||
// What this will do is cause the top-margin of the block
|
||||
// frame we are about to reflow to be collapsed with that
|
||||
// distance.
|
||||
aState.mPrevBottomMargin = deltaY;
|
||||
aState.mY = saveY;
|
||||
|
||||
// Force margin to be applied in this circumstance
|
||||
applyTopMargin = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Put aState.mY back to its original value since no clearing
|
||||
// happened. That way the previous blocks bottom margin will
|
||||
// be applied properly.
|
||||
aState.mY = saveY - aState.mPrevBottomMargin;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2331,29 +2377,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
WillReflowFrame(aState, aLine, frame);
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsMargin computedOffsets;
|
||||
PRBool applyTopMargin = aState.ShouldApplyTopMargin();
|
||||
if (!applyTopMargin) {
|
||||
// XXX clarify the IsAdjacentWithTop
|
||||
|
||||
// XXX rationalize this with the box model....
|
||||
nsLineBox* line = mLines;
|
||||
while (line != aLine) {
|
||||
if ((nsnull != line->mFloaters) && (0 != line->mFloaters->Count())) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
if (line->IsBlock()) {
|
||||
applyTopMargin = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
rv = brc.ReflowBlock(frame, availSpace,
|
||||
#ifdef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin, aState.mPrevBottomMargin,
|
||||
#endif
|
||||
aState.IsAdjacentWithTop(),
|
||||
rv = brc.ReflowBlock(frame, availSpace, applyTopMargin,
|
||||
aState.mPrevBottomMargin, aState.IsAdjacentWithTop(),
|
||||
computedOffsets, frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -2375,21 +2400,13 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
|
||||
// Try to place the child block
|
||||
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop,
|
||||
#ifndef SPECULATIVE_TOP_MARGIN
|
||||
applyTopMargin,
|
||||
aState.mPrevBottomMargin,
|
||||
#endif
|
||||
computedOffsets,
|
||||
nscoord collapsedBottomMargin;
|
||||
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, aLine->mCombinedArea);
|
||||
if (*aKeepReflowGoing) {
|
||||
// Some of the child block fit
|
||||
|
||||
// Set carry out top margin value when margin is not being applied
|
||||
if (!applyTopMargin) {
|
||||
aState.mCarriedOutTopMargin = brc.GetCollapsedTopMargin();
|
||||
}
|
||||
|
||||
// Advance to new Y position
|
||||
nscoord newY = aLine->mBounds.YMost();
|
||||
if (isCompactFrame) {
|
||||
|
@ -2406,7 +2423,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
aState.mY = newY;
|
||||
aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
//XXX aLine->mCarriedOutTopMargin = brc.GetCarriedOutTopMargin();
|
||||
aLine->mCarriedOutBottomMargin = brc.GetCarriedOutBottomMargin();
|
||||
|
||||
// Continue the block frame now if it didn't completely fit in
|
||||
|
@ -2448,8 +2465,16 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
else {
|
||||
aState.mPrevBottomMargin = brc.GetCollapsedBottomMargin();
|
||||
aState.mPrevBottomMargin = collapsedBottomMargin;
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
ListTag(stdout);
|
||||
printf(": frame=");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
|
||||
aLine->mCarriedOutBottomMargin, collapsedBottomMargin,
|
||||
aState.mPrevBottomMargin);
|
||||
#endif
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(brc.GetMaxElementSize());
|
||||
|
@ -2501,9 +2526,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Tall bullets won't look particularly nice here...
|
||||
nsRect bbox;
|
||||
mBullet->GetRect(bbox);
|
||||
nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent +
|
||||
topMargin;
|
||||
nscoord topMargin = applyTopMargin ? collapsedBottomMargin : 0;
|
||||
bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
}
|
||||
}
|
||||
|
@ -2553,8 +2577,10 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into.
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
|
@ -2568,7 +2594,8 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mCurrentBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight,
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
|
||||
|
@ -3023,11 +3050,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// Calculate the bottom margin for the line.
|
||||
nscoord lineBottomMargin = 0;
|
||||
if (0 == aLine->mBounds.height) {
|
||||
// XXX I don't think that this is necessary anymore because of the
|
||||
// way that min-line-height is applied in the vertical alignment
|
||||
// code; since we always have a line-height, a BR on its own line
|
||||
// will get at least the default line-height amount of vertical
|
||||
// space.
|
||||
nsIFrame* brFrame = lineLayout->GetBRFrame();
|
||||
if (nsnull != brFrame) {
|
||||
// If a line ends in a BR, and the line is empty of height, then
|
||||
|
@ -3051,6 +3073,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Calculate the lines top and bottom margin values. The margin will
|
||||
// come from an embedded block frame, not from inline
|
||||
// frames. Because this is an "inline" line, the child margins are
|
||||
|
@ -3068,14 +3091,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mCarriedOutTopMargin = topMargin;
|
||||
topMargin = 0;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
lineLayout = nsnull;
|
||||
//XXX aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = lineLayout->GetCarriedOutBottomMargin();
|
||||
#endif
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
// impacted by prior block margins. If this line ends up having some
|
||||
// height then we zero out the previous bottom margin value that was
|
||||
// already applied to the line's starting Y coordinate. Otherwise we
|
||||
// leave it be so that the previous blocks bottom margin can be
|
||||
// collapsed with a block that follows.
|
||||
nscoord newY;
|
||||
if (aLine->mBounds.height > 0) {
|
||||
// This line has some height. Therefore the application of the
|
||||
// previous-bottom-margin should stick.
|
||||
aState.mPrevBottomMargin = 0;
|
||||
newY = aLine->mBounds.YMost() + lineBottomMargin;
|
||||
}
|
||||
else {
|
||||
// Don't let the previous-bottom-margin value affect the newY
|
||||
// coordinate (it was applied in ReflowInlineFrames speculatively)
|
||||
// since the line is empty.
|
||||
newY = aState.mY - aState.mPrevBottomMargin + lineBottomMargin;
|
||||
}
|
||||
aLine->mCarriedOutBottomMargin = 0;/* XXX ib */
|
||||
|
||||
// See if the line fit. If it doesn't we need to push it. Our first
|
||||
// line will always fit.
|
||||
nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin;
|
||||
if ((mLines != aLine) && (newY > aState.mBottomEdge)) {
|
||||
// Push this line and all of it's children and anything else that
|
||||
// follows to our next-in-flow
|
||||
|
@ -3089,18 +3130,18 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
aLine->mCarriedOutTopMargin = cotm;
|
||||
aLine->mCarriedOutBottomMargin = cobm;
|
||||
aState.mPrevBottomMargin = bottomMargin;
|
||||
#if 0
|
||||
if (0 != topMargin) {
|
||||
// Apply collapsed top-margin value
|
||||
SlideFrames(aState.mPresContext, aState.mSpaceManager, aLine, topMargin);
|
||||
SlideFloaters(aState.mPresContext, aState.mSpaceManager, aLine, topMargin,
|
||||
PR_TRUE);
|
||||
}
|
||||
#endif
|
||||
aState.mY = newY;
|
||||
|
||||
if (0 != aState.mCurrentBand.GetFloaterCount()) {
|
||||
|
@ -3135,6 +3176,8 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4170,12 +4213,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
mBlock->ReflowFloater(*this, aPlaceholder, metrics);
|
||||
|
||||
// Flush out pending bottom margin before placing floater
|
||||
if (0 != mPrevBottomMargin) {
|
||||
mY += mPrevBottomMargin;
|
||||
mPrevBottomMargin = 0;
|
||||
}
|
||||
|
||||
// Because we are in the middle of reflowing a placeholder frame
|
||||
// within a line (and possibly nested in an inline frame or two
|
||||
// that's a child of our block) we need to restore the space
|
||||
|
@ -4191,7 +4228,6 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
PlaceFloater(aPlaceholder, &isLeftFloater, &origin);
|
||||
|
||||
// Update the floater combined-area
|
||||
// XXX SlideFrames will muck this up!
|
||||
metrics.mCombinedArea.x += origin.x;
|
||||
metrics.mCombinedArea.y += origin.y;
|
||||
CombineRects(metrics.mCombinedArea, mFloaterCombinedArea);
|
||||
|
|
Загрузка…
Ссылка в новой задаче