Bug 209694. Major rework of margin-collapsing and clearance to match CSS 2.1 rules. Also includes major incremental reflow fixes for those situations. See the bug for details. rubber-stamp r+sr=dbaron
git-svn-id: svn://10.0.0.236/trunk@165781 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
c5ebd56e85
commit
d4a6c32e7b
@ -434,3 +434,33 @@ nsLayoutUtils::GetNearestScrollingView(nsIView* aView, Direction aDirection)
|
||||
}
|
||||
return scrollableView;
|
||||
}
|
||||
|
||||
// Combine aNewBreakType with aOrigBreakType, but limit the break types
|
||||
// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT.
|
||||
PRUint8
|
||||
nsLayoutUtils::CombineBreakType(PRUint8 aOrigBreakType,
|
||||
PRUint8 aNewBreakType)
|
||||
{
|
||||
PRUint8 breakType = aOrigBreakType;
|
||||
switch(breakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
if ((NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
||||
breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
||||
breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_CLEAR_NONE:
|
||||
if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
||||
breakType = aNewBreakType;
|
||||
}
|
||||
}
|
||||
return breakType;
|
||||
}
|
||||
|
||||
@ -236,6 +236,10 @@ public:
|
||||
* otherwise return nsnull.
|
||||
*/
|
||||
static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPossiblePlaceholder);
|
||||
|
||||
// Combine aNewBreakType with aOrigBreakType, but limit the break types
|
||||
// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT.
|
||||
static PRUint8 CombineBreakType(PRUint8 aOrigBreakType, PRUint8 aNewBreakType);
|
||||
};
|
||||
|
||||
#endif // nsLayoutUtils_h__
|
||||
|
||||
@ -237,6 +237,13 @@ struct nsHTMLReflowState {
|
||||
// a frame (e.g. nsTableFrame) which initiates a special reflow for percent height calculations
|
||||
nsIFrame* mPercentHeightReflowInitiator;
|
||||
|
||||
// CSS margin collapsing sometimes requires us to reflow
|
||||
// optimistically assuming that margins collapse to see if clearance
|
||||
// is required. When we discover that clearance is required, we
|
||||
// store the frame in which clearance was discovered to the location
|
||||
// requested here.
|
||||
nsIFrame** mDiscoveredClearance;
|
||||
|
||||
// This value keeps track of how deeply nested a given reflow state
|
||||
// is from the top of the frame tree.
|
||||
PRInt16 mReflowDepth;
|
||||
@ -249,6 +256,7 @@ struct nsHTMLReflowState {
|
||||
PRUint16 mIsTopOfPage:1; // is the current context at the top of a page?
|
||||
PRUint16 mBlinks:1; // Keep track of text-decoration: blink
|
||||
PRUint16 mVisualBidiFormControl:1; // Keep track of descendants of form controls on Visual Bidi pages
|
||||
PRUint16 mHasClearance:1; // Block has clearance
|
||||
} mFlags;
|
||||
|
||||
#ifdef IBMBIDI
|
||||
|
||||
@ -236,6 +236,10 @@ public:
|
||||
* otherwise return nsnull.
|
||||
*/
|
||||
static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPossiblePlaceholder);
|
||||
|
||||
// Combine aNewBreakType with aOrigBreakType, but limit the break types
|
||||
// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT.
|
||||
static PRUint8 CombineBreakType(PRUint8 aOrigBreakType, PRUint8 aNewBreakType);
|
||||
};
|
||||
|
||||
#endif // nsLayoutUtils_h__
|
||||
|
||||
@ -434,3 +434,33 @@ nsLayoutUtils::GetNearestScrollingView(nsIView* aView, Direction aDirection)
|
||||
}
|
||||
return scrollableView;
|
||||
}
|
||||
|
||||
// Combine aNewBreakType with aOrigBreakType, but limit the break types
|
||||
// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT.
|
||||
PRUint8
|
||||
nsLayoutUtils::CombineBreakType(PRUint8 aOrigBreakType,
|
||||
PRUint8 aNewBreakType)
|
||||
{
|
||||
PRUint8 breakType = aOrigBreakType;
|
||||
switch(breakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
if ((NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
||||
breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
||||
breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_CLEAR_NONE:
|
||||
if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
|
||||
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
||||
breakType = aNewBreakType;
|
||||
}
|
||||
}
|
||||
return breakType;
|
||||
}
|
||||
|
||||
@ -1080,6 +1080,22 @@ nsSpaceManager::PopState()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSpaceManager::DiscardState()
|
||||
{
|
||||
NS_ASSERTION(mSavedStates, "Invalid call to DiscardState()!");
|
||||
|
||||
if (!mSavedStates) {
|
||||
return;
|
||||
}
|
||||
|
||||
SpaceManagerState *state = mSavedStates;
|
||||
mSavedStates = mSavedStates->mNext;
|
||||
if(state != &mAutoState) {
|
||||
delete state;
|
||||
}
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsSpaceManager::GetLowestRegionTop()
|
||||
{
|
||||
|
||||
@ -311,6 +311,12 @@ public:
|
||||
*/
|
||||
void PopState();
|
||||
|
||||
/**
|
||||
* Pops the state off the stack without restoring it. Useful for speculative
|
||||
* reflow where we're not sure if we're going to keep the result.
|
||||
*/
|
||||
void DiscardState();
|
||||
|
||||
/**
|
||||
* Get the top of the last region placed into the space manager, to
|
||||
* enforce the rule that a float can't be above an earlier float.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -69,6 +69,11 @@ class nsIntervalSet;
|
||||
#define NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS 0x04000000
|
||||
#define NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS 0x08000000
|
||||
|
||||
// Set on any block that has descendant frames in the normal
|
||||
// flow with 'clear' set to something other than 'none'
|
||||
// (including <BR CLEAR="..."> frames)
|
||||
#define NS_BLOCK_HAS_CLEAR_CHILDREN 0x10000000
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
@ -224,6 +229,11 @@ public:
|
||||
virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
|
||||
nsIFrame* aNextInFlow);
|
||||
|
||||
// Determines whether the collapsed margin carried out of the last
|
||||
// line includes the margin-top of a line with clearance (in which
|
||||
// case we must avoid collapsing that margin with our bottom margin)
|
||||
PRBool CheckForCollapsedBottomMarginFromClearanceLine();
|
||||
|
||||
/** return the topmost block child based on y-index.
|
||||
* almost always the first or second line, if there is one.
|
||||
* accounts for lines that hold only compressed white space, etc.
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
#include "nsIDOMHTMLBodyElement.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_MAX_ELEMENT_SIZE
|
||||
@ -79,13 +80,12 @@ nsBlockReflowContext::nsBlockReflowContext(nsPresContext* aPresContext,
|
||||
mMetrics.mFlags |= NS_REFLOW_CALC_MAX_WIDTH;
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockReflowContext::ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
nsHTMLReflowState& aRS,
|
||||
/* inout */ nsCollapsingMargin& aMargin)
|
||||
PRBool
|
||||
nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
|
||||
nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame, PRBool* aMayNeedRetry)
|
||||
{
|
||||
// Get aFrame's top margin
|
||||
aMargin.Include(aRS.mComputedMargin.top);
|
||||
// Include frame's top margin
|
||||
aMargin->Include(aRS.mComputedMargin.top);
|
||||
|
||||
// The inclusion of the bottom margin when empty is done by the caller
|
||||
// since it doesn't need to be done by the top-level (non-recursive)
|
||||
@ -93,48 +93,77 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, aRS.frame);
|
||||
printf(": %d => %d\n", aRS.mComputedMargin.top, aMargin.get());
|
||||
printf(": %d => %d\n", aRS.mComputedMargin.top, aMargin->get());
|
||||
#endif
|
||||
|
||||
// Calculate aFrame's generational top-margin from its child
|
||||
// blocks. Note that if aFrame has a non-zero top-border or
|
||||
PRBool dirtiedLine = PR_FALSE;
|
||||
|
||||
// Calculate the frame's generational top-margin from its child
|
||||
// blocks. Note that if the frame has a non-zero top-border or
|
||||
// top-padding then this step is skipped because it will be a margin
|
||||
// root. It is also skipped if the frame is a margin root for other
|
||||
// reasons.
|
||||
void* bf;
|
||||
if (0 == aRS.mComputedBorderPadding.top &&
|
||||
!(aRS.frame->GetStateBits() & NS_BLOCK_MARGIN_ROOT)) {
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID,
|
||||
NS_REINTERPRET_CAST(void**, &bf)))) {
|
||||
for (nsBlockFrame::line_iterator line = bf->begin_lines(),
|
||||
line_end = bf->end_lines();
|
||||
line != line_end; ++line) {
|
||||
PRBool isEmpty = line->IsEmpty();
|
||||
if (line->IsBlock()) {
|
||||
// Here is where we recur. Now that we have determined that a
|
||||
// generational collapse is required we need to compute the
|
||||
// child blocks margin and so in so that we can look into
|
||||
// it. For its margins to be computed we need to have a reflow
|
||||
// state for it. Since the reflow reason is irrelevant, we'll
|
||||
// arbitrarily make it a `resize' to avoid the path-plucking
|
||||
// behavior if we're in an incremental reflow.
|
||||
nsSize availSpace(aRS.mComputedWidth, aRS.mComputedHeight);
|
||||
nsHTMLReflowState reflowState(aPresContext, aRS, line->mFirstChild,
|
||||
availSpace, eReflowReason_Resize);
|
||||
ComputeCollapsedTopMargin(aPresContext, reflowState, aMargin);
|
||||
if (isEmpty)
|
||||
aMargin.Include(reflowState.mComputedMargin.bottom);
|
||||
}
|
||||
if (!isEmpty)
|
||||
break;
|
||||
!(aRS.frame->GetStateBits() & NS_BLOCK_MARGIN_ROOT) &&
|
||||
NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, &bf))) {
|
||||
nsBlockFrame* block = NS_STATIC_CAST(nsBlockFrame*, aRS.frame);
|
||||
|
||||
for (nsBlockFrame::line_iterator line = block->begin_lines(),
|
||||
line_end = block->end_lines();
|
||||
line != line_end; ++line) {
|
||||
if (!aClearanceFrame && line->HasClearance()) {
|
||||
// If we don't have a clearance frame, then we're computing
|
||||
// the collapsed margin in the first pass, assuming that all
|
||||
// lines have no clearance. So clear their clearance flags.
|
||||
line->ClearHasClearance();
|
||||
line->MarkDirty();
|
||||
dirtiedLine = PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool isEmpty = line->IsEmpty();
|
||||
if (line->IsBlock()) {
|
||||
nsBlockFrame* kidBlock = NS_STATIC_CAST(nsBlockFrame*, line->mFirstChild);
|
||||
if (kidBlock == aClearanceFrame) {
|
||||
line->SetHasClearance();
|
||||
line->MarkDirty();
|
||||
dirtiedLine = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
// Here is where we recur. Now that we have determined that a
|
||||
// generational collapse is required we need to compute the
|
||||
// child blocks margin and so in so that we can look into
|
||||
// it. For its margins to be computed we need to have a reflow
|
||||
// state for it. Since the reflow reason is irrelevant, we'll
|
||||
// arbitrarily make it a `resize' to avoid the path-plucking
|
||||
// behavior if we're in an incremental reflow.
|
||||
nsSize availSpace(aRS.mComputedWidth, aRS.mComputedHeight);
|
||||
nsHTMLReflowState reflowState(kidBlock->GetPresContext(),
|
||||
aRS, kidBlock,
|
||||
availSpace, eReflowReason_Resize);
|
||||
// Record that we're being optimistic by assuming the kid
|
||||
// has no clearance
|
||||
if (kidBlock->GetStyleDisplay()->mBreakType != NS_STYLE_CLEAR_NONE) {
|
||||
*aMayNeedRetry = PR_TRUE;
|
||||
}
|
||||
if (ComputeCollapsedTopMargin(reflowState, aMargin, aClearanceFrame, aMayNeedRetry)) {
|
||||
line->MarkDirty();
|
||||
dirtiedLine = PR_TRUE;
|
||||
}
|
||||
if (isEmpty)
|
||||
aMargin->Include(reflowState.mComputedMargin.bottom);
|
||||
}
|
||||
if (!isEmpty)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, aRS.frame);
|
||||
printf(": => %d\n", aMargin.get());
|
||||
#endif
|
||||
|
||||
return dirtiedLine;
|
||||
}
|
||||
|
||||
struct nsBlockHorizontalAlign {
|
||||
@ -302,7 +331,8 @@ nsPointDtor(void *aFrame, nsIAtom *aPropertyName,
|
||||
nsresult
|
||||
nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
PRBool aApplyTopMargin,
|
||||
nsCollapsingMargin& aPrevBottomMargin,
|
||||
nsCollapsingMargin& aPrevMargin,
|
||||
nscoord aClearance,
|
||||
PRBool aIsAdjacentWithTop,
|
||||
nsMargin& aComputedOffsets,
|
||||
nsHTMLReflowState& aFrameRS,
|
||||
@ -354,32 +384,8 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
aFrameRS.reason = eReflowReason_Dirty;
|
||||
}
|
||||
|
||||
/* We build a different reflow context based on the width attribute of the block,
|
||||
* if it's a float.
|
||||
* Auto-width floats need to have their containing-block size set explicitly,
|
||||
* factoring in other floats that impact it.
|
||||
* It's possible this should be quirks-only.
|
||||
* All other blocks proceed normally.
|
||||
*/
|
||||
// XXXldb We should really fix this in nsHTMLReflowState::InitConstraints instead.
|
||||
const nsStylePosition* position = mFrame->GetStylePosition();
|
||||
nsStyleUnit widthUnit = position->mWidth.GetUnit();
|
||||
const nsStyleDisplay* display = mFrame->GetStyleDisplay();
|
||||
|
||||
if ((eStyleUnit_Auto == widthUnit) &&
|
||||
((NS_STYLE_FLOAT_LEFT == display->mFloats) ||
|
||||
(NS_STYLE_FLOAT_RIGHT == display->mFloats))) {
|
||||
// Initialize the reflow state and constrain the containing block's
|
||||
// width and height to the available width and height.
|
||||
aFrameRS.Init(mPresContext, mSpace.width, mSpace.height);
|
||||
}
|
||||
else {
|
||||
// Initialize the reflow state and use the containing block's computed
|
||||
// width and height (or derive appropriate values for an
|
||||
// absolutely positioned frame).
|
||||
aFrameRS.Init(mPresContext);
|
||||
}
|
||||
|
||||
aComputedOffsets = aFrameRS.mComputedOffsets;
|
||||
if (NS_STYLE_POSITION_RELATIVE == display->mPosition) {
|
||||
nsPropertyTable *propTable = mPresContext->PropertyTable();
|
||||
@ -404,23 +410,20 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
mComputedWidth = aFrameRS.mComputedWidth;
|
||||
|
||||
if (aApplyTopMargin) {
|
||||
// Compute the childs collapsed top margin (its margin collpased
|
||||
// with its first childs top-margin -- recursively).
|
||||
ComputeCollapsedTopMargin(mPresContext, aFrameRS, aPrevBottomMargin);
|
||||
mTopMargin = aPrevMargin;
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, mOuterReflowState.frame);
|
||||
printf(": reflowing ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(" margin => %d\n", aPrevBottomMargin.get());
|
||||
printf(" margin => %d, clearance => %d\n", mTopMargin.get(), aClearance);
|
||||
#endif
|
||||
|
||||
// Adjust the available height if its constrained so that the
|
||||
// child frame doesn't think it can reflow into its margin area.
|
||||
if (NS_UNCONSTRAINEDSIZE != aFrameRS.availableHeight) {
|
||||
aFrameRS.availableHeight -= aPrevBottomMargin.get();
|
||||
aFrameRS.availableHeight -= mTopMargin.get() + aClearance;
|
||||
}
|
||||
mTopMargin = aPrevBottomMargin;
|
||||
}
|
||||
|
||||
// Compute x/y coordinate where reflow will begin. Use the rules
|
||||
@ -431,7 +434,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
mStyleMargin = aFrameRS.mStyleMargin;
|
||||
mStylePadding = aFrameRS.mStylePadding;
|
||||
nscoord x;
|
||||
nscoord y = mSpace.y + mTopMargin.get();
|
||||
nscoord y = mSpace.y + mTopMargin.get() + aClearance;
|
||||
|
||||
// If it's a right floated element, then calculate the x-offset
|
||||
// differently
|
||||
@ -647,6 +650,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
PRBool
|
||||
nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool aForceFit,
|
||||
nsLineBox* aLine,
|
||||
const nsMargin& aComputedOffsets,
|
||||
nsCollapsingMargin& aBottomMarginResult,
|
||||
nsRect& aInFlowBounds,
|
||||
@ -660,15 +664,13 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool fits = PR_TRUE;
|
||||
nscoord x = mX;
|
||||
nscoord y = mY;
|
||||
// When deciding whether it's empty we also need to take into
|
||||
// account the overflow area
|
||||
|
||||
// XXXldb What should really matter is whether there exist non-
|
||||
// empty frames in the block (with appropriate whitespace munging).
|
||||
// Consider the case where we clip off the overflow with
|
||||
// 'overflow: -moz-hidden-unscrollable' (which doesn't currently
|
||||
// affect mOverflowArea, but probably should.
|
||||
if ((0 == mMetrics.height) && (0 == mMetrics.mOverflowArea.height))
|
||||
// Check whether the block's bottom margin collapses with its top
|
||||
// margin. See CSS 2.1 section 8.3.1; those rules seem to match
|
||||
// nsBlockFrame::IsEmpty(). Any such block must have zero height so
|
||||
// check that first.
|
||||
if (0 == mMetrics.height && !aLine->HasClearance() &&
|
||||
aLine->CachedIsEmpty())
|
||||
{
|
||||
// Collapse the bottom margin with the top margin that was already
|
||||
// applied.
|
||||
|
||||
@ -39,10 +39,12 @@
|
||||
#define nsBlockReflowContext_h___
|
||||
|
||||
#include "nsIFrame.h"
|
||||
#include "nsHTMLReflowState.h"
|
||||
#include "nsHTMLReflowMetrics.h"
|
||||
|
||||
class nsBlockFrame;
|
||||
class nsBlockReflowState;
|
||||
class nsHTMLReflowState;
|
||||
class nsLineBox;
|
||||
class nsIFrame;
|
||||
class nsPresContext;
|
||||
class nsLineLayout;
|
||||
@ -62,7 +64,8 @@ public:
|
||||
|
||||
nsresult ReflowBlock(const nsRect& aSpace,
|
||||
PRBool aApplyTopMargin,
|
||||
nsCollapsingMargin& aPrevBottomMargin,
|
||||
nsCollapsingMargin& aPrevMargin,
|
||||
nscoord aClearance,
|
||||
PRBool aIsAdjacentWithTop,
|
||||
nsMargin& aComputedOffsets,
|
||||
nsHTMLReflowState& aReflowState,
|
||||
@ -70,6 +73,7 @@ public:
|
||||
|
||||
PRBool PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool aForceFit,
|
||||
nsLineBox* aLine,
|
||||
const nsMargin& aComputedOffsets,
|
||||
nsCollapsingMargin& aBottomMarginResult /* out */,
|
||||
nsRect& aInFlowBounds,
|
||||
@ -101,9 +105,23 @@ public:
|
||||
return mMetrics.mMaximumWidth;
|
||||
}
|
||||
|
||||
static void ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
nsHTMLReflowState& aRS,
|
||||
/* inout */ nsCollapsingMargin& aMargin);
|
||||
/**
|
||||
* Computes the collapsed top margin for a block whose reflow state is in aRS.
|
||||
* The computed margin is added into aMargin.
|
||||
* If aClearanceFrame is null then this is the first optimistic pass which shall assume
|
||||
* that no frames have clearance, and we clear the HasClearance on all frames encountered.
|
||||
* If non-null, this is the second pass and
|
||||
* the caller has decided aClearanceFrame needs clearance (and we will
|
||||
* therefore stop collapsing there); also, this function is responsible for marking
|
||||
* it with SetHasClearance.
|
||||
* If in the optimistic pass any frame is encountered that might possibly need
|
||||
* clearance (i.e., if we really needed the optimism assumption) then we set aMayNeedRetry
|
||||
* to true.
|
||||
* We return PR_TRUE if we changed the clearance state of any line and marked it dirty.
|
||||
*/
|
||||
static PRBool ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
|
||||
nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame,
|
||||
PRBool* aMayNeedRetry);
|
||||
|
||||
protected:
|
||||
nsPresContext* mPresContext;
|
||||
|
||||
@ -60,7 +60,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
PRBool aBlockMarginRoot)
|
||||
PRBool aTopMarginRoot,
|
||||
PRBool aBottomMarginRoot)
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
@ -71,14 +72,10 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
{
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
if (aBlockMarginRoot) {
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.top) {
|
||||
if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) {
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
if (aBottomMarginRoot || 0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
||||
@ -338,68 +335,6 @@ nsBlockReflowState::GetAvailableSpace(nscoord aY)
|
||||
#endif
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockReflowState::ClearPastFloats(PRUint8 aBreakType)
|
||||
{
|
||||
nscoord saveY, deltaY;
|
||||
|
||||
PRBool applyTopMargin = PR_FALSE;
|
||||
switch (aBreakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
||||
// Apply the previous margin before clearing
|
||||
saveY = mY + mPrevBottomMargin.get();
|
||||
ClearFloats(saveY, aBreakType);
|
||||
#ifdef NOISY_FLOAT_CLEARING
|
||||
nsFrame::ListTag(stdout, mBlock);
|
||||
printf(": ClearPastFloats: mPrevBottomMargin=%d saveY=%d oldY=%d newY=%d deltaY=%d\n",
|
||||
mPrevBottomMargin.get(), saveY, saveY - mPrevBottomMargin.get(), mY,
|
||||
mY - saveY);
|
||||
#endif
|
||||
|
||||
// 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 = 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 floats.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// XXXldb This doesn't handle collapsing with negative margins
|
||||
// correctly, although it's arguable what "correct" is.
|
||||
|
||||
// XXX Are all the other margins included by this point?
|
||||
mPrevBottomMargin.Zero();
|
||||
mPrevBottomMargin.Include(deltaY);
|
||||
mY = saveY;
|
||||
|
||||
// Force margin to be applied in this circumstance
|
||||
applyTopMargin = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Put mY back to its original value since no clearing
|
||||
// happened. That way the previous blocks bottom margin will
|
||||
// be applied properly.
|
||||
mY = saveY - mPrevBottomMargin.get();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return applyTopMargin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reconstruct the vertical margin before the line |aLine| in order to
|
||||
* do an incremental reflow that begins with |aLine| without reflowing
|
||||
@ -851,12 +786,10 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
||||
// See if the float should clear any preceeding floats...
|
||||
if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
|
||||
// XXXldb Does this handle vertical margins correctly?
|
||||
ClearFloats(mY, floatDisplay->mBreakType);
|
||||
mY = ClearFloats(mY, floatDisplay->mBreakType);
|
||||
}
|
||||
else {
|
||||
// Get the band of available space
|
||||
GetAvailableSpace();
|
||||
}
|
||||
|
||||
NS_ASSERTION(floatFrame->GetParent() == mBlock,
|
||||
"Float frame has wrong parent");
|
||||
@ -1154,14 +1087,14 @@ nsBlockReflowState::PlaceBelowCurrentLineFloats(nsFloatCacheList& aList)
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nscoord
|
||||
nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisyReflow) {
|
||||
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
||||
printf("clear floats: in: mY=%d aY=%d(%d)\n",
|
||||
mY, aY, aY - BorderPadding().top);
|
||||
printf("clear floats: in: aY=%d(%d)\n",
|
||||
aY, aY - BorderPadding().top);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1173,14 +1106,15 @@ nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType)
|
||||
|
||||
const nsMargin& bp = BorderPadding();
|
||||
nscoord newY = mSpaceManager->ClearFloats(aY - bp.top, aBreakType);
|
||||
mY = newY + bp.top;
|
||||
GetAvailableSpace();
|
||||
newY += bp.top;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisyReflow) {
|
||||
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
||||
printf("clear floats: out: mY=%d(%d)\n", mY, mY - bp.top);
|
||||
printf("clear floats: out: y=%d(%d)\n", newY, newY - bp.top);
|
||||
}
|
||||
#endif
|
||||
|
||||
return newY;
|
||||
}
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ public:
|
||||
nsPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
PRBool aBlockMarginRoot);
|
||||
PRBool aTopMarginRoot, PRBool aBottomMarginRoot);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
@ -85,12 +85,9 @@ public:
|
||||
|
||||
PRBool PlaceBelowCurrentLineFloats(nsFloatCacheList& aFloats);
|
||||
|
||||
// called when clearing a line with a break type caused by a BR past
|
||||
// floats, and also used internally by ClearPastFloats
|
||||
void ClearFloats(nscoord aY, PRUint8 aBreakType);
|
||||
|
||||
// called when clearing a block past floats
|
||||
PRBool ClearPastFloats(PRUint8 aBreakType);
|
||||
// Returns the first coordinate >= aY that clears the
|
||||
// indicated floats.
|
||||
nscoord ClearFloats(nscoord aY, PRUint8 aBreakType);
|
||||
|
||||
PRBool IsAdjacentWithTop() const {
|
||||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
|
||||
@ -111,6 +111,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mSpecialHeightReflow = PR_FALSE;
|
||||
mFlags.mIsTopOfPage = PR_FALSE;
|
||||
mFlags.mNextInFlowUntouched = PR_FALSE;
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = nsnull;
|
||||
mPercentHeightReflowInitiator = nsnull;
|
||||
Init(aPresContext);
|
||||
@ -143,6 +145,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mSpecialHeightReflow = PR_FALSE;
|
||||
mFlags.mIsTopOfPage = PR_FALSE;
|
||||
mFlags.mNextInFlowUntouched = PR_FALSE;
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = nsnull;
|
||||
mPercentHeightReflowInitiator = nsnull;
|
||||
Init(aPresContext);
|
||||
@ -193,6 +197,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
@ -240,6 +246,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
@ -287,6 +295,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
|
||||
@ -237,6 +237,13 @@ struct nsHTMLReflowState {
|
||||
// a frame (e.g. nsTableFrame) which initiates a special reflow for percent height calculations
|
||||
nsIFrame* mPercentHeightReflowInitiator;
|
||||
|
||||
// CSS margin collapsing sometimes requires us to reflow
|
||||
// optimistically assuming that margins collapse to see if clearance
|
||||
// is required. When we discover that clearance is required, we
|
||||
// store the frame in which clearance was discovered to the location
|
||||
// requested here.
|
||||
nsIFrame** mDiscoveredClearance;
|
||||
|
||||
// This value keeps track of how deeply nested a given reflow state
|
||||
// is from the top of the frame tree.
|
||||
PRInt16 mReflowDepth;
|
||||
@ -249,6 +256,7 @@ struct nsHTMLReflowState {
|
||||
PRUint16 mIsTopOfPage:1; // is the current context at the top of a page?
|
||||
PRUint16 mBlinks:1; // Keep track of text-decoration: blink
|
||||
PRUint16 mVisualBidiFormControl:1; // Keep track of descendants of form controls on Visual Bidi pages
|
||||
PRUint16 mHasClearance:1; // Block has clearance
|
||||
} mFlags;
|
||||
|
||||
#ifdef IBMBIDI
|
||||
|
||||
@ -181,13 +181,14 @@ BreakTypeToString(PRUint8 aBreakType)
|
||||
char*
|
||||
nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const
|
||||
{
|
||||
PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,%s[0x%x]",
|
||||
PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,before:%s,after:%s[0x%x]",
|
||||
IsBlock() ? "block" : "inline",
|
||||
IsDirty() ? "dirty" : "clean",
|
||||
IsPreviousMarginDirty() ? "prevmargindirty" : "prevmarginclean",
|
||||
IsImpactedByFloat() ? "impacted" : "not impacted",
|
||||
IsLineWrapped() ? "wrapped" : "not wrapped",
|
||||
BreakTypeToString(GetBreakType()),
|
||||
BreakTypeToString(GetBreakTypeBefore()),
|
||||
BreakTypeToString(GetBreakTypeAfter()),
|
||||
mAllFlags);
|
||||
return aBuf;
|
||||
}
|
||||
@ -604,7 +605,7 @@ nsLineIterator::GetLine(PRInt32 aLineNumber,
|
||||
flags |= NS_LINE_FLAG_IS_BLOCK;
|
||||
}
|
||||
else {
|
||||
if (line->HasBreak())
|
||||
if (line->HasBreakAfter())
|
||||
flags |= NS_LINE_FLAG_ENDS_IN_BREAK;
|
||||
}
|
||||
*aLineFlags = flags;
|
||||
|
||||
@ -246,6 +246,17 @@ public:
|
||||
return mFlags.mPreviousMarginDirty;
|
||||
}
|
||||
|
||||
// mHasClearance bit
|
||||
void SetHasClearance() {
|
||||
mFlags.mHasClearance = 1;
|
||||
}
|
||||
void ClearHasClearance() {
|
||||
mFlags.mHasClearance = 0;
|
||||
}
|
||||
PRBool HasClearance() const {
|
||||
return mFlags.mHasClearance;
|
||||
}
|
||||
|
||||
// mImpactedByFloat bit
|
||||
void SetLineIsImpactedByFloat(PRBool aValue) {
|
||||
NS_ASSERTION((PR_FALSE==aValue || PR_TRUE==aValue), "somebody is playing fast and loose with bools and bits!");
|
||||
@ -300,20 +311,37 @@ public:
|
||||
}
|
||||
|
||||
// mBreakType value
|
||||
PRBool HasBreak() const {
|
||||
return NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
|
||||
// Break information is applied *before* the line if the line is a block,
|
||||
// or *after* the line if the line is an inline. Confusing, I know, but
|
||||
// using different names should help.
|
||||
PRBool HasBreakBefore() const {
|
||||
return IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
|
||||
}
|
||||
PRBool HasFloatBreak() const {
|
||||
return NS_STYLE_CLEAR_LEFT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_LEFT_AND_RIGHT == mFlags.mBreakType;
|
||||
}
|
||||
void SetBreakType(PRUint8 aBreakType) {
|
||||
NS_WARN_IF_FALSE(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
|
||||
void SetBreakTypeBefore(PRUint8 aBreakType) {
|
||||
NS_ASSERTION(IsBlock(), "Only blocks have break-before");
|
||||
NS_ASSERTION(aBreakType <= NS_STYLE_CLEAR_LEFT_AND_RIGHT,
|
||||
"Only float break types are allowed before a line");
|
||||
mFlags.mBreakType = aBreakType;
|
||||
}
|
||||
PRUint8 GetBreakType() const {
|
||||
return mFlags.mBreakType;
|
||||
PRUint8 GetBreakTypeBefore() const {
|
||||
return IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
|
||||
}
|
||||
|
||||
PRBool HasBreakAfter() const {
|
||||
return !IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
|
||||
}
|
||||
void SetBreakTypeAfter(PRUint8 aBreakType) {
|
||||
NS_ASSERTION(!IsBlock(), "Only inlines have break-after");
|
||||
NS_ASSERTION(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
|
||||
mFlags.mBreakType = aBreakType;
|
||||
}
|
||||
PRBool HasFloatBreakAfter() const {
|
||||
return !IsBlock() && (NS_STYLE_CLEAR_LEFT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_LEFT_AND_RIGHT == mFlags.mBreakType);
|
||||
}
|
||||
PRUint8 GetBreakTypeAfter() const {
|
||||
return !IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
|
||||
}
|
||||
|
||||
// mCarriedOutBottomMargin value
|
||||
@ -427,6 +455,7 @@ public:
|
||||
struct FlagBits {
|
||||
PRUint32 mDirty : 1;
|
||||
PRUint32 mPreviousMarginDirty : 1;
|
||||
PRUint32 mHasClearance : 1;
|
||||
PRUint32 mBlock : 1;
|
||||
PRUint32 mImpactedByFloat : 1;
|
||||
PRUint32 mHasPercentageChild : 1;
|
||||
@ -436,7 +465,7 @@ public:
|
||||
PRUint32 mEmptyCacheState: 1;
|
||||
PRUint32 mBreakType : 4;
|
||||
|
||||
PRUint32 mChildCount : 19;
|
||||
PRUint32 mChildCount : 18;
|
||||
};
|
||||
|
||||
struct ExtraData {
|
||||
|
||||
@ -1080,6 +1080,22 @@ nsSpaceManager::PopState()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSpaceManager::DiscardState()
|
||||
{
|
||||
NS_ASSERTION(mSavedStates, "Invalid call to DiscardState()!");
|
||||
|
||||
if (!mSavedStates) {
|
||||
return;
|
||||
}
|
||||
|
||||
SpaceManagerState *state = mSavedStates;
|
||||
mSavedStates = mSavedStates->mNext;
|
||||
if(state != &mAutoState) {
|
||||
delete state;
|
||||
}
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsSpaceManager::GetLowestRegionTop()
|
||||
{
|
||||
|
||||
@ -311,6 +311,12 @@ public:
|
||||
*/
|
||||
void PopState();
|
||||
|
||||
/**
|
||||
* Pops the state off the stack without restoring it. Useful for speculative
|
||||
* reflow where we're not sure if we're going to keep the result.
|
||||
*/
|
||||
void DiscardState();
|
||||
|
||||
/**
|
||||
* Get the top of the last region placed into the space manager, to
|
||||
* enforce the rule that a float can't be above an earlier float.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -69,6 +69,11 @@ class nsIntervalSet;
|
||||
#define NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS 0x04000000
|
||||
#define NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS 0x08000000
|
||||
|
||||
// Set on any block that has descendant frames in the normal
|
||||
// flow with 'clear' set to something other than 'none'
|
||||
// (including <BR CLEAR="..."> frames)
|
||||
#define NS_BLOCK_HAS_CLEAR_CHILDREN 0x10000000
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
@ -224,6 +229,11 @@ public:
|
||||
virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
|
||||
nsIFrame* aNextInFlow);
|
||||
|
||||
// Determines whether the collapsed margin carried out of the last
|
||||
// line includes the margin-top of a line with clearance (in which
|
||||
// case we must avoid collapsing that margin with our bottom margin)
|
||||
PRBool CheckForCollapsedBottomMarginFromClearanceLine();
|
||||
|
||||
/** return the topmost block child based on y-index.
|
||||
* almost always the first or second line, if there is one.
|
||||
* accounts for lines that hold only compressed white space, etc.
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
#include "nsIDOMHTMLBodyElement.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#undef NOISY_MAX_ELEMENT_SIZE
|
||||
@ -79,13 +80,12 @@ nsBlockReflowContext::nsBlockReflowContext(nsPresContext* aPresContext,
|
||||
mMetrics.mFlags |= NS_REFLOW_CALC_MAX_WIDTH;
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockReflowContext::ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
nsHTMLReflowState& aRS,
|
||||
/* inout */ nsCollapsingMargin& aMargin)
|
||||
PRBool
|
||||
nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
|
||||
nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame, PRBool* aMayNeedRetry)
|
||||
{
|
||||
// Get aFrame's top margin
|
||||
aMargin.Include(aRS.mComputedMargin.top);
|
||||
// Include frame's top margin
|
||||
aMargin->Include(aRS.mComputedMargin.top);
|
||||
|
||||
// The inclusion of the bottom margin when empty is done by the caller
|
||||
// since it doesn't need to be done by the top-level (non-recursive)
|
||||
@ -93,48 +93,77 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, aRS.frame);
|
||||
printf(": %d => %d\n", aRS.mComputedMargin.top, aMargin.get());
|
||||
printf(": %d => %d\n", aRS.mComputedMargin.top, aMargin->get());
|
||||
#endif
|
||||
|
||||
// Calculate aFrame's generational top-margin from its child
|
||||
// blocks. Note that if aFrame has a non-zero top-border or
|
||||
PRBool dirtiedLine = PR_FALSE;
|
||||
|
||||
// Calculate the frame's generational top-margin from its child
|
||||
// blocks. Note that if the frame has a non-zero top-border or
|
||||
// top-padding then this step is skipped because it will be a margin
|
||||
// root. It is also skipped if the frame is a margin root for other
|
||||
// reasons.
|
||||
void* bf;
|
||||
if (0 == aRS.mComputedBorderPadding.top &&
|
||||
!(aRS.frame->GetStateBits() & NS_BLOCK_MARGIN_ROOT)) {
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID,
|
||||
NS_REINTERPRET_CAST(void**, &bf)))) {
|
||||
for (nsBlockFrame::line_iterator line = bf->begin_lines(),
|
||||
line_end = bf->end_lines();
|
||||
line != line_end; ++line) {
|
||||
PRBool isEmpty = line->IsEmpty();
|
||||
if (line->IsBlock()) {
|
||||
// Here is where we recur. Now that we have determined that a
|
||||
// generational collapse is required we need to compute the
|
||||
// child blocks margin and so in so that we can look into
|
||||
// it. For its margins to be computed we need to have a reflow
|
||||
// state for it. Since the reflow reason is irrelevant, we'll
|
||||
// arbitrarily make it a `resize' to avoid the path-plucking
|
||||
// behavior if we're in an incremental reflow.
|
||||
nsSize availSpace(aRS.mComputedWidth, aRS.mComputedHeight);
|
||||
nsHTMLReflowState reflowState(aPresContext, aRS, line->mFirstChild,
|
||||
availSpace, eReflowReason_Resize);
|
||||
ComputeCollapsedTopMargin(aPresContext, reflowState, aMargin);
|
||||
if (isEmpty)
|
||||
aMargin.Include(reflowState.mComputedMargin.bottom);
|
||||
}
|
||||
if (!isEmpty)
|
||||
break;
|
||||
!(aRS.frame->GetStateBits() & NS_BLOCK_MARGIN_ROOT) &&
|
||||
NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, &bf))) {
|
||||
nsBlockFrame* block = NS_STATIC_CAST(nsBlockFrame*, aRS.frame);
|
||||
|
||||
for (nsBlockFrame::line_iterator line = block->begin_lines(),
|
||||
line_end = block->end_lines();
|
||||
line != line_end; ++line) {
|
||||
if (!aClearanceFrame && line->HasClearance()) {
|
||||
// If we don't have a clearance frame, then we're computing
|
||||
// the collapsed margin in the first pass, assuming that all
|
||||
// lines have no clearance. So clear their clearance flags.
|
||||
line->ClearHasClearance();
|
||||
line->MarkDirty();
|
||||
dirtiedLine = PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool isEmpty = line->IsEmpty();
|
||||
if (line->IsBlock()) {
|
||||
nsBlockFrame* kidBlock = NS_STATIC_CAST(nsBlockFrame*, line->mFirstChild);
|
||||
if (kidBlock == aClearanceFrame) {
|
||||
line->SetHasClearance();
|
||||
line->MarkDirty();
|
||||
dirtiedLine = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
// Here is where we recur. Now that we have determined that a
|
||||
// generational collapse is required we need to compute the
|
||||
// child blocks margin and so in so that we can look into
|
||||
// it. For its margins to be computed we need to have a reflow
|
||||
// state for it. Since the reflow reason is irrelevant, we'll
|
||||
// arbitrarily make it a `resize' to avoid the path-plucking
|
||||
// behavior if we're in an incremental reflow.
|
||||
nsSize availSpace(aRS.mComputedWidth, aRS.mComputedHeight);
|
||||
nsHTMLReflowState reflowState(kidBlock->GetPresContext(),
|
||||
aRS, kidBlock,
|
||||
availSpace, eReflowReason_Resize);
|
||||
// Record that we're being optimistic by assuming the kid
|
||||
// has no clearance
|
||||
if (kidBlock->GetStyleDisplay()->mBreakType != NS_STYLE_CLEAR_NONE) {
|
||||
*aMayNeedRetry = PR_TRUE;
|
||||
}
|
||||
if (ComputeCollapsedTopMargin(reflowState, aMargin, aClearanceFrame, aMayNeedRetry)) {
|
||||
line->MarkDirty();
|
||||
dirtiedLine = PR_TRUE;
|
||||
}
|
||||
if (isEmpty)
|
||||
aMargin->Include(reflowState.mComputedMargin.bottom);
|
||||
}
|
||||
if (!isEmpty)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, aRS.frame);
|
||||
printf(": => %d\n", aMargin.get());
|
||||
#endif
|
||||
|
||||
return dirtiedLine;
|
||||
}
|
||||
|
||||
struct nsBlockHorizontalAlign {
|
||||
@ -302,7 +331,8 @@ nsPointDtor(void *aFrame, nsIAtom *aPropertyName,
|
||||
nsresult
|
||||
nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
PRBool aApplyTopMargin,
|
||||
nsCollapsingMargin& aPrevBottomMargin,
|
||||
nsCollapsingMargin& aPrevMargin,
|
||||
nscoord aClearance,
|
||||
PRBool aIsAdjacentWithTop,
|
||||
nsMargin& aComputedOffsets,
|
||||
nsHTMLReflowState& aFrameRS,
|
||||
@ -354,32 +384,8 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
aFrameRS.reason = eReflowReason_Dirty;
|
||||
}
|
||||
|
||||
/* We build a different reflow context based on the width attribute of the block,
|
||||
* if it's a float.
|
||||
* Auto-width floats need to have their containing-block size set explicitly,
|
||||
* factoring in other floats that impact it.
|
||||
* It's possible this should be quirks-only.
|
||||
* All other blocks proceed normally.
|
||||
*/
|
||||
// XXXldb We should really fix this in nsHTMLReflowState::InitConstraints instead.
|
||||
const nsStylePosition* position = mFrame->GetStylePosition();
|
||||
nsStyleUnit widthUnit = position->mWidth.GetUnit();
|
||||
const nsStyleDisplay* display = mFrame->GetStyleDisplay();
|
||||
|
||||
if ((eStyleUnit_Auto == widthUnit) &&
|
||||
((NS_STYLE_FLOAT_LEFT == display->mFloats) ||
|
||||
(NS_STYLE_FLOAT_RIGHT == display->mFloats))) {
|
||||
// Initialize the reflow state and constrain the containing block's
|
||||
// width and height to the available width and height.
|
||||
aFrameRS.Init(mPresContext, mSpace.width, mSpace.height);
|
||||
}
|
||||
else {
|
||||
// Initialize the reflow state and use the containing block's computed
|
||||
// width and height (or derive appropriate values for an
|
||||
// absolutely positioned frame).
|
||||
aFrameRS.Init(mPresContext);
|
||||
}
|
||||
|
||||
aComputedOffsets = aFrameRS.mComputedOffsets;
|
||||
if (NS_STYLE_POSITION_RELATIVE == display->mPosition) {
|
||||
nsPropertyTable *propTable = mPresContext->PropertyTable();
|
||||
@ -404,23 +410,20 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
mComputedWidth = aFrameRS.mComputedWidth;
|
||||
|
||||
if (aApplyTopMargin) {
|
||||
// Compute the childs collapsed top margin (its margin collpased
|
||||
// with its first childs top-margin -- recursively).
|
||||
ComputeCollapsedTopMargin(mPresContext, aFrameRS, aPrevBottomMargin);
|
||||
mTopMargin = aPrevMargin;
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
nsFrame::ListTag(stdout, mOuterReflowState.frame);
|
||||
printf(": reflowing ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(" margin => %d\n", aPrevBottomMargin.get());
|
||||
printf(" margin => %d, clearance => %d\n", mTopMargin.get(), aClearance);
|
||||
#endif
|
||||
|
||||
// Adjust the available height if its constrained so that the
|
||||
// child frame doesn't think it can reflow into its margin area.
|
||||
if (NS_UNCONSTRAINEDSIZE != aFrameRS.availableHeight) {
|
||||
aFrameRS.availableHeight -= aPrevBottomMargin.get();
|
||||
aFrameRS.availableHeight -= mTopMargin.get() + aClearance;
|
||||
}
|
||||
mTopMargin = aPrevBottomMargin;
|
||||
}
|
||||
|
||||
// Compute x/y coordinate where reflow will begin. Use the rules
|
||||
@ -431,7 +434,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
mStyleMargin = aFrameRS.mStyleMargin;
|
||||
mStylePadding = aFrameRS.mStylePadding;
|
||||
nscoord x;
|
||||
nscoord y = mSpace.y + mTopMargin.get();
|
||||
nscoord y = mSpace.y + mTopMargin.get() + aClearance;
|
||||
|
||||
// If it's a right floated element, then calculate the x-offset
|
||||
// differently
|
||||
@ -647,6 +650,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
||||
PRBool
|
||||
nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool aForceFit,
|
||||
nsLineBox* aLine,
|
||||
const nsMargin& aComputedOffsets,
|
||||
nsCollapsingMargin& aBottomMarginResult,
|
||||
nsRect& aInFlowBounds,
|
||||
@ -660,15 +664,13 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool fits = PR_TRUE;
|
||||
nscoord x = mX;
|
||||
nscoord y = mY;
|
||||
// When deciding whether it's empty we also need to take into
|
||||
// account the overflow area
|
||||
|
||||
// XXXldb What should really matter is whether there exist non-
|
||||
// empty frames in the block (with appropriate whitespace munging).
|
||||
// Consider the case where we clip off the overflow with
|
||||
// 'overflow: -moz-hidden-unscrollable' (which doesn't currently
|
||||
// affect mOverflowArea, but probably should.
|
||||
if ((0 == mMetrics.height) && (0 == mMetrics.mOverflowArea.height))
|
||||
// Check whether the block's bottom margin collapses with its top
|
||||
// margin. See CSS 2.1 section 8.3.1; those rules seem to match
|
||||
// nsBlockFrame::IsEmpty(). Any such block must have zero height so
|
||||
// check that first.
|
||||
if (0 == mMetrics.height && !aLine->HasClearance() &&
|
||||
aLine->CachedIsEmpty())
|
||||
{
|
||||
// Collapse the bottom margin with the top margin that was already
|
||||
// applied.
|
||||
|
||||
@ -39,10 +39,12 @@
|
||||
#define nsBlockReflowContext_h___
|
||||
|
||||
#include "nsIFrame.h"
|
||||
#include "nsHTMLReflowState.h"
|
||||
#include "nsHTMLReflowMetrics.h"
|
||||
|
||||
class nsBlockFrame;
|
||||
class nsBlockReflowState;
|
||||
class nsHTMLReflowState;
|
||||
class nsLineBox;
|
||||
class nsIFrame;
|
||||
class nsPresContext;
|
||||
class nsLineLayout;
|
||||
@ -62,7 +64,8 @@ public:
|
||||
|
||||
nsresult ReflowBlock(const nsRect& aSpace,
|
||||
PRBool aApplyTopMargin,
|
||||
nsCollapsingMargin& aPrevBottomMargin,
|
||||
nsCollapsingMargin& aPrevMargin,
|
||||
nscoord aClearance,
|
||||
PRBool aIsAdjacentWithTop,
|
||||
nsMargin& aComputedOffsets,
|
||||
nsHTMLReflowState& aReflowState,
|
||||
@ -70,6 +73,7 @@ public:
|
||||
|
||||
PRBool PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
PRBool aForceFit,
|
||||
nsLineBox* aLine,
|
||||
const nsMargin& aComputedOffsets,
|
||||
nsCollapsingMargin& aBottomMarginResult /* out */,
|
||||
nsRect& aInFlowBounds,
|
||||
@ -101,9 +105,23 @@ public:
|
||||
return mMetrics.mMaximumWidth;
|
||||
}
|
||||
|
||||
static void ComputeCollapsedTopMargin(nsPresContext* aPresContext,
|
||||
nsHTMLReflowState& aRS,
|
||||
/* inout */ nsCollapsingMargin& aMargin);
|
||||
/**
|
||||
* Computes the collapsed top margin for a block whose reflow state is in aRS.
|
||||
* The computed margin is added into aMargin.
|
||||
* If aClearanceFrame is null then this is the first optimistic pass which shall assume
|
||||
* that no frames have clearance, and we clear the HasClearance on all frames encountered.
|
||||
* If non-null, this is the second pass and
|
||||
* the caller has decided aClearanceFrame needs clearance (and we will
|
||||
* therefore stop collapsing there); also, this function is responsible for marking
|
||||
* it with SetHasClearance.
|
||||
* If in the optimistic pass any frame is encountered that might possibly need
|
||||
* clearance (i.e., if we really needed the optimism assumption) then we set aMayNeedRetry
|
||||
* to true.
|
||||
* We return PR_TRUE if we changed the clearance state of any line and marked it dirty.
|
||||
*/
|
||||
static PRBool ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
|
||||
nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame,
|
||||
PRBool* aMayNeedRetry);
|
||||
|
||||
protected:
|
||||
nsPresContext* mPresContext;
|
||||
|
||||
@ -60,7 +60,8 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
PRBool aBlockMarginRoot)
|
||||
PRBool aTopMarginRoot,
|
||||
PRBool aBottomMarginRoot)
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
@ -71,14 +72,10 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
{
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
if (aBlockMarginRoot) {
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.top) {
|
||||
if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) {
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
if (aBottomMarginRoot || 0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
||||
@ -338,68 +335,6 @@ nsBlockReflowState::GetAvailableSpace(nscoord aY)
|
||||
#endif
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockReflowState::ClearPastFloats(PRUint8 aBreakType)
|
||||
{
|
||||
nscoord saveY, deltaY;
|
||||
|
||||
PRBool applyTopMargin = PR_FALSE;
|
||||
switch (aBreakType) {
|
||||
case NS_STYLE_CLEAR_LEFT:
|
||||
case NS_STYLE_CLEAR_RIGHT:
|
||||
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
||||
// Apply the previous margin before clearing
|
||||
saveY = mY + mPrevBottomMargin.get();
|
||||
ClearFloats(saveY, aBreakType);
|
||||
#ifdef NOISY_FLOAT_CLEARING
|
||||
nsFrame::ListTag(stdout, mBlock);
|
||||
printf(": ClearPastFloats: mPrevBottomMargin=%d saveY=%d oldY=%d newY=%d deltaY=%d\n",
|
||||
mPrevBottomMargin.get(), saveY, saveY - mPrevBottomMargin.get(), mY,
|
||||
mY - saveY);
|
||||
#endif
|
||||
|
||||
// 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 = 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 floats.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// XXXldb This doesn't handle collapsing with negative margins
|
||||
// correctly, although it's arguable what "correct" is.
|
||||
|
||||
// XXX Are all the other margins included by this point?
|
||||
mPrevBottomMargin.Zero();
|
||||
mPrevBottomMargin.Include(deltaY);
|
||||
mY = saveY;
|
||||
|
||||
// Force margin to be applied in this circumstance
|
||||
applyTopMargin = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Put mY back to its original value since no clearing
|
||||
// happened. That way the previous blocks bottom margin will
|
||||
// be applied properly.
|
||||
mY = saveY - mPrevBottomMargin.get();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return applyTopMargin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reconstruct the vertical margin before the line |aLine| in order to
|
||||
* do an incremental reflow that begins with |aLine| without reflowing
|
||||
@ -851,12 +786,10 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
||||
// See if the float should clear any preceeding floats...
|
||||
if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
|
||||
// XXXldb Does this handle vertical margins correctly?
|
||||
ClearFloats(mY, floatDisplay->mBreakType);
|
||||
mY = ClearFloats(mY, floatDisplay->mBreakType);
|
||||
}
|
||||
else {
|
||||
// Get the band of available space
|
||||
GetAvailableSpace();
|
||||
}
|
||||
|
||||
NS_ASSERTION(floatFrame->GetParent() == mBlock,
|
||||
"Float frame has wrong parent");
|
||||
@ -1154,14 +1087,14 @@ nsBlockReflowState::PlaceBelowCurrentLineFloats(nsFloatCacheList& aList)
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nscoord
|
||||
nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisyReflow) {
|
||||
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
||||
printf("clear floats: in: mY=%d aY=%d(%d)\n",
|
||||
mY, aY, aY - BorderPadding().top);
|
||||
printf("clear floats: in: aY=%d(%d)\n",
|
||||
aY, aY - BorderPadding().top);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1173,14 +1106,15 @@ nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType)
|
||||
|
||||
const nsMargin& bp = BorderPadding();
|
||||
nscoord newY = mSpaceManager->ClearFloats(aY - bp.top, aBreakType);
|
||||
mY = newY + bp.top;
|
||||
GetAvailableSpace();
|
||||
newY += bp.top;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisyReflow) {
|
||||
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
||||
printf("clear floats: out: mY=%d(%d)\n", mY, mY - bp.top);
|
||||
printf("clear floats: out: y=%d(%d)\n", newY, newY - bp.top);
|
||||
}
|
||||
#endif
|
||||
|
||||
return newY;
|
||||
}
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ public:
|
||||
nsPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
PRBool aBlockMarginRoot);
|
||||
PRBool aTopMarginRoot, PRBool aBottomMarginRoot);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
@ -85,12 +85,9 @@ public:
|
||||
|
||||
PRBool PlaceBelowCurrentLineFloats(nsFloatCacheList& aFloats);
|
||||
|
||||
// called when clearing a line with a break type caused by a BR past
|
||||
// floats, and also used internally by ClearPastFloats
|
||||
void ClearFloats(nscoord aY, PRUint8 aBreakType);
|
||||
|
||||
// called when clearing a block past floats
|
||||
PRBool ClearPastFloats(PRUint8 aBreakType);
|
||||
// Returns the first coordinate >= aY that clears the
|
||||
// indicated floats.
|
||||
nscoord ClearFloats(nscoord aY, PRUint8 aBreakType);
|
||||
|
||||
PRBool IsAdjacentWithTop() const {
|
||||
return mY == mReflowState.mComputedBorderPadding.top;
|
||||
|
||||
@ -111,6 +111,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mSpecialHeightReflow = PR_FALSE;
|
||||
mFlags.mIsTopOfPage = PR_FALSE;
|
||||
mFlags.mNextInFlowUntouched = PR_FALSE;
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = nsnull;
|
||||
mPercentHeightReflowInitiator = nsnull;
|
||||
Init(aPresContext);
|
||||
@ -143,6 +145,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mSpecialHeightReflow = PR_FALSE;
|
||||
mFlags.mIsTopOfPage = PR_FALSE;
|
||||
mFlags.mNextInFlowUntouched = PR_FALSE;
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = nsnull;
|
||||
mPercentHeightReflowInitiator = nsnull;
|
||||
Init(aPresContext);
|
||||
@ -193,6 +197,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
@ -240,6 +246,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
@ -287,6 +295,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
|
||||
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
|
||||
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
|
||||
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
|
||||
mFlags.mHasClearance = PR_FALSE;
|
||||
mDiscoveredClearance = nsnull;
|
||||
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
|
||||
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
|
||||
? aParentReflowState.mPercentHeightObserver : nsnull;
|
||||
|
||||
@ -181,13 +181,14 @@ BreakTypeToString(PRUint8 aBreakType)
|
||||
char*
|
||||
nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const
|
||||
{
|
||||
PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,%s[0x%x]",
|
||||
PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,before:%s,after:%s[0x%x]",
|
||||
IsBlock() ? "block" : "inline",
|
||||
IsDirty() ? "dirty" : "clean",
|
||||
IsPreviousMarginDirty() ? "prevmargindirty" : "prevmarginclean",
|
||||
IsImpactedByFloat() ? "impacted" : "not impacted",
|
||||
IsLineWrapped() ? "wrapped" : "not wrapped",
|
||||
BreakTypeToString(GetBreakType()),
|
||||
BreakTypeToString(GetBreakTypeBefore()),
|
||||
BreakTypeToString(GetBreakTypeAfter()),
|
||||
mAllFlags);
|
||||
return aBuf;
|
||||
}
|
||||
@ -604,7 +605,7 @@ nsLineIterator::GetLine(PRInt32 aLineNumber,
|
||||
flags |= NS_LINE_FLAG_IS_BLOCK;
|
||||
}
|
||||
else {
|
||||
if (line->HasBreak())
|
||||
if (line->HasBreakAfter())
|
||||
flags |= NS_LINE_FLAG_ENDS_IN_BREAK;
|
||||
}
|
||||
*aLineFlags = flags;
|
||||
|
||||
@ -246,6 +246,17 @@ public:
|
||||
return mFlags.mPreviousMarginDirty;
|
||||
}
|
||||
|
||||
// mHasClearance bit
|
||||
void SetHasClearance() {
|
||||
mFlags.mHasClearance = 1;
|
||||
}
|
||||
void ClearHasClearance() {
|
||||
mFlags.mHasClearance = 0;
|
||||
}
|
||||
PRBool HasClearance() const {
|
||||
return mFlags.mHasClearance;
|
||||
}
|
||||
|
||||
// mImpactedByFloat bit
|
||||
void SetLineIsImpactedByFloat(PRBool aValue) {
|
||||
NS_ASSERTION((PR_FALSE==aValue || PR_TRUE==aValue), "somebody is playing fast and loose with bools and bits!");
|
||||
@ -300,20 +311,37 @@ public:
|
||||
}
|
||||
|
||||
// mBreakType value
|
||||
PRBool HasBreak() const {
|
||||
return NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
|
||||
// Break information is applied *before* the line if the line is a block,
|
||||
// or *after* the line if the line is an inline. Confusing, I know, but
|
||||
// using different names should help.
|
||||
PRBool HasBreakBefore() const {
|
||||
return IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
|
||||
}
|
||||
PRBool HasFloatBreak() const {
|
||||
return NS_STYLE_CLEAR_LEFT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_LEFT_AND_RIGHT == mFlags.mBreakType;
|
||||
}
|
||||
void SetBreakType(PRUint8 aBreakType) {
|
||||
NS_WARN_IF_FALSE(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
|
||||
void SetBreakTypeBefore(PRUint8 aBreakType) {
|
||||
NS_ASSERTION(IsBlock(), "Only blocks have break-before");
|
||||
NS_ASSERTION(aBreakType <= NS_STYLE_CLEAR_LEFT_AND_RIGHT,
|
||||
"Only float break types are allowed before a line");
|
||||
mFlags.mBreakType = aBreakType;
|
||||
}
|
||||
PRUint8 GetBreakType() const {
|
||||
return mFlags.mBreakType;
|
||||
PRUint8 GetBreakTypeBefore() const {
|
||||
return IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
|
||||
}
|
||||
|
||||
PRBool HasBreakAfter() const {
|
||||
return !IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
|
||||
}
|
||||
void SetBreakTypeAfter(PRUint8 aBreakType) {
|
||||
NS_ASSERTION(!IsBlock(), "Only inlines have break-after");
|
||||
NS_ASSERTION(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
|
||||
mFlags.mBreakType = aBreakType;
|
||||
}
|
||||
PRBool HasFloatBreakAfter() const {
|
||||
return !IsBlock() && (NS_STYLE_CLEAR_LEFT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType ||
|
||||
NS_STYLE_CLEAR_LEFT_AND_RIGHT == mFlags.mBreakType);
|
||||
}
|
||||
PRUint8 GetBreakTypeAfter() const {
|
||||
return !IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
|
||||
}
|
||||
|
||||
// mCarriedOutBottomMargin value
|
||||
@ -427,6 +455,7 @@ public:
|
||||
struct FlagBits {
|
||||
PRUint32 mDirty : 1;
|
||||
PRUint32 mPreviousMarginDirty : 1;
|
||||
PRUint32 mHasClearance : 1;
|
||||
PRUint32 mBlock : 1;
|
||||
PRUint32 mImpactedByFloat : 1;
|
||||
PRUint32 mHasPercentageChild : 1;
|
||||
@ -436,7 +465,7 @@ public:
|
||||
PRUint32 mEmptyCacheState: 1;
|
||||
PRUint32 mBreakType : 4;
|
||||
|
||||
PRUint32 mChildCount : 19;
|
||||
PRUint32 mChildCount : 18;
|
||||
};
|
||||
|
||||
struct ExtraData {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user