зеркало из https://github.com/mozilla/pjs.git
Bug 263825. Make paginated floats work, and other fixes. r+sr=dbaron
This commit is contained in:
Родитель
9a36e969fe
Коммит
30604288b9
|
@ -538,6 +538,7 @@ nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
|
|||
|
||||
NS_ASSERTION(!entry->placeholderFrame, "Registering a placeholder for a frame that already has a placeholder!");
|
||||
entry->placeholderFrame = aPlaceholderFrame;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ LAYOUT_ATOM(overflowAreaProperty, "OverflowArea") // nsRect*
|
|||
LAYOUT_ATOM(overflowProperty, "OverflowProperty") // list of nsIFrame*
|
||||
LAYOUT_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox*
|
||||
LAYOUT_ATOM(overflowOutOfFlowsProperty, "OverflowOutOfFlowsProperty") // nsFrameList*
|
||||
LAYOUT_ATOM(overflowPlaceholdersProperty, "OverflowPlaceholdersProperty") // nsPlaceholder*
|
||||
LAYOUT_ATOM(overflowPlaceholdersProperty, "OverflowPlaceholdersProperty") // nsFrameList*
|
||||
LAYOUT_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty") // nscoord*
|
||||
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)
|
||||
|
|
|
@ -490,9 +490,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
|
|||
PrettyUC(aReflowState.mComputedHeight, height);
|
||||
printf("c=%s,%s \n", width, height);
|
||||
}
|
||||
if (nsBlockFrame::gNoisy) {
|
||||
nsBlockFrame::gNoiseIndent++;
|
||||
}
|
||||
AutoNoisyIndenter indent(nsBlockFrame::gNoisy);
|
||||
#endif // DEBUG
|
||||
|
||||
nsresult rv;
|
||||
|
@ -665,11 +663,8 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
|
|||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisy) {
|
||||
nsBlockFrame::gNoiseIndent--;
|
||||
}
|
||||
if (nsBlockFrame::gNoisyReflow) {
|
||||
nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent);
|
||||
nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1);
|
||||
printf("abs pos ");
|
||||
if (nsnull != aKidFrame) {
|
||||
nsIFrameDebug* frameDebug;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -63,6 +63,32 @@ class nsIntervalSet;
|
|||
#define NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX 4
|
||||
#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
|
||||
#define NS_BLOCK_HAS_LINE_CURSOR 0x01000000
|
||||
#define NS_BLOCK_HAS_OVERFLOW_LINES 0x02000000
|
||||
|
@ -222,9 +248,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)
|
||||
/**
|
||||
* 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.
|
||||
|
@ -243,7 +271,7 @@ public:
|
|||
|
||||
// Create a contination for aPlaceholder and its out of flow frame and
|
||||
// add it to the list of overflow floats
|
||||
nsresult SplitPlaceholder(nsPresContext& aPresContext, nsIFrame& aPlaceholder);
|
||||
nsresult SplitPlaceholder(nsBlockReflowState& aState, nsIFrame* aPlaceholder);
|
||||
|
||||
void UndoSplitPlaceholders(nsBlockReflowState& aState,
|
||||
nsIFrame* aLastPlaceholder);
|
||||
|
@ -258,6 +286,12 @@ public:
|
|||
aDirtyRect, aFrame, aWhichLayer, aFlags);
|
||||
}
|
||||
|
||||
PRBool HandleOverflowPlaceholdersForPulledFrame(
|
||||
nsBlockReflowState& aState, nsIFrame* aFrame);
|
||||
|
||||
PRBool HandleOverflowPlaceholdersOnPulledLine(
|
||||
nsBlockReflowState& aState, nsLineBox* aLine);
|
||||
|
||||
protected:
|
||||
nsBlockFrame();
|
||||
virtual ~nsBlockFrame();
|
||||
|
@ -331,18 +365,23 @@ protected:
|
|||
nsresult AddFrames(nsIFrame* aFrameList,
|
||||
nsIFrame* aPrevSibling);
|
||||
|
||||
public:
|
||||
/** does all the real work for removing aDeletedFrame from this
|
||||
* finds the line containing aFrame.
|
||||
* handled continued frames
|
||||
* 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
|
||||
* part of this block's mLines list.
|
||||
* @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
|
||||
|
@ -350,6 +389,8 @@ protected:
|
|||
*/
|
||||
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
|
||||
static void DoRemoveOutOfFlowFrame(nsIFrame* aFrame);
|
||||
|
||||
|
@ -391,8 +432,11 @@ protected:
|
|||
*/
|
||||
nsresult PrepareResizeReflow(nsBlockReflowState& aState);
|
||||
|
||||
/** reflow all lines that have been marked dirty */
|
||||
nsresult ReflowDirtyLines(nsBlockReflowState& aState);
|
||||
/** reflow all lines that have been marked dirty.
|
||||
* @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
|
||||
|
@ -498,13 +542,13 @@ protected:
|
|||
PRBool aDamageDeletedLine,
|
||||
nsIFrame*& aFrameResult);
|
||||
|
||||
nsresult PullFrameFrom(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
nsBlockFrame* aFromContainer,
|
||||
PRBool aFromOverflowLine,
|
||||
nsLineList::iterator aFromLine,
|
||||
PRBool aDamageDeletedLines,
|
||||
nsIFrame*& aFrameResult);
|
||||
PRBool PullFrameFrom(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
nsBlockFrame* aFromContainer,
|
||||
PRBool aFromOverflowLine,
|
||||
nsLineList::iterator aFromLine,
|
||||
PRBool aDamageDeletedLines,
|
||||
nsIFrame*& aFrameResult);
|
||||
|
||||
void PushLines(nsBlockReflowState& aState,
|
||||
nsLineList::iterator aLineBefore);
|
||||
|
@ -552,17 +596,39 @@ protected:
|
|||
|
||||
//----------------------------------------
|
||||
|
||||
public:
|
||||
nsLineList* GetOverflowLines() const;
|
||||
protected:
|
||||
nsLineList* RemoveOverflowLines();
|
||||
nsresult SetOverflowLines(nsLineList* aOverflowLines);
|
||||
|
||||
nsFrameList* GetOverflowPlaceholders() const;
|
||||
nsFrameList* RemoveOverflowPlaceholders();
|
||||
nsresult SetOverflowPlaceholders(nsFrameList* aOverflowPlaceholders);
|
||||
|
||||
nsFrameList* GetOverflowOutOfFlows() const;
|
||||
nsFrameList* RemoveOverflowOutOfFlows();
|
||||
nsresult SetOverflowOutOfFlows(nsFrameList* aFloaters);
|
||||
/**
|
||||
* This class is useful for efficiently modifying the out of flow
|
||||
* 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();
|
||||
|
||||
|
@ -613,5 +679,23 @@ protected:
|
|||
#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___ */
|
||||
|
||||
|
|
|
@ -107,55 +107,79 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
|
|||
if (0 == aRS.mComputedBorderPadding.top &&
|
||||
!(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;
|
||||
// iterate not just through the lines of 'block' but also its
|
||||
// overflow lines and the normal and overflow lines of its next in
|
||||
// flows. Note that this will traverse some frames more than once:
|
||||
// for example, if A contains B and A->nextinflow contains
|
||||
// B->nextinflow, we'll traverse B->nextinflow twice. But this is
|
||||
// OK because our traversal is idempotent.
|
||||
for (nsBlockFrame* block = NS_STATIC_CAST(nsBlockFrame*, aRS.frame);
|
||||
block; block = NS_STATIC_CAST(nsBlockFrame*, block->GetNextInFlow())) {
|
||||
for (PRBool overflowLines = PR_FALSE; overflowLines <= PR_TRUE; ++overflowLines) {
|
||||
nsBlockFrame::line_iterator line;
|
||||
nsBlockFrame::line_iterator line_end;
|
||||
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
|
||||
|
@ -624,7 +648,9 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
|||
if (nsnull != kidNextInFlow) {
|
||||
// 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
|
||||
// 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 */
|
||||
NS_STATIC_CAST(nsHTMLContainerFrame*, kidNextInFlow->GetParent())
|
||||
->DeleteNextInFlowChild(mPresContext, kidNextInFlow);
|
||||
|
@ -654,17 +680,20 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
|||
const nsMargin& aComputedOffsets,
|
||||
nsCollapsingMargin& aBottomMarginResult,
|
||||
nsRect& aInFlowBounds,
|
||||
nsRect& aCombinedRect)
|
||||
nsRect& aCombinedRect,
|
||||
nsReflowStatus aReflowStatus)
|
||||
{
|
||||
// Compute collapsed bottom margin value
|
||||
aBottomMarginResult = mMetrics.mCarriedOutBottomMargin;
|
||||
aBottomMarginResult.Include(mMargin.bottom);
|
||||
// Compute collapsed bottom margin value.
|
||||
if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
|
||||
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 y = mY;
|
||||
|
||||
nscoord backupContainingBlockAdvance = 0;
|
||||
|
||||
// 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
|
||||
// have adjoining top/bottom margins, because the clearance goes
|
||||
// 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
|
||||
// applied.
|
||||
aBottomMarginResult.Include(mTopMargin);
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
printf(" ");
|
||||
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",
|
||||
y, mSpace.y);
|
||||
#endif
|
||||
|
||||
// Empty blocks always fit
|
||||
fits = PR_TRUE;
|
||||
|
||||
// Section 8.3.1 of CSS 2.1 says that blocks with adjoining
|
||||
// top/bottom margins whose top margin collapses with their
|
||||
// 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.
|
||||
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
|
||||
// account the margins around the block element.
|
||||
// Do not allow auto margins to impact the max-element size
|
||||
// since they are springy and don't really count!
|
||||
if (mMetrics.mComputeMEW) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
// See if the frame fit. If it's the first frame or empty 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.
|
||||
if (!empty && !aForceFit && mSpace.height != NS_UNCONSTRAINEDSIZE) {
|
||||
nscoord yMost = y - backupContainingBlockAdvance + mMetrics.height;
|
||||
if (yMost > mSpace.YMost()) {
|
||||
// didn't fit, we must acquit.
|
||||
mFrame->DidReflow(mPresContext, &aReflowState, NS_FRAME_REFLOW_FINISHED);
|
||||
fits = PR_FALSE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (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;
|
||||
if (!empty)
|
||||
{
|
||||
// Adjust the max-element-size in the metrics to take into
|
||||
// account the margins around the block element.
|
||||
// Do not allow auto margins to impact the max-element size
|
||||
// since they are springy and don't really count!
|
||||
if (mMetrics.mComputeMEW) {
|
||||
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,
|
||||
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;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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,
|
||||
nsCollapsingMargin& aBottomMarginResult /* out */,
|
||||
nsRect& aInFlowBounds,
|
||||
nsRect& aCombinedRect);
|
||||
nsRect& aCombinedRect,
|
||||
nsReflowStatus aReflowStatus);
|
||||
|
||||
void AlignBlockHorizontally(nscoord aWidth, nsBlockHorizontalAlign&);
|
||||
|
||||
|
|
|
@ -72,6 +72,12 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
{
|
||||
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) {
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
|
@ -172,6 +178,11 @@ nsBlockReflowState::~nsBlockReflowState()
|
|||
const nsMargin& borderPadding = BorderPadding();
|
||||
mSpaceManager->Translate(-borderPadding.left, -borderPadding.top);
|
||||
}
|
||||
|
||||
if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
|
||||
mBlock->UnsetProperty(nsLayoutAtoms::overflowPlaceholdersProperty);
|
||||
mBlock->RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS);
|
||||
}
|
||||
}
|
||||
|
||||
nsLineBox*
|
||||
|
@ -543,7 +554,7 @@ nsBlockReflowState::IsImpactedByFloat() const
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
PRBool
|
||||
nsBlockReflowState::InitFloat(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder,
|
||||
nsReflowStatus& aReflowStatus)
|
||||
|
@ -554,7 +565,7 @@ nsBlockReflowState::InitFloat(nsLineLayout& aLineLayout,
|
|||
|
||||
// Then add the float to the current line and place it when
|
||||
// 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
|
||||
|
@ -567,7 +578,7 @@ nsBlockReflowState::InitFloat(nsLineLayout& aLineLayout,
|
|||
// 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.
|
||||
// But nobody else implements it that way...
|
||||
void
|
||||
PRBool
|
||||
nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder,
|
||||
PRBool aInitialReflow,
|
||||
|
@ -582,12 +593,11 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
|
|||
fc->mIsCurrentLineFloat = aLineLayout.CanPlaceFloatNow();
|
||||
fc->mMaxElementWidth = 0;
|
||||
|
||||
PRBool placed;
|
||||
|
||||
// Now place the float immediately if possible. Otherwise stash it
|
||||
// away in mPendingFloats and place it later.
|
||||
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
|
||||
// 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
|
||||
|
@ -601,15 +611,19 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
|
|||
|
||||
// And then place it
|
||||
PRBool isLeftFloat;
|
||||
FlowAndPlaceFloat(fc, &isLeftFloat, aReflowStatus);
|
||||
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloat,
|
||||
aPlaceholder->GetOutOfFlowFrame());
|
||||
placed = FlowAndPlaceFloat(fc, &isLeftFloat, aReflowStatus);
|
||||
if (placed) {
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloat,
|
||||
aPlaceholder->GetOutOfFlowFrame());
|
||||
|
||||
// Record this float in the current-line list
|
||||
mCurrentLineFloats.Append(fc);
|
||||
}
|
||||
|
||||
// Restore coordinate system
|
||||
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
|
||||
// below-current-line float).
|
||||
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
|
||||
|
@ -716,6 +739,12 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
|
|||
nscoord saveY = mY;
|
||||
for (;;) {
|
||||
// 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;
|
||||
GetAvailableSpace();
|
||||
|
||||
|
@ -752,7 +781,7 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
|
|||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
PRBool
|
||||
nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
||||
PRBool* aIsLeftFloat,
|
||||
nsReflowStatus& aReflowStatus)
|
||||
|
@ -821,6 +850,12 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
|||
PRBool keepFloatOnSameLine = PR_FALSE;
|
||||
|
||||
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.
|
||||
if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
|
||||
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
|
||||
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
|
||||
// prevRect.x to account for the missing frame offsets.
|
||||
nsIFrame* placeParent = placeholder->GetParent();
|
||||
nsIFrame* placeParentPrev = placeParent->GetPrevInFlow();
|
||||
nsIFrame* prevPlace =
|
||||
mPresContext->FrameManager()->GetPlaceholderFrameFor(prevInFlow);
|
||||
// We don't worry about the geometry of the prev in flow, let the continuation
|
||||
// place and size itself as required.
|
||||
|
||||
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
|
||||
// coordinates are computed <b>relative to the translation in the
|
||||
// spacemanager</b> which means that the impacted region will be
|
||||
|
@ -907,15 +927,12 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
|||
nscoord floatX, floatY;
|
||||
if (NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) {
|
||||
isLeftFloat = PR_TRUE;
|
||||
floatX = (prevInFlow) ? prevRect.x : mAvailSpaceRect.x;
|
||||
floatX = mAvailSpaceRect.x;
|
||||
}
|
||||
else {
|
||||
isLeftFloat = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.width) {
|
||||
if (prevInFlow) {
|
||||
floatX = prevRect.x;
|
||||
}
|
||||
else if (!keepFloatOnSameLine) {
|
||||
if (!keepFloatOnSameLine) {
|
||||
floatX = mAvailSpaceRect.XMost() - floatSize.width;
|
||||
}
|
||||
else {
|
||||
|
@ -947,7 +964,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
|||
// if the float split, then take up all of the vertical height
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) &&
|
||||
(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);
|
||||
|
@ -1041,6 +1058,8 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
|||
printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
|
||||
}
|
||||
#endif
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1066,17 +1085,25 @@ nsBlockReflowState::PlaceBelowCurrentLineFloats(nsFloatCacheList& aList)
|
|||
// Place the float
|
||||
PRBool isLeftFloat;
|
||||
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 PR_FALSE;
|
||||
}
|
||||
else if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus)) {
|
||||
// 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))
|
||||
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();
|
||||
|
|
|
@ -68,21 +68,22 @@ public:
|
|||
|
||||
void GetAvailableSpace(nscoord aY);
|
||||
|
||||
void InitFloat(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
|
||||
void AddFloat(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
PRBool aInitialReflow,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
|
||||
/*
|
||||
* The following functions all return PR_TRUE if they were able to
|
||||
* place the float, PR_FALSE if the float did not fit in available
|
||||
* space.
|
||||
*/
|
||||
PRBool InitFloat(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
PRBool AddFloat(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
PRBool aInitialReflow,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
PRBool CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats);
|
||||
|
||||
void FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
||||
PRBool* aIsLeftFloat,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
|
||||
PRBool FlowAndPlaceFloat(nsFloatCache* aFloatCache,
|
||||
PRBool* aIsLeftFloat,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
PRBool PlaceBelowCurrentLineFloats(nsFloatCacheList& aFloats);
|
||||
|
||||
// Returns the first coordinate >= aY that clears the
|
||||
|
@ -162,6 +163,10 @@ public:
|
|||
// unconstrained area.
|
||||
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
|
||||
|
|
|
@ -69,6 +69,10 @@ public:
|
|||
NS_IMETHOD RemoveFrame(nsIAtom* aListName,
|
||||
nsIFrame* aOldFrame);
|
||||
|
||||
NS_IMETHOD GetFrameForPoint(const nsPoint& aPoint,
|
||||
nsFramePaintLayer aWhichLayer,
|
||||
nsIFrame** aFrame);
|
||||
|
||||
virtual nsIFrame* GetContentInsertionFrame() {
|
||||
return GetFirstChild(nsnull)->GetContentInsertionFrame();
|
||||
}
|
||||
|
@ -163,6 +167,16 @@ nsColumnSetFrame::GetType() const
|
|||
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
|
||||
nsColumnSetFrame::SetInitialChildList(nsPresContext* aPresContext,
|
||||
nsIAtom* aListName,
|
||||
|
@ -260,6 +274,9 @@ nsColumnSetFrame::ChooseColumnStrategy(const nsHTMLReflowState& aReflowState)
|
|||
// colWidth*nominalColumnCount is nearly availContentWidth
|
||||
// make sure to round down
|
||||
numColumns = (availContentWidth + colGap)/(colGap + colWidth);
|
||||
if (numColumns <= 0) {
|
||||
numColumns = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute extra space and divide it among the columns
|
||||
|
|
|
@ -638,6 +638,20 @@ nsFrame::Destroy(nsPresContext* aPresContext)
|
|||
|
||||
nsIPresShell *shell = aPresContext->GetPresShell();
|
||||
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
|
||||
// the quoteList.
|
||||
if (mState & NS_FRAME_GENERATED_CONTENT) {
|
||||
|
@ -2724,6 +2738,14 @@ nsFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
|
|||
if (0 != 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));
|
||||
nsFrame* f = NS_CONST_CAST(nsFrame*, this);
|
||||
nsRect* overflowArea = f->GetOverflowAreaProperty(PR_FALSE);
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#ifdef NS_DEBUG
|
||||
#include "nsIFrameDebug.h"
|
||||
#endif
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#ifdef IBMBIDI
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -160,6 +162,7 @@ nsFrameList::AppendFrame(nsIFrame* aParent, nsIFrame* aFrame)
|
|||
{
|
||||
NS_PRECONDITION(nsnull != aFrame, "null ptr");
|
||||
if (nsnull != aFrame) {
|
||||
NS_PRECONDITION(!aFrame->GetNextSibling(), "Can only append one frame here");
|
||||
nsIFrame* lastChild = LastChild();
|
||||
if (nsnull == lastChild) {
|
||||
mFirstChild = aFrame;
|
||||
|
@ -180,11 +183,11 @@ PRBool
|
|||
nsFrameList::RemoveFrame(nsIFrame* aFrame, nsIFrame* aPrevSiblingHint)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aFrame, "null ptr");
|
||||
if (nsnull != aFrame) {
|
||||
if (aFrame) {
|
||||
nsIFrame* nextFrame = aFrame->GetNextSibling();
|
||||
aFrame->SetNextSibling(nsnull);
|
||||
if (aFrame == mFirstChild) {
|
||||
mFirstChild = nextFrame;
|
||||
aFrame->SetNextSibling(nsnull);
|
||||
return PR_TRUE;
|
||||
}
|
||||
else {
|
||||
|
@ -194,6 +197,7 @@ nsFrameList::RemoveFrame(nsIFrame* aFrame, nsIFrame* aPrevSiblingHint)
|
|||
}
|
||||
if (prevSibling) {
|
||||
prevSibling->SetNextSibling(nextFrame);
|
||||
aFrame->SetNextSibling(nsnull);
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -441,6 +445,58 @@ nsFrameList::GetLength() const
|
|||
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*
|
||||
nsFrameList::GetPrevSiblingFor(nsIFrame* aFrame) const
|
||||
{
|
||||
|
|
|
@ -115,6 +115,14 @@ public:
|
|||
|
||||
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* aLastChild,
|
||||
nsFrameList& aFromList);
|
||||
|
|
|
@ -147,14 +147,22 @@ struct nsHTMLReflowState {
|
|||
// reason == eReflowReason_Incremental.
|
||||
nsReflowPath *path;
|
||||
|
||||
// the available space in which to reflow the frame. The space represents the
|
||||
// amount of room for the frame's border, padding, and content area (not the
|
||||
// margin area. The parent frame deals with the child frame's margins). The
|
||||
// frame size you choose should fit within the available space.
|
||||
// A value of NS_UNCONSTRAINEDSIZE for the available height means you can
|
||||
// choose whatever size you want. In galley mode the available height is always
|
||||
// NS_UNCONSTRAINEDSIZE, and only page mode involves a constrained height
|
||||
nscoord availableWidth, availableHeight;
|
||||
// the available width in which to reflow the frame. The space
|
||||
// represents the amount of room for the frame's border, padding,
|
||||
// and content area (not the margin area. The parent frame deals
|
||||
// with the child frame's margins). The frame size you choose should
|
||||
// fit within the available width.
|
||||
nscoord availableWidth;
|
||||
|
||||
// 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
|
||||
nsIRenderingContext* rendContext;
|
||||
|
|
|
@ -772,7 +772,7 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
|
|||
else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
|
||||
if (nsLayoutAtoms::placeholderFrame == aFrame->GetType()) {
|
||||
nsBlockReflowState* blockRS = lineLayout->mBlockRS;
|
||||
blockRS->mBlock->SplitPlaceholder(*aPresContext, *aFrame);
|
||||
blockRS->mBlock->SplitPlaceholder(*blockRS, aFrame);
|
||||
}
|
||||
else {
|
||||
nsIFrame* newFrame;
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "nsBlockFrame.h"
|
||||
#include "nsITextContent.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsFrameManager.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
static PRInt32 ctorCount;
|
||||
|
@ -62,6 +63,12 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock)
|
|||
MOZ_COUNT_CTOR(nsLineBox);
|
||||
#ifdef DEBUG
|
||||
++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
|
||||
|
||||
mAllFlags = 0;
|
||||
|
@ -464,7 +471,6 @@ nsLineBox::RemoveFloat(nsIFrame* aFrame)
|
|||
if (fc) {
|
||||
// Note: the placeholder is part of the line's child list
|
||||
// and will be removed later.
|
||||
fc->mPlaceholder->SetOutOfFlowFrame(nsnull);
|
||||
mInlineData->mFloats.Remove(fc);
|
||||
MaybeFreeData();
|
||||
return PR_TRUE;
|
||||
|
|
|
@ -1012,11 +1012,16 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame);
|
||||
if (outOfFlowFrame) {
|
||||
nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, aFrame);
|
||||
PRBool didPlace;
|
||||
if (eReflowReason_Incremental == reason) {
|
||||
InitFloat(placeholder, aReflowStatus);
|
||||
didPlace = InitFloat(placeholder, aReflowStatus);
|
||||
}
|
||||
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) {
|
||||
SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE);
|
||||
|
|
|
@ -252,12 +252,12 @@ public:
|
|||
//----------------------------------------
|
||||
// Inform the line-layout about the presence of a floating frame
|
||||
// XXX get rid of this: use get-frame-type?
|
||||
void InitFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) {
|
||||
mBlockRS->InitFloat(*this, aFrame, aReflowStatus);
|
||||
PRBool InitFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) {
|
||||
return mBlockRS->InitFloat(*this, aFrame, aReflowStatus);
|
||||
}
|
||||
|
||||
void AddFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) {
|
||||
mBlockRS->AddFloat(*this, aFrame, PR_FALSE, aReflowStatus);
|
||||
PRBool AddFloat(nsPlaceholderFrame* aFrame, nsReflowStatus& aReflowStatus) {
|
||||
return mBlockRS->AddFloat(*this, aFrame, PR_FALSE, aReflowStatus);
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "nsPresContext.h"
|
||||
#include "nsIRenderingContext.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsFrameManager.h"
|
||||
|
||||
nsresult
|
||||
NS_NewPlaceholderFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
|
||||
|
@ -86,6 +87,18 @@ nsPlaceholderFrame::Reflow(nsPresContext* aPresContext,
|
|||
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*
|
||||
nsPlaceholderFrame::GetType() const
|
||||
{
|
||||
|
@ -136,6 +149,14 @@ nsPlaceholderFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent
|
|||
if (0 != 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) {
|
||||
fprintf(out, " outOfFlowFrame=");
|
||||
nsFrame::ListTag(out, mOutOfFlowFrame);
|
||||
|
|
|
@ -64,6 +64,8 @@ public:
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
NS_IMETHOD Destroy(nsPresContext* aPresContext);
|
||||
|
||||
// nsIFrame overrides
|
||||
#ifdef DEBUG
|
||||
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
|
||||
// band, then all the space is available
|
||||
nscoord yMost;
|
||||
|
||||
nscoord maxHeight = aMaxSize.height == NS_UNCONSTRAINEDSIZE ? NS_UNCONSTRAINEDSIZE
|
||||
: PR_MAX(0, aMaxSize.height - aYOffset);
|
||||
|
||||
if (!YMost(yMost) || (y >= yMost)) {
|
||||
// All the requested space is available
|
||||
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].mFrame = nsnull;
|
||||
} else {
|
||||
|
@ -378,14 +380,14 @@ nsSpaceManager::GetBandData(nscoord aYOffset,
|
|||
// the top of the band is available
|
||||
aBandData.mCount = 1;
|
||||
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].mFrame = nsnull;
|
||||
break;
|
||||
} else if (y < band->mBottom) {
|
||||
// The band contains the y-offset. Return a list of available and
|
||||
// unavailable rects within the band
|
||||
return GetBandAvailableSpace(band, y, aMaxSize, aBandData);
|
||||
return GetBandAvailableSpace(band, y, nsSize(aMaxSize.width, maxHeight), aBandData);
|
||||
} else {
|
||||
// Skip to the next band
|
||||
band = GetNextBand(band);
|
||||
|
|
Загрузка…
Ссылка в новой задаче