Bug 263825. Make paginated floats work, and other fixes. r+sr=dbaron

This commit is contained in:
roc+%cs.cmu.edu 2005-03-23 03:35:08 +00:00
Родитель 9a36e969fe
Коммит 30604288b9
21 изменённых файлов: 1350 добавлений и 784 удалений

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

@ -538,6 +538,7 @@ nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
NS_ASSERTION(!entry->placeholderFrame, "Registering a placeholder for a frame that already has a placeholder!"); NS_ASSERTION(!entry->placeholderFrame, "Registering a placeholder for a frame that already has a placeholder!");
entry->placeholderFrame = aPlaceholderFrame; entry->placeholderFrame = aPlaceholderFrame;
return NS_OK; return NS_OK;
} }

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

@ -144,7 +144,7 @@ LAYOUT_ATOM(overflowAreaProperty, "OverflowArea") // nsRect*
LAYOUT_ATOM(overflowProperty, "OverflowProperty") // list of nsIFrame* LAYOUT_ATOM(overflowProperty, "OverflowProperty") // list of nsIFrame*
LAYOUT_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox* LAYOUT_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox*
LAYOUT_ATOM(overflowOutOfFlowsProperty, "OverflowOutOfFlowsProperty") // nsFrameList* LAYOUT_ATOM(overflowOutOfFlowsProperty, "OverflowOutOfFlowsProperty") // nsFrameList*
LAYOUT_ATOM(overflowPlaceholdersProperty, "OverflowPlaceholdersProperty") // nsPlaceholder* LAYOUT_ATOM(overflowPlaceholdersProperty, "OverflowPlaceholdersProperty") // nsFrameList*
LAYOUT_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty") // nscoord* LAYOUT_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty") // nscoord*
LAYOUT_ATOM(spaceManagerProperty, "SpaceManagerProperty") // the space manager for a block LAYOUT_ATOM(spaceManagerProperty, "SpaceManagerProperty") // the space manager for a block
LAYOUT_ATOM(tableBCProperty, "TableBCProperty") // table border collapsing info (e.g. damage area, table border widths) LAYOUT_ATOM(tableBCProperty, "TableBCProperty") // table border collapsing info (e.g. damage area, table border widths)

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

@ -490,9 +490,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
PrettyUC(aReflowState.mComputedHeight, height); PrettyUC(aReflowState.mComputedHeight, height);
printf("c=%s,%s \n", width, height); printf("c=%s,%s \n", width, height);
} }
if (nsBlockFrame::gNoisy) { AutoNoisyIndenter indent(nsBlockFrame::gNoisy);
nsBlockFrame::gNoiseIndent++;
}
#endif // DEBUG #endif // DEBUG
nsresult rv; nsresult rv;
@ -665,11 +663,8 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
} }
} }
#ifdef DEBUG #ifdef DEBUG
if (nsBlockFrame::gNoisy) {
nsBlockFrame::gNoiseIndent--;
}
if (nsBlockFrame::gNoisyReflow) { if (nsBlockFrame::gNoisyReflow) {
nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent); nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1);
printf("abs pos "); printf("abs pos ");
if (nsnull != aKidFrame) { if (nsnull != aKidFrame) {
nsIFrameDebug* frameDebug; nsIFrameDebug* frameDebug;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -63,6 +63,32 @@ class nsIntervalSet;
#define NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX 4 #define NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX 4
#define NS_BLOCK_FRAME_LAST_LIST_INDEX NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX #define NS_BLOCK_FRAME_LAST_LIST_INDEX NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX
/**
* Some invariants:
* -- The overflow out-of-flows list contains the out-of-
* flow frames whose placeholders are in the overflow list.
* -- A given piece of content has at most one placeholder
* frame in a block's normal child list.
* -- A given piece of content can have an unlimited number
* of placeholder frames in the overflow-lines list.
* -- A line containing a continuation placeholder contains
* only continuation placeholders.
* -- While a block is being reflowed, its overflowPlaceholdersList
* frame property points to an nsFrameList in its
* nsBlockReflowState. This list contains placeholders for
* floats whose prev-in-flow is in the block's regular line
* list. The list is always empty/non-existent after the
* block has been reflowed.
* -- In all these frame lists, if there are two frames for
* the same content appearing in the list, then the frames
* appear with the prev-in-flow before the next-in-flow.
* -- While reflowing a block, its overflow line list
* will usually be empty but in some cases will have lines
* (while we reflow the block at its shrink-wrap width).
* In this case any new overflowing content must be
* prepended to the overflow lines.
*/
// see nsHTMLParts.h for the public block state bits // see nsHTMLParts.h for the public block state bits
#define NS_BLOCK_HAS_LINE_CURSOR 0x01000000 #define NS_BLOCK_HAS_LINE_CURSOR 0x01000000
#define NS_BLOCK_HAS_OVERFLOW_LINES 0x02000000 #define NS_BLOCK_HAS_OVERFLOW_LINES 0x02000000
@ -222,9 +248,11 @@ public:
virtual void DeleteNextInFlowChild(nsPresContext* aPresContext, virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
nsIFrame* aNextInFlow); nsIFrame* aNextInFlow);
// Determines whether the collapsed margin carried out of the last /**
// line includes the margin-top of a line with clearance (in which * Determines whether the collapsed margin carried out of the last
// case we must avoid collapsing that margin with our bottom margin) * 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(); PRBool CheckForCollapsedBottomMarginFromClearanceLine();
/** return the topmost block child based on y-index. /** return the topmost block child based on y-index.
@ -243,7 +271,7 @@ public:
// Create a contination for aPlaceholder and its out of flow frame and // Create a contination for aPlaceholder and its out of flow frame and
// add it to the list of overflow floats // add it to the list of overflow floats
nsresult SplitPlaceholder(nsPresContext& aPresContext, nsIFrame& aPlaceholder); nsresult SplitPlaceholder(nsBlockReflowState& aState, nsIFrame* aPlaceholder);
void UndoSplitPlaceholders(nsBlockReflowState& aState, void UndoSplitPlaceholders(nsBlockReflowState& aState,
nsIFrame* aLastPlaceholder); nsIFrame* aLastPlaceholder);
@ -258,6 +286,12 @@ public:
aDirtyRect, aFrame, aWhichLayer, aFlags); aDirtyRect, aFrame, aWhichLayer, aFlags);
} }
PRBool HandleOverflowPlaceholdersForPulledFrame(
nsBlockReflowState& aState, nsIFrame* aFrame);
PRBool HandleOverflowPlaceholdersOnPulledLine(
nsBlockReflowState& aState, nsLineBox* aLine);
protected: protected:
nsBlockFrame(); nsBlockFrame();
virtual ~nsBlockFrame(); virtual ~nsBlockFrame();
@ -331,18 +365,23 @@ protected:
nsresult AddFrames(nsIFrame* aFrameList, nsresult AddFrames(nsIFrame* aFrameList,
nsIFrame* aPrevSibling); nsIFrame* aPrevSibling);
public:
/** does all the real work for removing aDeletedFrame from this /** does all the real work for removing aDeletedFrame from this
* finds the line containing aFrame. * finds the line containing aFrame.
* handled continued frames * handled continued frames
* marks lines dirty as needed * marks lines dirty as needed
* @param aDestroyFrames if false then we don't actually destroy the
* frame or its next in flows, we just remove them. This does NOT work
* on out of flow frames so always use PR_TRUE for out of flows.
*/ */
nsresult DoRemoveFrame(nsIFrame* aDeletedFrame); nsresult DoRemoveFrame(nsIFrame* aDeletedFrame, PRBool aDestroyFrames = PR_TRUE);
protected:
/** grab overflow lines from this block's prevInFlow, and make them /** grab overflow lines from this block's prevInFlow, and make them
* part of this block's mLines list. * part of this block's mLines list.
* @return PR_TRUE if any lines were drained. * @return PR_TRUE if any lines were drained.
*/ */
PRBool DrainOverflowLines(); PRBool DrainOverflowLines(nsBlockReflowState& aState);
/** /**
* Remove a float from our float list and also the float cache * Remove a float from our float list and also the float cache
@ -350,6 +389,8 @@ protected:
*/ */
line_iterator RemoveFloat(nsIFrame* aFloat); line_iterator RemoveFloat(nsIFrame* aFloat);
void CollectFloats(nsIFrame* aFrame, nsFrameList& aList, nsIFrame** aTail,
PRBool aFromOverflow);
// Remove a float, abs, rel positioned frame from the appropriate block's list // Remove a float, abs, rel positioned frame from the appropriate block's list
static void DoRemoveOutOfFlowFrame(nsIFrame* aFrame); static void DoRemoveOutOfFlowFrame(nsIFrame* aFrame);
@ -391,8 +432,11 @@ protected:
*/ */
nsresult PrepareResizeReflow(nsBlockReflowState& aState); nsresult PrepareResizeReflow(nsBlockReflowState& aState);
/** reflow all lines that have been marked dirty */ /** reflow all lines that have been marked dirty.
nsresult ReflowDirtyLines(nsBlockReflowState& aState); * @param aTryPull set this to PR_TRUE if you want to try pulling content from
* our next in flow while there is room.
*/
nsresult ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull);
//---------------------------------------- //----------------------------------------
// Methods for line reflow // Methods for line reflow
@ -498,13 +542,13 @@ protected:
PRBool aDamageDeletedLine, PRBool aDamageDeletedLine,
nsIFrame*& aFrameResult); nsIFrame*& aFrameResult);
nsresult PullFrameFrom(nsBlockReflowState& aState, PRBool PullFrameFrom(nsBlockReflowState& aState,
nsLineBox* aLine, nsLineBox* aLine,
nsBlockFrame* aFromContainer, nsBlockFrame* aFromContainer,
PRBool aFromOverflowLine, PRBool aFromOverflowLine,
nsLineList::iterator aFromLine, nsLineList::iterator aFromLine,
PRBool aDamageDeletedLines, PRBool aDamageDeletedLines,
nsIFrame*& aFrameResult); nsIFrame*& aFrameResult);
void PushLines(nsBlockReflowState& aState, void PushLines(nsBlockReflowState& aState,
nsLineList::iterator aLineBefore); nsLineList::iterator aLineBefore);
@ -552,17 +596,39 @@ protected:
//---------------------------------------- //----------------------------------------
public:
nsLineList* GetOverflowLines() const; nsLineList* GetOverflowLines() const;
protected:
nsLineList* RemoveOverflowLines(); nsLineList* RemoveOverflowLines();
nsresult SetOverflowLines(nsLineList* aOverflowLines); nsresult SetOverflowLines(nsLineList* aOverflowLines);
nsFrameList* GetOverflowPlaceholders() const; nsFrameList* GetOverflowPlaceholders() const;
nsFrameList* RemoveOverflowPlaceholders();
nsresult SetOverflowPlaceholders(nsFrameList* aOverflowPlaceholders);
nsFrameList* GetOverflowOutOfFlows() const; /**
nsFrameList* RemoveOverflowOutOfFlows(); * This class is useful for efficiently modifying the out of flow
nsresult SetOverflowOutOfFlows(nsFrameList* aFloaters); * overflow list. It gives the client direct writable access to
* the frame list temporarily but ensures that property is only
* written back if absolutely necessary.
*/
struct nsAutoOOFFrameList {
nsFrameList mList;
nsAutoOOFFrameList(nsBlockFrame* aBlock) :
mList(aBlock->GetOverflowOutOfFlows().FirstChild()),
aOldHead(mList.FirstChild()), mBlock(aBlock) {}
~nsAutoOOFFrameList() {
if (mList.FirstChild() != aOldHead) {
mBlock->SetOverflowOutOfFlows(mList);
}
}
protected:
nsIFrame* aOldHead;
nsBlockFrame* mBlock;
};
friend class nsAutoOOFFrameList;
nsFrameList GetOverflowOutOfFlows() const;
void SetOverflowOutOfFlows(const nsFrameList& aList);
nsIFrame* LastChild(); nsIFrame* LastChild();
@ -613,5 +679,23 @@ protected:
#endif #endif
}; };
#ifdef DEBUG
class AutoNoisyIndenter {
public:
AutoNoisyIndenter(PRBool aDoIndent) : mIndented(aDoIndent) {
if (mIndented) {
nsBlockFrame::gNoiseIndent++;
}
}
~AutoNoisyIndenter() {
if (mIndented) {
nsBlockFrame::gNoiseIndent--;
}
}
private:
PRBool mIndented;
};
#endif
#endif /* nsBlockFrame_h___ */ #endif /* nsBlockFrame_h___ */

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

@ -107,55 +107,79 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
if (0 == aRS.mComputedBorderPadding.top && if (0 == aRS.mComputedBorderPadding.top &&
!(aRS.frame->GetStateBits() & NS_BLOCK_MARGIN_ROOT) && !(aRS.frame->GetStateBits() & NS_BLOCK_MARGIN_ROOT) &&
NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, &bf))) { NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, &bf))) {
nsBlockFrame* block = NS_STATIC_CAST(nsBlockFrame*, aRS.frame); // iterate not just through the lines of 'block' but also its
// overflow lines and the normal and overflow lines of its next in
for (nsBlockFrame::line_iterator line = block->begin_lines(), // flows. Note that this will traverse some frames more than once:
line_end = block->end_lines(); // for example, if A contains B and A->nextinflow contains
line != line_end; ++line) { // B->nextinflow, we'll traverse B->nextinflow twice. But this is
if (!aClearanceFrame && line->HasClearance()) { // OK because our traversal is idempotent.
// If we don't have a clearance frame, then we're computing for (nsBlockFrame* block = NS_STATIC_CAST(nsBlockFrame*, aRS.frame);
// the collapsed margin in the first pass, assuming that all block; block = NS_STATIC_CAST(nsBlockFrame*, block->GetNextInFlow())) {
// lines have no clearance. So clear their clearance flags. for (PRBool overflowLines = PR_FALSE; overflowLines <= PR_TRUE; ++overflowLines) {
line->ClearHasClearance(); nsBlockFrame::line_iterator line;
line->MarkDirty(); nsBlockFrame::line_iterator line_end;
dirtiedLine = PR_TRUE; PRBool anyLines = PR_TRUE;
if (overflowLines) {
nsLineList* lines = block->GetOverflowLines();
if (!lines) {
anyLines = PR_FALSE;
} else {
line = lines->begin();
line_end = lines->end();
}
} else {
line = block->begin_lines();
line_end = block->end_lines();
}
for (; anyLines && 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;
goto done;
}
// 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)
goto done;
}
} }
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;
} }
done:
;
} }
#ifdef NOISY_VERTICAL_MARGINS #ifdef NOISY_VERTICAL_MARGINS
@ -624,7 +648,9 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
if (nsnull != kidNextInFlow) { if (nsnull != kidNextInFlow) {
// Remove all of the childs next-in-flows. Make sure that we ask // Remove all of the childs next-in-flows. Make sure that we ask
// the right parent to do the removal (it's possible that the // the right parent to do the removal (it's possible that the
// parent is not this because we are executing pullup code) // parent is not this because we are executing pullup code).
// Floats will eventually be removed via nsBlockFrame::RemoveFloat
// which detaches the placeholder from the float.
/* XXX promote DeleteChildsNextInFlow to nsIFrame to elminate this cast */ /* XXX promote DeleteChildsNextInFlow to nsIFrame to elminate this cast */
NS_STATIC_CAST(nsHTMLContainerFrame*, kidNextInFlow->GetParent()) NS_STATIC_CAST(nsHTMLContainerFrame*, kidNextInFlow->GetParent())
->DeleteNextInFlowChild(mPresContext, kidNextInFlow); ->DeleteNextInFlowChild(mPresContext, kidNextInFlow);
@ -654,17 +680,20 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
const nsMargin& aComputedOffsets, const nsMargin& aComputedOffsets,
nsCollapsingMargin& aBottomMarginResult, nsCollapsingMargin& aBottomMarginResult,
nsRect& aInFlowBounds, nsRect& aInFlowBounds,
nsRect& aCombinedRect) nsRect& aCombinedRect,
nsReflowStatus aReflowStatus)
{ {
// Compute collapsed bottom margin value // Compute collapsed bottom margin value.
aBottomMarginResult = mMetrics.mCarriedOutBottomMargin; if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
aBottomMarginResult.Include(mMargin.bottom); aBottomMarginResult = mMetrics.mCarriedOutBottomMargin;
aBottomMarginResult.Include(mMargin.bottom);
} else {
// The used bottom-margin is set to zero above a break.
aBottomMarginResult.Zero();
}
// See if the block will fit in the available space
PRBool fits;
nscoord x = mX; nscoord x = mX;
nscoord y = mY; nscoord y = mY;
nscoord backupContainingBlockAdvance = 0; nscoord backupContainingBlockAdvance = 0;
// Check whether the block's bottom margin collapses with its top // Check whether the block's bottom margin collapses with its top
@ -673,11 +702,12 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
// check that first. Note that a block can have clearance and still // check that first. Note that a block can have clearance and still
// have adjoining top/bottom margins, because the clearance goes // have adjoining top/bottom margins, because the clearance goes
// above the top margin. // above the top margin.
if (0 == mMetrics.height && aLine->CachedIsEmpty()) PRBool empty = 0 == mMetrics.height && aLine->CachedIsEmpty();
{ if (empty) {
// Collapse the bottom margin with the top margin that was already // Collapse the bottom margin with the top margin that was already
// applied. // applied.
aBottomMarginResult.Include(mTopMargin); aBottomMarginResult.Include(mTopMargin);
#ifdef NOISY_VERTICAL_MARGINS #ifdef NOISY_VERTICAL_MARGINS
printf(" "); printf(" ");
nsFrame::ListTag(stdout, mOuterReflowState.frame); nsFrame::ListTag(stdout, mOuterReflowState.frame);
@ -686,10 +716,6 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n", printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n",
y, mSpace.y); y, mSpace.y);
#endif #endif
// Empty blocks always fit
fits = PR_TRUE;
// Section 8.3.1 of CSS 2.1 says that blocks with adjoining // Section 8.3.1 of CSS 2.1 says that blocks with adjoining
// top/bottom margins whose top margin collapses with their // top/bottom margins whose top margin collapses with their
// parent's top margin should have their top border-edge at the // parent's top margin should have their top border-edge at the
@ -709,97 +735,92 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
// point from where this empty block will be. // point from where this empty block will be.
backupContainingBlockAdvance = mTopMargin.get(); backupContainingBlockAdvance = mTopMargin.get();
} }
else {
// See if the frame fit. If it's the first frame then it always
// fits. If the height is unconstrained then it always fits, even
// if there's some sort of integer overflow that makes
// y + mMetrics.height appear to go beyond the available height.
// XXX This is a bit of a hack. We really need to use floats in layout!
if (aForceFit ||
mSpace.height == NS_UNCONSTRAINEDSIZE ||
y + mMetrics.height <= mSpace.YMost())
{
fits = PR_TRUE;
// Adjust the max-element-size in the metrics to take into // See if the frame fit. If it's the first frame or empty then it
// account the margins around the block element. // always fits. If the height is unconstrained then it always fits,
// Do not allow auto margins to impact the max-element size // even if there's some sort of integer overflow that makes y +
// since they are springy and don't really count! // mMetrics.height appear to go beyond the available height.
if (mMetrics.mComputeMEW) { if (!empty && !aForceFit && mSpace.height != NS_UNCONSTRAINEDSIZE) {
nsMargin maxElemMargin; nscoord yMost = y - backupContainingBlockAdvance + mMetrics.height;
const nsStyleSides &styleMargin = mStyleMargin->mMargin; if (yMost > mSpace.YMost()) {
nsStyleCoord coord; // didn't fit, we must acquit.
if (styleMargin.GetLeftUnit() == eStyleUnit_Coord)
maxElemMargin.left = styleMargin.GetLeft(coord).GetCoordValue();
else
maxElemMargin.left = 0;
if (styleMargin.GetRightUnit() == eStyleUnit_Coord)
maxElemMargin.right = styleMargin.GetRight(coord).GetCoordValue();
else
maxElemMargin.right = 0;
nscoord dummyXOffset;
// Base the margins on the max-element size
ComputeShrinkwrapMargins(mStyleMargin, mMetrics.mMaxElementWidth,
maxElemMargin, dummyXOffset);
mMetrics.mMaxElementWidth += maxElemMargin.left + maxElemMargin.right;
}
// do the same for the maximum width
if (mComputeMaximumWidth) {
nsMargin maxWidthMargin;
const nsStyleSides &styleMargin = mStyleMargin->mMargin;
nsStyleCoord coord;
if (styleMargin.GetLeftUnit() == eStyleUnit_Coord)
maxWidthMargin.left = styleMargin.GetLeft(coord).GetCoordValue();
else
maxWidthMargin.left = 0;
if (styleMargin.GetRightUnit() == eStyleUnit_Coord)
maxWidthMargin.right = styleMargin.GetRight(coord).GetCoordValue();
else
maxWidthMargin.right = 0;
nscoord dummyXOffset;
// Base the margins on the maximum width
ComputeShrinkwrapMargins(mStyleMargin, mMetrics.mMaximumWidth,
maxWidthMargin, dummyXOffset);
mMetrics.mMaximumWidth += maxWidthMargin.left + maxWidthMargin.right;
}
}
else {
// Send the DidReflow() notification, but don't bother placing
// the frame
mFrame->DidReflow(mPresContext, &aReflowState, NS_FRAME_REFLOW_FINISHED); mFrame->DidReflow(mPresContext, &aReflowState, NS_FRAME_REFLOW_FINISHED);
fits = PR_FALSE; return PR_FALSE;
} }
} }
if (fits) { if (!empty)
// Calculate the actual x-offset and left and right margin {
nsBlockHorizontalAlign align; // Adjust the max-element-size in the metrics to take into
align.mXOffset = x; // account the margins around the block element.
AlignBlockHorizontally(mMetrics.width, align); // Do not allow auto margins to impact the max-element size
x = align.mXOffset; // since they are springy and don't really count!
mMargin.left = align.mLeftMargin; if (mMetrics.mComputeMEW) {
mMargin.right = align.mRightMargin; nsMargin maxElemMargin;
const nsStyleSides &styleMargin = mStyleMargin->mMargin;
nsStyleCoord coord;
if (styleMargin.GetLeftUnit() == eStyleUnit_Coord)
maxElemMargin.left = styleMargin.GetLeft(coord).GetCoordValue();
else
maxElemMargin.left = 0;
if (styleMargin.GetRightUnit() == eStyleUnit_Coord)
maxElemMargin.right = styleMargin.GetRight(coord).GetCoordValue();
else
maxElemMargin.right = 0;
nscoord dummyXOffset;
// Base the margins on the max-element size
ComputeShrinkwrapMargins(mStyleMargin, mMetrics.mMaxElementWidth,
maxElemMargin, dummyXOffset);
mMetrics.mMaxElementWidth += maxElemMargin.left + maxElemMargin.right;
}
aInFlowBounds = nsRect(x, y - backupContainingBlockAdvance, // do the same for the maximum width
mMetrics.width, mMetrics.height); if (mComputeMaximumWidth) {
nsMargin maxWidthMargin;
// Apply CSS relative positioning const nsStyleSides &styleMargin = mStyleMargin->mMargin;
const nsStyleDisplay* styleDisp = mFrame->GetStyleDisplay(); nsStyleCoord coord;
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) { if (styleMargin.GetLeftUnit() == eStyleUnit_Coord)
x += aComputedOffsets.left; maxWidthMargin.left = styleMargin.GetLeft(coord).GetCoordValue();
y += aComputedOffsets.top; else
maxWidthMargin.left = 0;
if (styleMargin.GetRightUnit() == eStyleUnit_Coord)
maxWidthMargin.right = styleMargin.GetRight(coord).GetCoordValue();
else
maxWidthMargin.right = 0;
nscoord dummyXOffset;
// Base the margins on the maximum width
ComputeShrinkwrapMargins(mStyleMargin, mMetrics.mMaximumWidth,
maxWidthMargin, dummyXOffset);
mMetrics.mMaximumWidth += maxWidthMargin.left + maxWidthMargin.right;
} }
// Now place the frame and complete the reflow process
nsContainerFrame::FinishReflowChild(mFrame, mPresContext, &aReflowState, mMetrics, x, y, 0);
aCombinedRect = mMetrics.mOverflowArea + nsPoint(x, y);
} }
return fits; // Calculate the actual x-offset and left and right margin
nsBlockHorizontalAlign align;
align.mXOffset = x;
AlignBlockHorizontally(mMetrics.width, align);
x = align.mXOffset;
mMargin.left = align.mLeftMargin;
mMargin.right = align.mRightMargin;
aInFlowBounds = nsRect(x, y - backupContainingBlockAdvance,
mMetrics.width, mMetrics.height);
// Apply CSS relative positioning
const nsStyleDisplay* styleDisp = mFrame->GetStyleDisplay();
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
x += aComputedOffsets.left;
y += aComputedOffsets.top;
}
// Now place the frame and complete the reflow process
nsContainerFrame::FinishReflowChild(mFrame, mPresContext, &aReflowState, mMetrics, x, y, 0);
aCombinedRect = mMetrics.mOverflowArea + nsPoint(x, y);
return PR_TRUE;
} }

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

@ -77,7 +77,8 @@ public:
const nsMargin& aComputedOffsets, const nsMargin& aComputedOffsets,
nsCollapsingMargin& aBottomMarginResult /* out */, nsCollapsingMargin& aBottomMarginResult /* out */,
nsRect& aInFlowBounds, nsRect& aInFlowBounds,
nsRect& aCombinedRect); nsRect& aCombinedRect,
nsReflowStatus aReflowStatus);
void AlignBlockHorizontally(nscoord aWidth, nsBlockHorizontalAlign&); void AlignBlockHorizontally(nscoord aWidth, nsBlockHorizontalAlign&);

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

@ -72,6 +72,12 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
{ {
const nsMargin& borderPadding = BorderPadding(); const nsMargin& borderPadding = BorderPadding();
if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
mBlock->SetProperty(nsLayoutAtoms::overflowPlaceholdersProperty,
&mOverflowPlaceholders, nsnull);
mBlock->AddStateBits(NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS);
}
if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) { if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) {
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE); SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
} }
@ -172,6 +178,11 @@ nsBlockReflowState::~nsBlockReflowState()
const nsMargin& borderPadding = BorderPadding(); const nsMargin& borderPadding = BorderPadding();
mSpaceManager->Translate(-borderPadding.left, -borderPadding.top); mSpaceManager->Translate(-borderPadding.left, -borderPadding.top);
} }
if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
mBlock->UnsetProperty(nsLayoutAtoms::overflowPlaceholdersProperty);
mBlock->RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS);
}
} }
nsLineBox* nsLineBox*
@ -543,7 +554,7 @@ nsBlockReflowState::IsImpactedByFloat() const
} }
void PRBool
nsBlockReflowState::InitFloat(nsLineLayout& aLineLayout, nsBlockReflowState::InitFloat(nsLineLayout& aLineLayout,
nsPlaceholderFrame* aPlaceholder, nsPlaceholderFrame* aPlaceholder,
nsReflowStatus& aReflowStatus) nsReflowStatus& aReflowStatus)
@ -554,7 +565,7 @@ nsBlockReflowState::InitFloat(nsLineLayout& aLineLayout,
// Then add the float to the current line and place it when // Then add the float to the current line and place it when
// appropriate // appropriate
AddFloat(aLineLayout, aPlaceholder, PR_TRUE, aReflowStatus); return AddFloat(aLineLayout, aPlaceholder, PR_TRUE, aReflowStatus);
} }
// This is called by the line layout's AddFloat method when a // This is called by the line layout's AddFloat method when a
@ -567,7 +578,7 @@ nsBlockReflowState::InitFloat(nsLineLayout& aLineLayout,
// technically we're supposed let the current line flow around the // technically we're supposed let the current line flow around the
// float as well unless it won't fit next to what we already have. // float as well unless it won't fit next to what we already have.
// But nobody else implements it that way... // But nobody else implements it that way...
void PRBool
nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout, nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
nsPlaceholderFrame* aPlaceholder, nsPlaceholderFrame* aPlaceholder,
PRBool aInitialReflow, PRBool aInitialReflow,
@ -582,12 +593,11 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
fc->mIsCurrentLineFloat = aLineLayout.CanPlaceFloatNow(); fc->mIsCurrentLineFloat = aLineLayout.CanPlaceFloatNow();
fc->mMaxElementWidth = 0; fc->mMaxElementWidth = 0;
PRBool placed;
// Now place the float immediately if possible. Otherwise stash it // Now place the float immediately if possible. Otherwise stash it
// away in mPendingFloats and place it later. // away in mPendingFloats and place it later.
if (fc->mIsCurrentLineFloat) { if (fc->mIsCurrentLineFloat) {
// Record this float in the current-line list
mCurrentLineFloats.Append(fc);
// Because we are in the middle of reflowing a placeholder frame // Because we are in the middle of reflowing a placeholder frame
// within a line (and possibly nested in an inline frame or two // 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 // that's a child of our block) we need to restore the space
@ -601,15 +611,19 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
// And then place it // And then place it
PRBool isLeftFloat; PRBool isLeftFloat;
FlowAndPlaceFloat(fc, &isLeftFloat, aReflowStatus); placed = FlowAndPlaceFloat(fc, &isLeftFloat, aReflowStatus);
if (placed) {
// Pass on updated available space to the current inline reflow engine // Pass on updated available space to the current inline reflow engine
GetAvailableSpace(); GetAvailableSpace();
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY, aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width, GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
mAvailSpaceRect.height, mAvailSpaceRect.height,
isLeftFloat, isLeftFloat,
aPlaceholder->GetOutOfFlowFrame()); aPlaceholder->GetOutOfFlowFrame());
// Record this float in the current-line list
mCurrentLineFloats.Append(fc);
}
// Restore coordinate system // Restore coordinate system
mSpaceManager->Translate(dx, dy); mSpaceManager->Translate(dx, dy);
@ -618,7 +632,16 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
// This float will be placed after the line is done (it is a // This float will be placed after the line is done (it is a
// below-current-line float). // below-current-line float).
mBelowCurrentLineFloats.Append(fc); mBelowCurrentLineFloats.Append(fc);
if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
// If the float might not be complete, mark it incomplete now to
// prevent the placeholders being torn down. We will destroy any
// placeholders later if PlaceBelowCurrentLineFloats finds the
// float is complete.
aReflowStatus = NS_FRAME_NOT_COMPLETE;
}
placed = PR_TRUE;
} }
return placed;
} }
void void
@ -716,6 +739,12 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
nscoord saveY = mY; nscoord saveY = mY;
for (;;) { for (;;) {
// Get the available space at the new Y coordinate // Get the available space at the new Y coordinate
if (mAvailSpaceRect.height <= 0) {
// there is no more available space. We lose.
result = PR_FALSE;
break;
}
mY += mAvailSpaceRect.height; mY += mAvailSpaceRect.height;
GetAvailableSpace(); GetAvailableSpace();
@ -752,7 +781,7 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
return result; return result;
} }
void PRBool
nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
PRBool* aIsLeftFloat, PRBool* aIsLeftFloat,
nsReflowStatus& aReflowStatus) nsReflowStatus& aReflowStatus)
@ -821,6 +850,12 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
PRBool keepFloatOnSameLine = PR_FALSE; PRBool keepFloatOnSameLine = PR_FALSE;
while (! CanPlaceFloat(floatSize, floatDisplay->mFloats)) { while (! CanPlaceFloat(floatSize, floatDisplay->mFloats)) {
if (mAvailSpaceRect.height <= 0) {
// No space, nowhere to put anything.
mY = saveY;
return PR_FALSE;
}
// Nope. try to advance to the next band. // Nope. try to advance to the next band.
if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay || if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) { eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) {
@ -880,25 +915,10 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
} }
// If the float is continued, it will get the same absolute x value as its prev-in-flow // If the float is continued, it will get the same absolute x value as its prev-in-flow
nsRect prevRect(0,0,0,0); nsRect prevRect(0,0,0,0);
nsIFrame* prevInFlow = floatFrame->GetPrevInFlow();
if (prevInFlow) {
prevRect = prevInFlow->GetRect();
// If prevInFlow's placeholder is in a block that wasn't continued, we need to adjust // We don't worry about the geometry of the prev in flow, let the continuation
// prevRect.x to account for the missing frame offsets. // place and size itself as required.
nsIFrame* placeParent = placeholder->GetParent();
nsIFrame* placeParentPrev = placeParent->GetPrevInFlow();
nsIFrame* prevPlace =
mPresContext->FrameManager()->GetPlaceholderFrameFor(prevInFlow);
nsIFrame* prevPlaceParent = prevPlace->GetParent();
for (nsIFrame* ancestor = prevPlaceParent;
ancestor && (ancestor != placeParentPrev);
ancestor = ancestor->GetParent()) {
prevRect.x += ancestor->GetRect().x;
}
}
// Assign an x and y coordinate to the float. Note that the x,y // Assign an x and y coordinate to the float. Note that the x,y
// coordinates are computed <b>relative to the translation in the // coordinates are computed <b>relative to the translation in the
// spacemanager</b> which means that the impacted region will be // spacemanager</b> which means that the impacted region will be
@ -907,15 +927,12 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
nscoord floatX, floatY; nscoord floatX, floatY;
if (NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) { if (NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) {
isLeftFloat = PR_TRUE; isLeftFloat = PR_TRUE;
floatX = (prevInFlow) ? prevRect.x : mAvailSpaceRect.x; floatX = mAvailSpaceRect.x;
} }
else { else {
isLeftFloat = PR_FALSE; isLeftFloat = PR_FALSE;
if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.width) { if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.width) {
if (prevInFlow) { if (!keepFloatOnSameLine) {
floatX = prevRect.x;
}
else if (!keepFloatOnSameLine) {
floatX = mAvailSpaceRect.XMost() - floatSize.width; floatX = mAvailSpaceRect.XMost() - floatSize.width;
} }
else { else {
@ -947,7 +964,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
// if the float split, then take up all of the vertical height // if the float split, then take up all of the vertical height
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) &&
(NS_UNCONSTRAINEDSIZE != mContentArea.height)) { (NS_UNCONSTRAINEDSIZE != mContentArea.height)) {
floatSize.height = PR_MAX(floatSize.height, mContentArea.height); floatSize.height = PR_MAX(floatSize.height, mContentArea.height - floatY);
} }
nsRect region(floatX, floatY, floatSize.width, floatSize.height); nsRect region(floatX, floatY, floatSize.width, floatSize.height);
@ -1041,6 +1058,8 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height); printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
} }
#endif #endif
return PR_TRUE;
} }
/** /**
@ -1066,17 +1085,25 @@ nsBlockReflowState::PlaceBelowCurrentLineFloats(nsFloatCacheList& aList)
// Place the float // Place the float
PRBool isLeftFloat; PRBool isLeftFloat;
nsReflowStatus reflowStatus; nsReflowStatus reflowStatus;
FlowAndPlaceFloat(fc, &isLeftFloat, reflowStatus); PRBool placed = FlowAndPlaceFloat(fc, &isLeftFloat, reflowStatus);
if (NS_FRAME_IS_TRUNCATED(reflowStatus)) { if (!placed || NS_FRAME_IS_TRUNCATED(reflowStatus)) {
// return before processing all of the floats, since the line will be pushed. // return before processing all of the floats, since the line will be pushed.
return PR_FALSE; return PR_FALSE;
} }
else if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus)) { else if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus)) {
// Create a continuation for the incomplete float and its placeholder. // Create a continuation for the incomplete float and its placeholder.
nsresult rv = mBlock->SplitPlaceholder(*mPresContext, *fc->mPlaceholder); nsresult rv = mBlock->SplitPlaceholder(*this, fc->mPlaceholder);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return PR_FALSE; return PR_FALSE;
} else {
// Float is complete. We need to delete any leftover placeholders now.
nsIFrame* nextPlaceholder = fc->mPlaceholder->GetNextInFlow();
if (nextPlaceholder) {
nsHTMLContainerFrame* parent =
NS_STATIC_CAST(nsHTMLContainerFrame*, nextPlaceholder->GetParent());
parent->DeleteNextInFlowChild(mPresContext, nextPlaceholder);
}
} }
} }
fc = fc->Next(); fc = fc->Next();

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

@ -68,21 +68,22 @@ public:
void GetAvailableSpace(nscoord aY); void GetAvailableSpace(nscoord aY);
void InitFloat(nsLineLayout& aLineLayout, /*
nsPlaceholderFrame* aPlaceholderFrame, * The following functions all return PR_TRUE if they were able to
nsReflowStatus& aReflowStatus); * place the float, PR_FALSE if the float did not fit in available
* space.
void AddFloat(nsLineLayout& aLineLayout, */
nsPlaceholderFrame* aPlaceholderFrame, PRBool InitFloat(nsLineLayout& aLineLayout,
PRBool aInitialReflow, nsPlaceholderFrame* aPlaceholderFrame,
nsReflowStatus& aReflowStatus); nsReflowStatus& aReflowStatus);
PRBool AddFloat(nsLineLayout& aLineLayout,
nsPlaceholderFrame* aPlaceholderFrame,
PRBool aInitialReflow,
nsReflowStatus& aReflowStatus);
PRBool CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats); PRBool CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats);
PRBool FlowAndPlaceFloat(nsFloatCache* aFloatCache,
void FlowAndPlaceFloat(nsFloatCache* aFloatCache, PRBool* aIsLeftFloat,
PRBool* aIsLeftFloat, nsReflowStatus& aReflowStatus);
nsReflowStatus& aReflowStatus);
PRBool PlaceBelowCurrentLineFloats(nsFloatCacheList& aFloats); PRBool PlaceBelowCurrentLineFloats(nsFloatCacheList& aFloats);
// Returns the first coordinate >= aY that clears the // Returns the first coordinate >= aY that clears the
@ -162,6 +163,10 @@ public:
// unconstrained area. // unconstrained area.
nsSize mContentArea; nsSize mContentArea;
// Placeholders for continuation out-of-flow frames that need to
// move to our next in flow are placed here during reflow.
nsFrameList mOverflowPlaceholders;
//---------------------------------------- //----------------------------------------
// This state is "running" state updated by the reflow of each line // This state is "running" state updated by the reflow of each line

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

@ -69,6 +69,10 @@ public:
NS_IMETHOD RemoveFrame(nsIAtom* aListName, NS_IMETHOD RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame); nsIFrame* aOldFrame);
NS_IMETHOD GetFrameForPoint(const nsPoint& aPoint,
nsFramePaintLayer aWhichLayer,
nsIFrame** aFrame);
virtual nsIFrame* GetContentInsertionFrame() { virtual nsIFrame* GetContentInsertionFrame() {
return GetFirstChild(nsnull)->GetContentInsertionFrame(); return GetFirstChild(nsnull)->GetContentInsertionFrame();
} }
@ -163,6 +167,16 @@ nsColumnSetFrame::GetType() const
return nsLayoutAtoms::columnSetFrame; return nsLayoutAtoms::columnSetFrame;
} }
NS_IMETHODIMP
nsColumnSetFrame::GetFrameForPoint(const nsPoint& aPoint,
nsFramePaintLayer aWhichLayer,
nsIFrame** aFrame)
{
// This frame counts as part of the background.
return GetFrameForPointUsing(aPoint, nsnull, aWhichLayer,
(aWhichLayer == NS_FRAME_PAINT_LAYER_BACKGROUND), aFrame);
}
NS_IMETHODIMP NS_IMETHODIMP
nsColumnSetFrame::SetInitialChildList(nsPresContext* aPresContext, nsColumnSetFrame::SetInitialChildList(nsPresContext* aPresContext,
nsIAtom* aListName, nsIAtom* aListName,
@ -260,6 +274,9 @@ nsColumnSetFrame::ChooseColumnStrategy(const nsHTMLReflowState& aReflowState)
// colWidth*nominalColumnCount is nearly availContentWidth // colWidth*nominalColumnCount is nearly availContentWidth
// make sure to round down // make sure to round down
numColumns = (availContentWidth + colGap)/(colGap + colWidth); numColumns = (availContentWidth + colGap)/(colGap + colWidth);
if (numColumns <= 0) {
numColumns = 1;
}
} }
// Compute extra space and divide it among the columns // Compute extra space and divide it among the columns

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

@ -638,6 +638,20 @@ nsFrame::Destroy(nsPresContext* aPresContext)
nsIPresShell *shell = aPresContext->GetPresShell(); nsIPresShell *shell = aPresContext->GetPresShell();
if (shell) { if (shell) {
if (mState & NS_FRAME_OUT_OF_FLOW) {
nsPlaceholderFrame* placeholder
= shell->FrameManager()->GetPlaceholderFrameFor(this);
if (placeholder) {
NS_WARNING("Deleting out of flow without tearing down placeholder relationship");
if (placeholder->GetOutOfFlowFrame()) {
NS_ASSERTION(placeholder->GetOutOfFlowFrame() == this,
"no-one told the frame manager about this");
shell->FrameManager()->UnregisterPlaceholderFrame(placeholder);
placeholder->SetOutOfFlowFrame(nsnull);
}
}
}
// If the frame contains generated context, remove it from // If the frame contains generated context, remove it from
// the quoteList. // the quoteList.
if (mState & NS_FRAME_GENERATED_CONTENT) { if (mState & NS_FRAME_GENERATED_CONTENT) {
@ -2724,6 +2738,14 @@ nsFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
if (0 != mState) { if (0 != mState) {
fprintf(out, " [state=%08x]", mState); fprintf(out, " [state=%08x]", mState);
} }
nsIFrame* prevInFlow = GetPrevInFlow();
nsIFrame* nextInFlow = GetNextInFlow();
if (nsnull != prevInFlow) {
fprintf(out, " prev-in-flow=%p", NS_STATIC_CAST(void*, prevInFlow));
}
if (nsnull != nextInFlow) {
fprintf(out, " next-in-flow=%p", NS_STATIC_CAST(void*, nextInFlow));
}
fprintf(out, " [content=%p]", NS_STATIC_CAST(void*, mContent)); fprintf(out, " [content=%p]", NS_STATIC_CAST(void*, mContent));
nsFrame* f = NS_CONST_CAST(nsFrame*, this); nsFrame* f = NS_CONST_CAST(nsFrame*, this);
nsRect* overflowArea = f->GetOverflowAreaProperty(PR_FALSE); nsRect* overflowArea = f->GetOverflowAreaProperty(PR_FALSE);

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

@ -39,6 +39,8 @@
#ifdef NS_DEBUG #ifdef NS_DEBUG
#include "nsIFrameDebug.h" #include "nsIFrameDebug.h"
#endif #endif
#include "nsVoidArray.h"
#include "nsLayoutUtils.h"
#ifdef IBMBIDI #ifdef IBMBIDI
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
@ -160,6 +162,7 @@ nsFrameList::AppendFrame(nsIFrame* aParent, nsIFrame* aFrame)
{ {
NS_PRECONDITION(nsnull != aFrame, "null ptr"); NS_PRECONDITION(nsnull != aFrame, "null ptr");
if (nsnull != aFrame) { if (nsnull != aFrame) {
NS_PRECONDITION(!aFrame->GetNextSibling(), "Can only append one frame here");
nsIFrame* lastChild = LastChild(); nsIFrame* lastChild = LastChild();
if (nsnull == lastChild) { if (nsnull == lastChild) {
mFirstChild = aFrame; mFirstChild = aFrame;
@ -180,11 +183,11 @@ PRBool
nsFrameList::RemoveFrame(nsIFrame* aFrame, nsIFrame* aPrevSiblingHint) nsFrameList::RemoveFrame(nsIFrame* aFrame, nsIFrame* aPrevSiblingHint)
{ {
NS_PRECONDITION(nsnull != aFrame, "null ptr"); NS_PRECONDITION(nsnull != aFrame, "null ptr");
if (nsnull != aFrame) { if (aFrame) {
nsIFrame* nextFrame = aFrame->GetNextSibling(); nsIFrame* nextFrame = aFrame->GetNextSibling();
aFrame->SetNextSibling(nsnull);
if (aFrame == mFirstChild) { if (aFrame == mFirstChild) {
mFirstChild = nextFrame; mFirstChild = nextFrame;
aFrame->SetNextSibling(nsnull);
return PR_TRUE; return PR_TRUE;
} }
else { else {
@ -194,6 +197,7 @@ nsFrameList::RemoveFrame(nsIFrame* aFrame, nsIFrame* aPrevSiblingHint)
} }
if (prevSibling) { if (prevSibling) {
prevSibling->SetNextSibling(nextFrame); prevSibling->SetNextSibling(nextFrame);
aFrame->SetNextSibling(nsnull);
return PR_TRUE; return PR_TRUE;
} }
} }
@ -441,6 +445,58 @@ nsFrameList::GetLength() const
return count; return count;
} }
static int PR_CALLBACK CompareByContentOrder(const void* aF1, const void* aF2,
void* aDummy)
{
const nsIFrame* f1 = NS_STATIC_CAST(const nsIFrame*, aF1);
const nsIFrame* f2 = NS_STATIC_CAST(const nsIFrame*, aF2);
if (f1->GetContent() != f2->GetContent()) {
return nsLayoutUtils::CompareTreePosition(f1->GetContent(), f2->GetContent());
}
if (f1 == f2) {
return 0;
}
const nsIFrame* f;
for (f = f2; f; f = f->GetPrevInFlow()) {
if (f == f1) {
// f1 comes before f2 in the flow
return -1;
}
}
for (f = f1; f; f = f->GetPrevInFlow()) {
if (f == f2) {
// f1 comes after f2 in the flow
return 1;
}
}
NS_ASSERTION(PR_FALSE, "Frames for same content but not in relative flow order");
return 0;
}
void
nsFrameList::SortByContentOrder()
{
if (!mFirstChild)
return;
nsAutoVoidArray array;
nsIFrame* f;
for (f = mFirstChild; f; f = f->GetNextSibling()) {
array.AppendElement(f);
}
array.Sort(CompareByContentOrder, nsnull);
f = mFirstChild = NS_STATIC_CAST(nsIFrame*, array.FastElementAt(0));
for (PRInt32 i = 1; i < array.Count(); ++i) {
nsIFrame* ff = NS_STATIC_CAST(nsIFrame*, array.FastElementAt(i));
f->SetNextSibling(ff);
f = ff;
}
f->SetNextSibling(nsnull);
}
nsIFrame* nsIFrame*
nsFrameList::GetPrevSiblingFor(nsIFrame* aFrame) const nsFrameList::GetPrevSiblingFor(nsIFrame* aFrame) const
{ {

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

@ -115,6 +115,14 @@ public:
PRBool Split(nsIFrame* aAfterFrame, nsIFrame** aNextFrameResult); PRBool Split(nsIFrame* aAfterFrame, nsIFrame** aNextFrameResult);
/**
* Sort the frames according to content order so that the first
* frame in the list is the first in content order. Frames for
* the same content will be ordered so that a prev in flow
* comes before its next in flow.
*/
void SortByContentOrder();
nsIFrame* PullFrame(nsIFrame* aParent, nsIFrame* PullFrame(nsIFrame* aParent,
nsIFrame* aLastChild, nsIFrame* aLastChild,
nsFrameList& aFromList); nsFrameList& aFromList);

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

@ -147,14 +147,22 @@ struct nsHTMLReflowState {
// reason == eReflowReason_Incremental. // reason == eReflowReason_Incremental.
nsReflowPath *path; nsReflowPath *path;
// the available space in which to reflow the frame. The space represents the // the available width in which to reflow the frame. The space
// amount of room for the frame's border, padding, and content area (not the // represents the amount of room for the frame's border, padding,
// margin area. The parent frame deals with the child frame's margins). The // and content area (not the margin area. The parent frame deals
// frame size you choose should fit within the available space. // with the child frame's margins). The frame size you choose should
// A value of NS_UNCONSTRAINEDSIZE for the available height means you can // fit within the available width.
// choose whatever size you want. In galley mode the available height is always nscoord availableWidth;
// NS_UNCONSTRAINEDSIZE, and only page mode involves a constrained height
nscoord availableWidth, availableHeight; // A value of NS_UNCONSTRAINEDSIZE for the available height means
// you can choose whatever size you want. In galley mode the
// available height is always NS_UNCONSTRAINEDSIZE, and only page
// mode involves a constrained height. The element's the top border
// and padding, and content, must fit. If the element is complete
// after reflow then its bottom border, padding and margin (and
// similar for its complete ancestors) will need to fit in this
// height.
nscoord availableHeight;
// rendering context to use for measurement // rendering context to use for measurement
nsIRenderingContext* rendContext; nsIRenderingContext* rendContext;

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

@ -772,7 +772,7 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
if (nsLayoutAtoms::placeholderFrame == aFrame->GetType()) { if (nsLayoutAtoms::placeholderFrame == aFrame->GetType()) {
nsBlockReflowState* blockRS = lineLayout->mBlockRS; nsBlockReflowState* blockRS = lineLayout->mBlockRS;
blockRS->mBlock->SplitPlaceholder(*aPresContext, *aFrame); blockRS->mBlock->SplitPlaceholder(*blockRS, aFrame);
} }
else { else {
nsIFrame* newFrame; nsIFrame* newFrame;

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

@ -44,6 +44,7 @@
#include "nsBlockFrame.h" #include "nsBlockFrame.h"
#include "nsITextContent.h" #include "nsITextContent.h"
#include "nsLayoutAtoms.h" #include "nsLayoutAtoms.h"
#include "nsFrameManager.h"
#ifdef DEBUG #ifdef DEBUG
static PRInt32 ctorCount; static PRInt32 ctorCount;
@ -62,6 +63,12 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock)
MOZ_COUNT_CTOR(nsLineBox); MOZ_COUNT_CTOR(nsLineBox);
#ifdef DEBUG #ifdef DEBUG
++ctorCount; ++ctorCount;
NS_ASSERTION(!aIsBlock || aCount == 1, "Blocks must have exactly one child");
nsIFrame* f = aFrame;
for (PRInt32 n = aCount; n > 0; f = f->GetNextSibling(), --n) {
NS_ASSERTION(aIsBlock == f->GetStyleDisplay()->IsBlockLevel(),
"wrong kind of child frame");
}
#endif #endif
mAllFlags = 0; mAllFlags = 0;
@ -464,7 +471,6 @@ nsLineBox::RemoveFloat(nsIFrame* aFrame)
if (fc) { if (fc) {
// Note: the placeholder is part of the line's child list // Note: the placeholder is part of the line's child list
// and will be removed later. // and will be removed later.
fc->mPlaceholder->SetOutOfFlowFrame(nsnull);
mInlineData->mFloats.Remove(fc); mInlineData->mFloats.Remove(fc);
MaybeFreeData(); MaybeFreeData();
return PR_TRUE; return PR_TRUE;

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

@ -1012,11 +1012,16 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame); nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame);
if (outOfFlowFrame) { if (outOfFlowFrame) {
nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, aFrame); nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, aFrame);
PRBool didPlace;
if (eReflowReason_Incremental == reason) { if (eReflowReason_Incremental == reason) {
InitFloat(placeholder, aReflowStatus); didPlace = InitFloat(placeholder, aReflowStatus);
} }
else { else {
AddFloat(placeholder, aReflowStatus); didPlace = AddFloat(placeholder, aReflowStatus);
}
printf("*** Reflowed float, didPlace=%d, status=%d\n", aReflowStatus);
if (!didPlace) {
aReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
} }
if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) { if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) {
SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE); SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE);

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

@ -252,12 +252,12 @@ public:
//---------------------------------------- //----------------------------------------
// Inform the line-layout about the presence of a floating frame // Inform the line-layout about the presence of a floating frame
// XXX get rid of this: use get-frame-type? // XXX get rid of this: use get-frame-type?
void InitFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) { PRBool InitFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) {
mBlockRS->InitFloat(*this, aFrame, aReflowStatus); return mBlockRS->InitFloat(*this, aFrame, aReflowStatus);
} }
void AddFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) { PRBool AddFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) {
mBlockRS->AddFloat(*this, aFrame, PR_FALSE, aReflowStatus); return mBlockRS->AddFloat(*this, aFrame, PR_FALSE, aReflowStatus);
} }
//---------------------------------------- //----------------------------------------

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

@ -40,6 +40,7 @@
#include "nsPresContext.h" #include "nsPresContext.h"
#include "nsIRenderingContext.h" #include "nsIRenderingContext.h"
#include "nsLayoutAtoms.h" #include "nsLayoutAtoms.h"
#include "nsFrameManager.h"
nsresult nsresult
NS_NewPlaceholderFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) NS_NewPlaceholderFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
@ -86,6 +87,18 @@ nsPlaceholderFrame::Reflow(nsPresContext* aPresContext,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsPlaceholderFrame::Destroy(nsPresContext* aPresContext)
{
nsIPresShell* shell = aPresContext->GetPresShell();
if (shell && mOutOfFlowFrame) {
NS_ASSERTION(!shell->FrameManager()->GetPlaceholderFrameFor(mOutOfFlowFrame),
"Placeholder relationship should have been torn down");
}
return nsSplittableFrame::Destroy(aPresContext);
}
nsIAtom* nsIAtom*
nsPlaceholderFrame::GetType() const nsPlaceholderFrame::GetType() const
{ {
@ -136,6 +149,14 @@ nsPlaceholderFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent
if (0 != mState) { if (0 != mState) {
fprintf(out, " [state=%08x]", mState); fprintf(out, " [state=%08x]", mState);
} }
nsIFrame* prevInFlow = GetPrevInFlow();
nsIFrame* nextInFlow = GetNextInFlow();
if (nsnull != prevInFlow) {
fprintf(out, " prev-in-flow=%p", NS_STATIC_CAST(void*, prevInFlow));
}
if (nsnull != nextInFlow) {
fprintf(out, " next-in-flow=%p", NS_STATIC_CAST(void*, nextInFlow));
}
if (mOutOfFlowFrame) { if (mOutOfFlowFrame) {
fprintf(out, " outOfFlowFrame="); fprintf(out, " outOfFlowFrame=");
nsFrame::ListTag(out, mOutOfFlowFrame); nsFrame::ListTag(out, mOutOfFlowFrame);

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

@ -64,6 +64,8 @@ public:
const nsHTMLReflowState& aReflowState, const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus); nsReflowStatus& aStatus);
NS_IMETHOD Destroy(nsPresContext* aPresContext);
// nsIFrame overrides // nsIFrame overrides
#ifdef DEBUG #ifdef DEBUG
NS_IMETHOD Paint(nsPresContext* aPresContext, NS_IMETHOD Paint(nsPresContext* aPresContext,

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

@ -359,11 +359,13 @@ nsSpaceManager::GetBandData(nscoord aYOffset,
// If there are no unavailable rects or the offset is below the bottommost // If there are no unavailable rects or the offset is below the bottommost
// band, then all the space is available // band, then all the space is available
nscoord yMost; nscoord yMost;
nscoord maxHeight = aMaxSize.height == NS_UNCONSTRAINEDSIZE ? NS_UNCONSTRAINEDSIZE
: PR_MAX(0, aMaxSize.height - aYOffset);
if (!YMost(yMost) || (y >= yMost)) { if (!YMost(yMost) || (y >= yMost)) {
// All the requested space is available // All the requested space is available
aBandData.mCount = 1; aBandData.mCount = 1;
aBandData.mTrapezoids[0] = nsRect(0, aYOffset, aMaxSize.width, aMaxSize.height); aBandData.mTrapezoids[0] = nsRect(0, aYOffset, aMaxSize.width, maxHeight);
aBandData.mTrapezoids[0].mState = nsBandTrapezoid::Available; aBandData.mTrapezoids[0].mState = nsBandTrapezoid::Available;
aBandData.mTrapezoids[0].mFrame = nsnull; aBandData.mTrapezoids[0].mFrame = nsnull;
} else { } else {
@ -378,14 +380,14 @@ nsSpaceManager::GetBandData(nscoord aYOffset,
// the top of the band is available // the top of the band is available
aBandData.mCount = 1; aBandData.mCount = 1;
aBandData.mTrapezoids[0] = aBandData.mTrapezoids[0] =
nsRect(0, aYOffset, aMaxSize.width, PR_MIN(band->mTop - y, aMaxSize.height)); nsRect(0, aYOffset, aMaxSize.width, PR_MIN(band->mTop - y, maxHeight));
aBandData.mTrapezoids[0].mState = nsBandTrapezoid::Available; aBandData.mTrapezoids[0].mState = nsBandTrapezoid::Available;
aBandData.mTrapezoids[0].mFrame = nsnull; aBandData.mTrapezoids[0].mFrame = nsnull;
break; break;
} else if (y < band->mBottom) { } else if (y < band->mBottom) {
// The band contains the y-offset. Return a list of available and // The band contains the y-offset. Return a list of available and
// unavailable rects within the band // unavailable rects within the band
return GetBandAvailableSpace(band, y, aMaxSize, aBandData); return GetBandAvailableSpace(band, y, nsSize(aMaxSize.width, maxHeight), aBandData);
} else { } else {
// Skip to the next band // Skip to the next band
band = GetNextBand(band); band = GetNextBand(band);