зеркало из https://github.com/mozilla/pjs.git
Bug 379349. Add support for 'overflow containers' --- special frame continuations that do not map any content of their own, but serve only as containers for laying out children that overflowed their parents' content height. patch by fantasai, r+sr=eli,roc
This commit is contained in:
Родитель
a883fd0427
Коммит
1da360b2d7
|
@ -320,6 +320,7 @@ GK_ATOM(error, "error")
|
|||
GK_ATOM(even, "even")
|
||||
GK_ATOM(event, "event")
|
||||
GK_ATOM(events, "events")
|
||||
GK_ATOM(excessOverflowContainersList, "ExcessOverflowContainers-list")
|
||||
GK_ATOM(excludeResultPrefixes, "exclude-result-prefixes")
|
||||
GK_ATOM(excludes, "excludes")
|
||||
GK_ATOM(expr, "expr")
|
||||
|
@ -624,6 +625,7 @@ GK_ATOM(output, "output")
|
|||
GK_ATOM(overflow, "overflow")
|
||||
GK_ATOM(overflowList, "Overflow-list")
|
||||
GK_ATOM(overflowchanged, "overflowchanged")
|
||||
GK_ATOM(overflowContainersList, "OverflowContainers-list")
|
||||
GK_ATOM(overflowOutOfFlowList, "OverflowOutOfFlow-list")
|
||||
GK_ATOM(overlay, "overlay")
|
||||
GK_ATOM(overlap, "overlap")
|
||||
|
@ -1461,6 +1463,8 @@ GK_ATOM(maxElementWidthProperty, "MaxElementWidthProperty") // nscoord*
|
|||
GK_ATOM(outOfFlowDirtyRectProperty, "OutOfFlowDirtyRectProperty") // nsRect*
|
||||
GK_ATOM(overflowAreaProperty, "OverflowArea") // nsRect*
|
||||
GK_ATOM(overflowProperty, "OverflowProperty") // list of nsIFrame*
|
||||
GK_ATOM(overflowContainersProperty, "OverflowContainersProperty") // nsFrameList*
|
||||
GK_ATOM(excessOverflowContainersProperty, "ExcessOverflowContainersProperty") // nsFrameList*
|
||||
GK_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox*
|
||||
GK_ATOM(overflowOutOfFlowsProperty, "OverflowOutOfFlowsProperty") // nsFrameList*
|
||||
GK_ATOM(overflowPlaceholdersProperty, "OverflowPlaceholdersProperty") // nsFrameList*
|
||||
|
|
|
@ -4646,7 +4646,12 @@ nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell* aPresShell,
|
|||
|
||||
// Initialize the page content frame and force it to have a view. Also make it the
|
||||
// containing block for fixed elements which are repeated on every page.
|
||||
aPageContentFrame->Init(nsnull, aPageFrame, nsnull);
|
||||
nsIFrame* prevPageContentFrame = nsnull;
|
||||
if (aPrevPageFrame) {
|
||||
prevPageContentFrame = aPrevPageFrame->GetFirstChild(nsnull);
|
||||
NS_ASSERTION(prevPageContentFrame, "missing page content frame");
|
||||
}
|
||||
aPageContentFrame->Init(nsnull, aPageFrame, prevPageContentFrame);
|
||||
mFixedContainingBlock = aPageContentFrame;
|
||||
|
||||
aPageFrame->SetInitialChildList(nsnull, aPageContentFrame);
|
||||
|
|
|
@ -1261,6 +1261,8 @@ nsComboboxControlFrame::SetInitialChildList(nsIAtom* aListName,
|
|||
return rv;
|
||||
}
|
||||
|
||||
#define NS_COMBO_FRAME_POPUP_LIST_INDEX (NS_BLOCK_LIST_COUNT)
|
||||
|
||||
nsIAtom*
|
||||
nsComboboxControlFrame::GetAdditionalChildListName(PRInt32 aIndex) const
|
||||
{
|
||||
|
@ -1268,7 +1270,7 @@ nsComboboxControlFrame::GetAdditionalChildListName(PRInt32 aIndex) const
|
|||
// This is necessary because we don't want the listbox to be included in the layout
|
||||
// of the combox's children because it would take up space, when it is suppose to
|
||||
// be floating above the display.
|
||||
if (aIndex <= NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX) {
|
||||
if (aIndex < NS_BLOCK_LIST_COUNT) {
|
||||
return nsAreaFrame::GetAdditionalChildListName(aIndex);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ class nsComboboxDisplayFrame;
|
|||
* Child list name indices
|
||||
* @see #GetAdditionalChildListName()
|
||||
*/
|
||||
#define NS_COMBO_FRAME_POPUP_LIST_INDEX (NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX + 1)
|
||||
#define NS_COMBO_LIST_COUNT (NS_BLOCK_LIST_COUNT + 1)
|
||||
|
||||
class nsComboboxControlFrame : public nsAreaFrame,
|
||||
public nsIFormControlFrame,
|
||||
|
|
|
@ -536,23 +536,28 @@ nsBlockFrame::GetFirstChild(nsIAtom* aListName) const
|
|||
return mFloats.FirstChild();
|
||||
}
|
||||
else if (aListName == nsGkAtoms::bulletList) {
|
||||
if (HaveOutsideBullet()) {
|
||||
return mBullet;
|
||||
}
|
||||
return (HaveOutsideBullet()) ? mBullet : nsnull;
|
||||
}
|
||||
return nsnull;
|
||||
return nsContainerFrame::GetFirstChild(aListName);;
|
||||
}
|
||||
|
||||
#define NS_BLOCK_FRAME_OVERFLOW_OOF_LIST_INDEX (NS_CONTAINER_LIST_COUNT_INCL_OC + 0)
|
||||
#define NS_BLOCK_FRAME_FLOAT_LIST_INDEX (NS_CONTAINER_LIST_COUNT_INCL_OC + 1)
|
||||
#define NS_BLOCK_FRAME_BULLET_LIST_INDEX (NS_CONTAINER_LIST_COUNT_INCL_OC + 2)
|
||||
#define NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX (NS_CONTAINER_LIST_COUNT_INCL_OC + 3)
|
||||
// If adding/removing lists, don't forget to update the count in nsBlockFrame.h
|
||||
|
||||
nsIAtom*
|
||||
nsBlockFrame::GetAdditionalChildListName(PRInt32 aIndex) const
|
||||
{
|
||||
if (aIndex < NS_CONTAINER_LIST_COUNT_INCL_OC)
|
||||
return nsContainerFrame::GetAdditionalChildListName(aIndex);
|
||||
|
||||
switch (aIndex) {
|
||||
case NS_BLOCK_FRAME_FLOAT_LIST_INDEX:
|
||||
return nsGkAtoms::floatList;
|
||||
case NS_BLOCK_FRAME_BULLET_LIST_INDEX:
|
||||
return nsGkAtoms::bulletList;
|
||||
case NS_BLOCK_FRAME_OVERFLOW_LIST_INDEX:
|
||||
return nsGkAtoms::overflowList;
|
||||
case NS_BLOCK_FRAME_OVERFLOW_OOF_LIST_INDEX:
|
||||
return nsGkAtoms::overflowOutOfFlowList;
|
||||
case NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX:
|
||||
|
@ -830,7 +835,7 @@ CalculateContainingBlockSizeForAbsolutes(const nsHTMLReflowState& aReflowState,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
||||
nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
|
@ -919,6 +924,14 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Handle paginated overflow (see nsContainerFrame.h)
|
||||
nsRect overflowContainerBounds;
|
||||
if (GetPrevInFlow()) {
|
||||
ReflowOverflowContainerChildren(aPresContext, aReflowState,
|
||||
overflowContainerBounds, 0,
|
||||
state.mReflowStatus);
|
||||
}
|
||||
|
||||
// If the block is complete, put continuted floats in the closest ancestor
|
||||
// block that uses the same space manager and leave the block complete; this
|
||||
// allows subsequent lines on the page to be impacted by floats. If the
|
||||
|
@ -927,7 +940,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
if (state.mOverflowPlaceholders.NotEmpty()) {
|
||||
NS_ASSERTION(aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE,
|
||||
"Somehow we failed to fit all content, even though we have unlimited space!");
|
||||
if (NS_FRAME_IS_COMPLETE(state.mReflowStatus)) {
|
||||
if (NS_FRAME_IS_FULLY_COMPLETE(state.mReflowStatus)) {
|
||||
// find the nearest block ancestor that uses the same space manager
|
||||
for (const nsHTMLReflowState* ancestorRS = aReflowState.parentReflowState;
|
||||
ancestorRS;
|
||||
|
@ -1006,7 +1019,8 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
}
|
||||
state.mOverflowPlaceholders.SetFrames(nsnull);
|
||||
}
|
||||
state.mReflowStatus |= NS_FRAME_NOT_COMPLETE | NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
state.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
NS_FRAME_SET_INCOMPLETE(state.mReflowStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1065,6 +1079,9 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
ComputeFinalSize(aReflowState, state, aMetrics);
|
||||
|
||||
ComputeCombinedArea(aReflowState, aMetrics);
|
||||
// Factor overflow container child bounds into the overflow area
|
||||
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea,
|
||||
overflowContainerBounds);
|
||||
|
||||
// see if verifyReflow is enabled, and if so store off the space manager pointer
|
||||
#ifdef DEBUG
|
||||
|
@ -1261,9 +1278,19 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
// We may have stretched the frame beyond its computed height. Oh well.
|
||||
computedHeightLeftOver = PR_MAX(0, computedHeightLeftOver);
|
||||
}
|
||||
NS_ASSERTION(!( (mState & NS_FRAME_IS_OVERFLOW_CONTAINER)
|
||||
&& computedHeightLeftOver ),
|
||||
"overflow container must not have computedHeightLeftOver");
|
||||
|
||||
aMetrics.height = borderPadding.top + computedHeightLeftOver + borderPadding.bottom;
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(aState.mReflowStatus)
|
||||
&& aMetrics.height < aReflowState.availableHeight) {
|
||||
// We ran out of height on this page but we're incomplete
|
||||
// Set status to complete except for overflow
|
||||
NS_FRAME_SET_OVERFLOW_INCOMPLETE(aState.mReflowStatus);
|
||||
}
|
||||
|
||||
if (NS_FRAME_IS_COMPLETE(aState.mReflowStatus)) {
|
||||
aMetrics.height = borderPadding.top + computedHeightLeftOver + borderPadding.bottom;
|
||||
if (computedHeightLeftOver > 0 &&
|
||||
aMetrics.height > aReflowState.availableHeight) {
|
||||
// We don't fit and we consumed some of the computed height,
|
||||
|
@ -1273,7 +1300,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|||
// border/padding to the next page/column.
|
||||
aMetrics.height = PR_MAX(aReflowState.availableHeight,
|
||||
aState.mY + nonCarriedOutVerticalMargin);
|
||||
aState.mReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
||||
NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
|
||||
if (!GetNextInFlow())
|
||||
aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -1860,6 +1889,11 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// used.
|
||||
deltaY = line->mBounds.YMost() - oldYMost;
|
||||
} else {
|
||||
aState.mOverflowTracker.Skip(line->mFirstChild, aState.mReflowStatus);
|
||||
// Nop except for blocks (we don't create overflow container
|
||||
// continuations for any inlines atm), so only checking mFirstChild
|
||||
// is enough
|
||||
|
||||
lastLineMovedUp = deltaY < 0;
|
||||
|
||||
if (deltaY != 0)
|
||||
|
@ -1926,15 +1960,14 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// didn't change)
|
||||
// XXXldb We should also check that the first line of the next-in-flow
|
||||
// isn't dirty.
|
||||
if (!aState.mNextInFlow ||
|
||||
if (aState.mNextInFlow &&
|
||||
(aState.mReflowState.mFlags.mNextInFlowUntouched &&
|
||||
!lastLineMovedUp &&
|
||||
!(GetStateBits() & NS_FRAME_IS_DIRTY) &&
|
||||
!reflowedFloat)) {
|
||||
if (aState.mNextInFlow) {
|
||||
aState.mReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
||||
}
|
||||
} else {
|
||||
NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
|
||||
}
|
||||
else if (aState.mNextInFlow) {
|
||||
// Pull data from a next-in-flow if there's still room for more
|
||||
// content here.
|
||||
while (keepGoing && (nsnull != aState.mNextInFlow)) {
|
||||
|
@ -2041,7 +2074,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(aState.mReflowStatus)) {
|
||||
aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
}
|
||||
} //XXXfr shouldn't set this flag when nextinflow has no lines
|
||||
}
|
||||
|
||||
// Handle an odd-ball case: a list-item with no lines
|
||||
|
@ -2926,7 +2959,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
UndoSplitPlaceholders(aState, lastPlaceholder);
|
||||
PushLines(aState, aLine.prev());
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
|
||||
}
|
||||
else {
|
||||
// Note: line-break-after a block is a nop
|
||||
|
@ -2962,65 +2995,113 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
|
||||
// Continue the block frame now if it didn't completely fit in
|
||||
// the available space.
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
|
||||
if (!NS_FRAME_IS_FULLY_COMPLETE(frameReflowStatus)) {
|
||||
PRBool madeContinuation;
|
||||
rv = CreateContinuationFor(aState, nsnull, frame, madeContinuation);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIFrame* nextFrame = frame->GetNextInFlow();
|
||||
NS_ASSERTION(nextFrame, "We're supposed to have a next-in-flow by now");
|
||||
|
||||
// Push continuation to a new line, but only if we actually made one.
|
||||
if (madeContinuation) {
|
||||
nsLineBox* line = aState.NewLineBox(nextFrame, 1, PR_TRUE);
|
||||
NS_ENSURE_TRUE(line, NS_ERROR_OUT_OF_MEMORY);
|
||||
mLines.after_insert(aLine, line);
|
||||
}
|
||||
|
||||
// Advance to next line since some of the block fit. That way
|
||||
// only the following lines will be pushed.
|
||||
PushLines(aState, aLine);
|
||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
// If we need to reflow the continuation of the block child,
|
||||
// then we'd better reflow our continuation
|
||||
if (frameReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) {
|
||||
aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
// We also need to make that continuation's line dirty so
|
||||
// it gets reflowed when we reflow our next in flow. The
|
||||
// nif's line must always be either a line of the nif's
|
||||
// parent block (only if we didn't make a continuation) or
|
||||
// else one of our own overflow lines. In the latter case
|
||||
// the line is already marked dirty, so just handle the
|
||||
// first case.
|
||||
if (!madeContinuation) {
|
||||
nsBlockFrame* nifBlock = static_cast<nsBlockFrame*>(nextFrame->GetParent());
|
||||
NS_ASSERTION(nifBlock->GetType() == nsGkAtoms::blockFrame
|
||||
|| nifBlock->GetType() == nsGkAtoms::areaFrame,
|
||||
"A block's child's next in flow's parent must be a block!");
|
||||
for (line_iterator line = nifBlock->begin_lines(),
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
|
||||
// If nextFrame used to be an overflow container, make it a normal block
|
||||
if (!madeContinuation &&
|
||||
(NS_FRAME_IS_OVERFLOW_CONTAINER & nextFrame->GetStateBits())) {
|
||||
aState.mOverflowTracker.Finish(frame);
|
||||
nsContainerFrame* parent =
|
||||
static_cast<nsContainerFrame*>(nextFrame->GetParent());
|
||||
rv = parent->StealFrame(aState.mPresContext, nextFrame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
ReparentFrame(nextFrame, parent, this);
|
||||
nextFrame->SetNextSibling(frame->GetNextSibling());
|
||||
frame->SetNextSibling(nextFrame);
|
||||
madeContinuation = PR_TRUE; // needs to be added to mLines
|
||||
nextFrame->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
|
||||
frameReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
}
|
||||
|
||||
// Push continuation to a new line, but only if we actually made one.
|
||||
if (madeContinuation) {
|
||||
nsLineBox* line = aState.NewLineBox(nextFrame, 1, PR_TRUE);
|
||||
NS_ENSURE_TRUE(line, NS_ERROR_OUT_OF_MEMORY);
|
||||
mLines.after_insert(aLine, line);
|
||||
}
|
||||
|
||||
PushLines(aState, aLine);
|
||||
NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
|
||||
|
||||
// If we need to reflow the continuation of the block child,
|
||||
// then we'd better reflow our continuation
|
||||
if (frameReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) {
|
||||
aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
// We also need to make that continuation's line dirty so
|
||||
// it gets reflowed when we reflow our next in flow. The
|
||||
// nif's line must always be either a line of the nif's
|
||||
// parent block (only if we didn't make a continuation) or
|
||||
// else one of our own overflow lines. In the latter case
|
||||
// the line is already marked dirty, so just handle the
|
||||
// first case.
|
||||
if (!madeContinuation) {
|
||||
nsBlockFrame* nifBlock = static_cast<nsBlockFrame*>(nextFrame->GetParent());
|
||||
NS_ASSERTION(nifBlock->GetType() == nsGkAtoms::blockFrame
|
||||
|| nifBlock->GetType() == nsGkAtoms::areaFrame,
|
||||
"A block's child's next in flow's parent must be a block!");
|
||||
for (line_iterator line = nifBlock->begin_lines(),
|
||||
line_end = nifBlock->end_lines(); line != line_end; ++line) {
|
||||
if (line->Contains(nextFrame)) {
|
||||
line->MarkDirty();
|
||||
break;
|
||||
if (line->Contains(nextFrame)) {
|
||||
line->MarkDirty();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
|
||||
// The bottom margin for a block is only applied on the last
|
||||
// flow block. Since we just continued the child block frame,
|
||||
// we know that line->mFirstChild is not the last flow block
|
||||
// therefore zero out the running margin value.
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
|
||||
// The bottom margin for a block is only applied on the last
|
||||
// flow block. Since we just continued the child block frame,
|
||||
// we know that line->mFirstChild is not the last flow block
|
||||
// therefore zero out the running margin value.
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
ListTag(stdout);
|
||||
printf(": reflow incomplete, frame=");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(" prevBottomMargin=%d, setting to zero\n",
|
||||
aState.mPrevBottomMargin);
|
||||
ListTag(stdout);
|
||||
printf(": reflow incomplete, frame=");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(" prevBottomMargin=%d, setting to zero\n",
|
||||
aState.mPrevBottomMargin);
|
||||
#endif
|
||||
aState.mPrevBottomMargin.Zero();
|
||||
aState.mPrevBottomMargin.Zero();
|
||||
}
|
||||
else { // frame is complete but its overflow is not complete
|
||||
// Disconnect the next-in-flow and put it in our overflow tracker
|
||||
if (!madeContinuation &&
|
||||
!(NS_FRAME_IS_OVERFLOW_CONTAINER & nextFrame->GetStateBits())) {
|
||||
// It already exists, but as a normal next-in-flow, so we need
|
||||
// to dig it out of the child lists.
|
||||
nsContainerFrame* parent = static_cast<nsContainerFrame*>
|
||||
(nextFrame->GetParent());
|
||||
rv = parent->StealFrame(aState.mPresContext, nextFrame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else if (madeContinuation) {
|
||||
frame->SetNextSibling(nextFrame->GetNextSibling());
|
||||
nextFrame->SetNextSibling(nsnull);
|
||||
}
|
||||
|
||||
// Put it in our overflow list
|
||||
aState.mOverflowTracker.Insert(nextFrame, frameReflowStatus);
|
||||
aState.mReflowStatus = NS_FRAME_MERGE_INCOMPLETE(frameReflowStatus,
|
||||
aState.mReflowStatus);
|
||||
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
ListTag(stdout);
|
||||
printf(": reflow complete but overflow incomplete for ");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(" prevBottomMargin=%d collapsedBottomMargin=%d\n",
|
||||
aState.mPrevBottomMargin, collapsedBottomMargin.get());
|
||||
#endif
|
||||
aState.mPrevBottomMargin = collapsedBottomMargin;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else { // frame is fully complete
|
||||
#ifdef NOISY_VERTICAL_MARGINS
|
||||
ListTag(stdout);
|
||||
printf(": reflow complete for ");
|
||||
|
@ -3052,7 +3133,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// to our next-in-flow.
|
||||
UndoSplitPlaceholders(aState, lastPlaceholder);
|
||||
PushLines(aState, aLine.prev());
|
||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3174,7 +3255,7 @@ nsBlockFrame::PushTruncatedPlaceholderLine(nsBlockReflowState& aState,
|
|||
--prevLine;
|
||||
PushLines(aState, prevLine);
|
||||
aKeepReflowGoing = PR_FALSE;
|
||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -3927,7 +4008,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// Stop reflow and whack the reflow status if reflow hasn't
|
||||
// already been stopped.
|
||||
if (*aKeepReflowGoing) {
|
||||
aState.mReflowStatus |= NS_FRAME_NOT_COMPLETE;
|
||||
NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
|
@ -4946,7 +5027,8 @@ nsBlockFrame::DoRemoveOutOfFlowFrame(nsIFrame* aFrame)
|
|||
|
||||
// The containing block is always the parent of aFrame.
|
||||
nsBlockFrame* block = (nsBlockFrame*)aFrame->GetParent();
|
||||
// Remove aFrame from the appropriate list.
|
||||
|
||||
// Remove aFrame from the appropriate list.
|
||||
if (display->IsAbsolutelyPositioned()) {
|
||||
block->mAbsoluteContainer.RemoveFrame(block,
|
||||
block->mAbsoluteContainer.GetChildListName(),
|
||||
|
@ -5014,6 +5096,11 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, PRBool aDestroyFrames,
|
|||
nsPresContext* presContext = PresContext();
|
||||
nsIPresShell* presShell = presContext->PresShell();
|
||||
|
||||
if (NS_FRAME_IS_OVERFLOW_CONTAINER & aDeletedFrame->GetStateBits()) {
|
||||
nsContainerFrame::DeleteNextInFlowChild(presContext, aDeletedFrame);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool isPlaceholder = nsGkAtoms::placeholderFrame == aDeletedFrame->GetType();
|
||||
if (isPlaceholder) {
|
||||
nsFrameList* overflowPlaceholders = GetOverflowPlaceholders();
|
||||
|
@ -5222,15 +5309,91 @@ found_frame:;
|
|||
return RemoveBlockChild(aDeletedFrame, aDestroyFrames);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::StealFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aChild,
|
||||
PRBool aForceNormal)
|
||||
{
|
||||
NS_PRECONDITION(aPresContext && aChild, "null pointer");
|
||||
|
||||
if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
|
||||
&& !aForceNormal)
|
||||
return nsContainerFrame::StealFrame(aPresContext, aChild);
|
||||
|
||||
// Find the line and the previous sibling that contains
|
||||
// aChild; we also find the pointer to the line.
|
||||
nsLineList::iterator line = mLines.begin(),
|
||||
line_end = mLines.end();
|
||||
PRBool searchingOverflowList = PR_FALSE;
|
||||
nsIFrame* prevSibling = nsnull;
|
||||
// Make sure we look in the overflow lines even if the normal line
|
||||
// list is empty
|
||||
TryAllLines(&line, &line_end, &searchingOverflowList);
|
||||
while (line != line_end) {
|
||||
nsIFrame* frame = line->mFirstChild;
|
||||
PRInt32 n = line->GetChildCount();
|
||||
while (--n >= 0) {
|
||||
if (frame == aChild) {
|
||||
// Disconnect from sibling list
|
||||
if (prevSibling)
|
||||
prevSibling->SetNextSibling(frame->GetNextSibling());
|
||||
else
|
||||
line->mFirstChild = frame->GetNextSibling();
|
||||
frame->SetNextSibling(nsnull);
|
||||
|
||||
// Register removal with the line boxes
|
||||
PRInt32 count = line->GetChildCount();
|
||||
line->SetChildCount(--count);
|
||||
if (count > 0) {
|
||||
line->MarkDirty();
|
||||
}
|
||||
else {
|
||||
// Remove the line box
|
||||
nsLineBox* lineBox = line;
|
||||
if (searchingOverflowList) {
|
||||
// Erase line, but avoid making the overflow line list empty
|
||||
nsLineList* lineList = RemoveOverflowLines();
|
||||
lineList->erase(line);
|
||||
if (!lineList->empty()) {
|
||||
nsresult rv = SetOverflowLines(lineList);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mLines.erase(line);
|
||||
}
|
||||
lineBox->Destroy(aPresContext->PresShell());
|
||||
if (line != line_end) {
|
||||
// Line disappeared, so tell next line it may have to change position
|
||||
line->MarkPreviousMarginDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// Ok, we're done
|
||||
return NS_OK;
|
||||
}
|
||||
prevSibling = frame;
|
||||
frame = frame->GetNextSibling();
|
||||
}
|
||||
++line;
|
||||
TryAllLines(&line, &line_end, &searchingOverflowList);
|
||||
}
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
|
||||
nsIFrame* aNextInFlow)
|
||||
{
|
||||
nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
|
||||
NS_PRECONDITION(prevInFlow, "bad next-in-flow");
|
||||
NS_PRECONDITION(IsChild(aNextInFlow), "bad geometric parent");
|
||||
|
||||
DoRemoveFrame(aNextInFlow);
|
||||
if (NS_FRAME_IS_OVERFLOW_CONTAINER & aNextInFlow->GetStateBits()) {
|
||||
nsContainerFrame::DeleteNextInFlowChild(aPresContext, aNextInFlow);
|
||||
}
|
||||
else {
|
||||
DoRemoveFrame(aNextInFlow);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -5329,6 +5492,10 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
|
|||
// if the height is constrained (bug 145305).
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && (NS_UNCONSTRAINEDSIZE == availHeight))
|
||||
aReflowStatus = NS_FRAME_COMPLETE;
|
||||
|
||||
//XXXfr Floats can't be overflow incomplete yet
|
||||
if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aReflowStatus))
|
||||
NS_FRAME_SET_INCOMPLETE(aReflowStatus);
|
||||
|
||||
if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
|
||||
// Float is now complete, so delete the placeholder's next in
|
||||
|
@ -5410,9 +5577,12 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
|
|||
// get the containing block of prevPlaceholder which is our prev-in-flow
|
||||
if (GetPrevInFlow()) {
|
||||
// get the break type of the last line in mPrevInFlow
|
||||
line_iterator endLine = --((nsBlockFrame*)GetPrevInFlow())->end_lines();
|
||||
if (endLine->HasFloatBreakAfter()) {
|
||||
aState.mFloatBreakType = endLine->GetBreakTypeAfter();
|
||||
nsBlockFrame* prevBlock = static_cast<nsBlockFrame*>(GetPrevInFlow());
|
||||
line_iterator endLine = prevBlock->end_lines();
|
||||
if (endLine != prevBlock->begin_lines()) {
|
||||
--endLine;
|
||||
if (endLine->HasFloatBreakAfter())
|
||||
aState.mFloatBreakType = endLine->GetBreakTypeAfter();
|
||||
}
|
||||
}
|
||||
else NS_ASSERTION(PR_FALSE, "no prev in flow");
|
||||
|
@ -5427,11 +5597,15 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
|
|||
PRIntn
|
||||
nsBlockFrame::GetSkipSides() const
|
||||
{
|
||||
if (mState & NS_FRAME_IS_OVERFLOW_CONTAINER)
|
||||
return (1 << NS_SIDE_TOP) | (1 << NS_SIDE_BOTTOM);
|
||||
|
||||
PRIntn skip = 0;
|
||||
if (nsnull != GetPrevInFlow()) {
|
||||
if (GetPrevInFlow()) {
|
||||
skip |= 1 << NS_SIDE_TOP;
|
||||
}
|
||||
if (nsnull != GetNextInFlow()) {
|
||||
nsIFrame* nif = GetNextInFlow();
|
||||
if (nif && !(nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
|
||||
skip |= 1 << NS_SIDE_BOTTOM;
|
||||
}
|
||||
return skip;
|
||||
|
@ -5629,7 +5803,11 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
#endif
|
||||
|
||||
DisplayBorderBackgroundOutline(aBuilder, aLists);
|
||||
|
||||
|
||||
if (GetPrevInFlow()) {
|
||||
DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
|
||||
}
|
||||
|
||||
aBuilder->MarkFramesForDisplayList(this, mFloats.FirstChild(), aDirtyRect);
|
||||
aBuilder->MarkFramesForDisplayList(this, mAbsoluteContainer.GetFirstChild(), aDirtyRect);
|
||||
|
||||
|
@ -5890,43 +6068,6 @@ InSiblingList(nsLineList& aLines, nsIFrame* aFrame)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBlockFrame::IsChild(nsIFrame* aFrame)
|
||||
{
|
||||
// Continued out-of-flows don't satisfy InLineList(), continued out-of-flows
|
||||
// and placeholders don't satisfy InSiblingList().
|
||||
PRBool skipLineList = PR_FALSE;
|
||||
PRBool skipSiblingList = PR_FALSE;
|
||||
nsIFrame* prevInFlow = aFrame->GetPrevInFlow();
|
||||
PRBool isPlaceholder = nsGkAtoms::placeholderFrame == aFrame->GetType();
|
||||
if (prevInFlow) {
|
||||
nsFrameState state = aFrame->GetStateBits();
|
||||
skipLineList = (state & NS_FRAME_OUT_OF_FLOW);
|
||||
skipSiblingList = isPlaceholder || (state & NS_FRAME_OUT_OF_FLOW);
|
||||
}
|
||||
|
||||
if (isPlaceholder) {
|
||||
nsFrameList* overflowPlaceholders = GetOverflowPlaceholders();
|
||||
if (overflowPlaceholders && overflowPlaceholders->ContainsFrame(aFrame)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (aFrame->GetParent() != (nsIFrame*)this) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
if ((skipLineList || InLineList(mLines, aFrame)) &&
|
||||
(skipSiblingList || InSiblingList(mLines, aFrame))) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
nsLineList* overflowLines = GetOverflowLines();
|
||||
if (overflowLines && (skipLineList || InLineList(*overflowLines, aFrame)) &&
|
||||
(skipSiblingList || InSiblingList(*overflowLines, aFrame))) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::VerifyTree() const
|
||||
{
|
||||
|
|
|
@ -79,12 +79,7 @@ class nsIntervalSet;
|
|||
* Child list name indices
|
||||
* @see #GetAdditionalChildListName()
|
||||
*/
|
||||
#define NS_BLOCK_FRAME_FLOAT_LIST_INDEX 0
|
||||
#define NS_BLOCK_FRAME_BULLET_LIST_INDEX 1
|
||||
#define NS_BLOCK_FRAME_OVERFLOW_LIST_INDEX 2
|
||||
#define NS_BLOCK_FRAME_OVERFLOW_OOF_LIST_INDEX 3
|
||||
#define NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX 4
|
||||
#define NS_BLOCK_FRAME_LAST_LIST_INDEX NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX
|
||||
#define NS_BLOCK_LIST_COUNT (NS_CONTAINER_LIST_COUNT_INCL_OC + 4)
|
||||
|
||||
/**
|
||||
* Some invariants:
|
||||
|
@ -186,6 +181,12 @@ public:
|
|||
nscoord aX, nscoord aY, nsIFrame* aForChild,
|
||||
PRBool aImmediate);
|
||||
virtual nsIAtom* GetType() const;
|
||||
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
|
||||
{
|
||||
return nsContainerFrame::IsFrameOfType(aFlags &
|
||||
~(nsIFrame::eCanContainOverflowContainers));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
||||
NS_IMETHOD_(nsFrameState) GetDebugStateBits() const;
|
||||
|
@ -241,6 +242,10 @@ public:
|
|||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType);
|
||||
|
||||
virtual nsresult StealFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aChild,
|
||||
PRBool aForceNormal);
|
||||
|
||||
virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
|
||||
nsIFrame* aNextInFlow);
|
||||
|
||||
|
@ -584,7 +589,6 @@ protected:
|
|||
nsIFrame* LastChild();
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PRBool IsChild(nsIFrame* aFrame);
|
||||
void VerifyLines(PRBool aFinalCheckOK);
|
||||
void VerifyOverflowSituation();
|
||||
PRInt32 GetDepth() const;
|
||||
|
|
|
@ -400,7 +400,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
|
|||
// them now. Do not do this when a break-before is signaled because
|
||||
// the frame is going to get reflowed again (and may end up wanting
|
||||
// a next-in-flow where it ends up), unless it is an out of flow frame.
|
||||
if (NS_FRAME_IS_COMPLETE(aFrameReflowStatus)) {
|
||||
if (NS_FRAME_IS_FULLY_COMPLETE(aFrameReflowStatus)) {
|
||||
nsIFrame* kidNextInFlow = mFrame->GetNextInFlow();
|
||||
if (nsnull != kidNextInFlow) {
|
||||
// Remove all of the childs next-in-flows. Make sure that we ask
|
||||
|
|
|
@ -71,9 +71,12 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mPrevBottomMargin(),
|
||||
mLineNumber(0),
|
||||
mFlags(0),
|
||||
mFloatBreakType(NS_STYLE_CLEAR_NONE)
|
||||
mFloatBreakType(NS_STYLE_CLEAR_NONE),
|
||||
mOverflowTracker(aPresContext, aFrame)
|
||||
{
|
||||
SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nsnull);
|
||||
SetFlag(BRS_ISOVERFLOWCONTAINER,
|
||||
!!(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER));
|
||||
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "nsBlockBandData.h"
|
||||
#include "nsLineBox.h"
|
||||
#include "nsFrameList.h"
|
||||
#include "nsContainerFrame.h"
|
||||
|
||||
class nsBlockFrame;
|
||||
|
||||
|
@ -59,7 +60,8 @@ class nsBlockFrame;
|
|||
#define BRS_HAVELINEADJACENTTOTOP 0x00000020
|
||||
// Set when the block has the equivalent of NS_BLOCK_SPACE_MGR
|
||||
#define BRS_SPACE_MGR 0x00000040
|
||||
#define BRS_LASTFLAG BRS_SPACE_MGR
|
||||
#define BRS_ISOVERFLOWCONTAINER 0x00000100
|
||||
#define BRS_LASTFLAG BRS_ISOVERFLOWCONTAINER
|
||||
|
||||
class nsBlockReflowState {
|
||||
public:
|
||||
|
@ -123,6 +125,9 @@ public:
|
|||
nsMargin result = mReflowState.mComputedBorderPadding;
|
||||
if (!(mFlags & BRS_ISFIRSTINFLOW)) {
|
||||
result.top = 0;
|
||||
if (mFlags & BRS_ISOVERFLOWCONTAINER) {
|
||||
result.bottom = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -196,6 +201,9 @@ public:
|
|||
// the overflow lines.
|
||||
nsFrameList mOverflowPlaceholders;
|
||||
|
||||
// Track child overflow continuations.
|
||||
nsOverflowContinuationTracker mOverflowTracker;
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is "running" state updated by the reflow of each line
|
||||
|
|
|
@ -75,7 +75,14 @@ public:
|
|||
virtual nsIFrame* GetContentInsertionFrame() {
|
||||
return GetFirstChild(nsnull)->GetContentInsertionFrame();
|
||||
}
|
||||
|
||||
|
||||
virtual nsresult StealFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aChild,
|
||||
PRBool aForceNormal)
|
||||
{ // nsColumnSetFrame keeps overflow containers in main child list
|
||||
return nsContainerFrame::StealFrame(aPresContext, aChild, PR_TRUE);
|
||||
}
|
||||
|
||||
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists);
|
||||
|
@ -440,9 +447,9 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
|
|||
// might be pullable back to this column. We can't skip if it's the last child
|
||||
// because we need to obtain the bottom margin.
|
||||
PRBool skipIncremental = !(GetStateBits() & NS_FRAME_IS_DIRTY)
|
||||
&& !(child->GetStateBits() & NS_FRAME_IS_DIRTY)
|
||||
&& !NS_SUBTREE_DIRTY(child)
|
||||
&& child->GetNextSibling()
|
||||
&& !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY);
|
||||
&& !NS_SUBTREE_DIRTY(child->GetNextSibling());
|
||||
// If we need to pull up content from the prev-in-flow then this is not just
|
||||
// a height shrink. The prev in flow will have set the dirty bit.
|
||||
// Check the overflow rect YMost instead of just the child's content height. The child
|
||||
|
@ -457,8 +464,11 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
|
|||
MoveChildTo(this, child, childOrigin);
|
||||
|
||||
// If this is the last frame then make sure we get the right status
|
||||
if (child->GetNextSibling()) {
|
||||
aStatus = NS_FRAME_NOT_COMPLETE;
|
||||
nsIFrame* kidNext = child->GetNextSibling();
|
||||
if (kidNext) {
|
||||
aStatus = (kidNext->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
|
||||
? NS_FRAME_OVERFLOW_INCOMPLETE
|
||||
: NS_FRAME_NOT_COMPLETE;
|
||||
} else {
|
||||
aStatus = mLastFrameStatus;
|
||||
}
|
||||
|
@ -536,7 +546,7 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
|
|||
// Build a continuation column if necessary
|
||||
nsIFrame* kidNextInFlow = child->GetNextInFlow();
|
||||
|
||||
if (NS_FRAME_IS_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)) {
|
||||
if (NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)) {
|
||||
NS_ASSERTION(!kidNextInFlow, "next in flow should have been deleted");
|
||||
break;
|
||||
} else {
|
||||
|
@ -557,6 +567,21 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we reflow a next-in-flow when it switches between being
|
||||
// normal or overflow container
|
||||
if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
|
||||
if (!(kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
|
||||
aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
reflowNext = PR_TRUE;
|
||||
kidNextInFlow->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
|
||||
}
|
||||
}
|
||||
else if (kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
|
||||
aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
reflowNext = PR_TRUE;
|
||||
kidNextInFlow->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
|
||||
}
|
||||
|
||||
if (columnCount >= aConfig.mBalanceColCount) {
|
||||
// No more columns allowed here. Stop.
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Elika J. Etemad ("fantasai") <fantasai@inkedblade.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -39,6 +40,7 @@
|
|||
/* base class #1 for rendering objects that have child lists */
|
||||
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsPresContext.h"
|
||||
|
@ -218,6 +220,10 @@ nsContainerFrame::RemoveFrame(nsIAtom* aListName,
|
|||
// remove the frame from its parents list and generate a reflow
|
||||
// command.
|
||||
nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation();
|
||||
//XXXfr probably should use StealFrame here. I'm not sure if we need to
|
||||
// check the overflow lists atm, but we'll need a prescontext lookup
|
||||
// for overflow containers once we can split abspos elements with
|
||||
// inline containing blocks.
|
||||
parent->mFrames.DestroyFrame(aOldFrame);
|
||||
aOldFrame = oldFrameNextContinuation;
|
||||
if (aOldFrame) {
|
||||
|
@ -244,11 +250,25 @@ nsContainerFrame::Destroy()
|
|||
|
||||
// Delete the primary child list
|
||||
mFrames.DestroyFrames();
|
||||
|
||||
// Destroy overflow frames now
|
||||
nsFrameList overflowFrames(GetOverflowFrames(PresContext(), PR_TRUE));
|
||||
|
||||
// Destroy auxiliary frame lists
|
||||
nsPresContext* prescontext = PresContext();
|
||||
|
||||
nsFrameList overflowFrames(GetOverflowFrames(prescontext, PR_TRUE));
|
||||
overflowFrames.DestroyFrames();
|
||||
|
||||
if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
|
||||
nsFrameList* frameList = RemovePropTableFrames(prescontext,
|
||||
nsGkAtoms::overflowContainersProperty);
|
||||
if (frameList)
|
||||
frameList->Destroy();
|
||||
|
||||
frameList = RemovePropTableFrames(prescontext,
|
||||
nsGkAtoms::excessOverflowContainersProperty);
|
||||
if (frameList)
|
||||
frameList->Destroy();
|
||||
}
|
||||
|
||||
if (IsGeneratedContentFrame()) {
|
||||
// Make sure all the content nodes for the generated content inside
|
||||
// this frame know it's going away.
|
||||
|
@ -286,19 +306,38 @@ nsContainerFrame::GetFirstChild(nsIAtom* aListName) const
|
|||
return mFrames.FirstChild();
|
||||
} else if (nsGkAtoms::overflowList == aListName) {
|
||||
return GetOverflowFrames(PresContext(), PR_FALSE);
|
||||
} else if (nsGkAtoms::overflowContainersList == aListName) {
|
||||
nsFrameList* list = GetPropTableFrames(PresContext(),
|
||||
nsGkAtoms::overflowContainersProperty);
|
||||
return (list) ? list->FirstChild() : nsnull;
|
||||
} else if (nsGkAtoms::excessOverflowContainersList == aListName) {
|
||||
nsFrameList* list = GetPropTableFrames(PresContext(),
|
||||
nsGkAtoms::excessOverflowContainersProperty);
|
||||
return (list) ? list->FirstChild() : nsnull;
|
||||
|
||||
} else {
|
||||
return nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
#define NS_CONTAINER_FRAME_OVERFLOW_LIST_INDEX 0
|
||||
#define NS_CONTAINER_FRAME_OVERFLOW_CONTAINERS_LIST_INDEX 1
|
||||
#define NS_CONTAINER_FRAME_EXCESS_OVERFLOW_CONTAINERS_LIST_INDEX 2
|
||||
// If adding/removing lists, don't forget to update count in .h file
|
||||
|
||||
|
||||
nsIAtom*
|
||||
nsContainerFrame::GetAdditionalChildListName(PRInt32 aIndex) const
|
||||
{
|
||||
if (aIndex == 0) {
|
||||
if (NS_CONTAINER_FRAME_OVERFLOW_LIST_INDEX == aIndex)
|
||||
return nsGkAtoms::overflowList;
|
||||
} else {
|
||||
return nsnull;
|
||||
else if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
|
||||
if (NS_CONTAINER_FRAME_OVERFLOW_CONTAINERS_LIST_INDEX == aIndex)
|
||||
return nsGkAtoms::overflowContainersList;
|
||||
else if (NS_CONTAINER_FRAME_EXCESS_OVERFLOW_CONTAINERS_LIST_INDEX == aIndex)
|
||||
return nsGkAtoms::excessOverflowContainersList;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -652,7 +691,8 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
|
|||
nscoord aX,
|
||||
nscoord aY,
|
||||
PRUint32 aFlags,
|
||||
nsReflowStatus& aStatus)
|
||||
nsReflowStatus& aStatus,
|
||||
nsOverflowContinuationTracker* aTracker)
|
||||
{
|
||||
NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state");
|
||||
|
||||
|
@ -676,7 +716,8 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
|
|||
|
||||
// If the reflow was successful and the child frame is complete, delete any
|
||||
// next-in-flows
|
||||
if (NS_SUCCEEDED(result) && NS_FRAME_IS_COMPLETE(aStatus)) {
|
||||
if (NS_SUCCEEDED(result) && NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
|
||||
if (aTracker) aTracker->Finish(aKidFrame);
|
||||
nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
|
||||
if (nsnull != kidNextInFlow) {
|
||||
// Remove all of the childs next-in-flows. Make sure that we ask
|
||||
|
@ -788,6 +829,167 @@ nsContainerFrame::FinishReflowChild(nsIFrame* aKidFrame,
|
|||
return aKidFrame->DidReflow(aPresContext, aReflowState, NS_FRAME_REFLOW_FINISHED);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsRect& aOverflowRect,
|
||||
PRUint32 aFlags,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_PRECONDITION(aPresContext, "null pointer");
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsFrameList* overflowContainers =
|
||||
GetPropTableFrames(aPresContext,
|
||||
nsGkAtoms::overflowContainersProperty);
|
||||
|
||||
NS_ASSERTION(!(overflowContainers && GetPrevInFlow()
|
||||
&& static_cast<nsContainerFrame*>(GetPrevInFlow())
|
||||
->GetPropTableFrames(aPresContext,
|
||||
nsGkAtoms::excessOverflowContainersProperty)),
|
||||
"conflicting overflow containers lists");
|
||||
|
||||
if (!overflowContainers) {
|
||||
// Drain excess from previnflow
|
||||
nsContainerFrame* prev = (nsContainerFrame*) GetPrevInFlow();
|
||||
if (prev) {
|
||||
nsFrameList* excessFrames =
|
||||
prev->RemovePropTableFrames(aPresContext,
|
||||
nsGkAtoms::excessOverflowContainersProperty);
|
||||
if (excessFrames) {
|
||||
nsFrameList reparenter;
|
||||
reparenter.InsertFrames(this, nsnull, excessFrames->FirstChild());
|
||||
nsHTMLContainerFrame::ReparentFrameViewList(aPresContext,
|
||||
excessFrames->FirstChild(),
|
||||
prev, this);
|
||||
overflowContainers = excessFrames;
|
||||
rv = SetPropTableFrames(aPresContext, overflowContainers,
|
||||
nsGkAtoms::overflowContainersProperty);
|
||||
if (NS_FAILED(rv)) {
|
||||
excessFrames->DestroyFrames();
|
||||
delete excessFrames;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!overflowContainers)
|
||||
return NS_OK; // nothing to reflow
|
||||
|
||||
nsOverflowContinuationTracker tracker(aPresContext, this, PR_FALSE);
|
||||
for (nsIFrame* frame = overflowContainers->FirstChild(); frame;
|
||||
frame = frame->GetNextSibling()) {
|
||||
if (NS_SUBTREE_DIRTY(frame)) {
|
||||
// Get prev-in-flow
|
||||
nsIFrame* prevInFlow = frame->GetPrevInFlow();
|
||||
NS_ASSERTION(prevInFlow,
|
||||
"overflow container frame must have a prev-in-flow");
|
||||
NS_ASSERTION(frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
|
||||
"overflow container frame must have overflow container bit set");
|
||||
nsRect prevRect = prevInFlow->GetRect();
|
||||
|
||||
// Initialize reflow params
|
||||
nsSize availSpace(prevRect.width, aReflowState.availableHeight);
|
||||
nsHTMLReflowMetrics desiredSize;
|
||||
nsHTMLReflowState frameState(aPresContext, aReflowState,
|
||||
frame, availSpace);
|
||||
nsReflowStatus frameStatus = NS_FRAME_COMPLETE;
|
||||
|
||||
// Reflow
|
||||
rv = ReflowChild(frame, aPresContext, desiredSize, frameState,
|
||||
prevRect.x, 0, aFlags, frameStatus);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
//XXXfr Do we need to override any shrinkwrap effects here?
|
||||
// e.g. desiredSize.width = prevRect.width;
|
||||
rv = FinishReflowChild(frame, aPresContext, &frameState, desiredSize,
|
||||
prevRect.x, 0, aFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Handle continuations
|
||||
NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus),
|
||||
"overflow container frames can't be incomplete, only overflow-incomplete");
|
||||
if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) {
|
||||
// Acquire a next-in-flow, creating it if necessary
|
||||
nsIFrame* nif = frame->GetNextInFlow();
|
||||
if (!nif) {
|
||||
rv = nsHTMLContainerFrame::CreateNextInFlow(aPresContext, this,
|
||||
frame, nif);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(frameStatus & NS_FRAME_REFLOW_NEXTINFLOW,
|
||||
"Someone forgot a REFLOW_NEXTINFLOW flag");
|
||||
frame->SetNextSibling(nif->GetNextSibling());
|
||||
nif->SetNextSibling(nsnull);
|
||||
}
|
||||
else if (!(nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
|
||||
// used to be a normal next-in-flow; steal it from the child list
|
||||
rv = static_cast<nsContainerFrame*>(nif->GetParent())
|
||||
->StealFrame(aPresContext, nif);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
tracker.Insert(nif, frameStatus);
|
||||
}
|
||||
aStatus = NS_FRAME_MERGE_INCOMPLETE(aStatus, frameStatus);
|
||||
// At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
|
||||
// but we have some unsplittable frames that, when taller than
|
||||
// availableHeight will push zero-height content into a next-in-flow.
|
||||
}
|
||||
else {
|
||||
tracker.Skip(frame, aStatus);
|
||||
}
|
||||
ConsiderChildOverflow(aOverflowRect, frame);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists)
|
||||
{
|
||||
nsFrameList* overflowconts = GetPropTableFrames(PresContext(),
|
||||
nsGkAtoms::overflowContainersProperty);
|
||||
if (overflowconts) {
|
||||
for (nsIFrame* frame = overflowconts->FirstChild(); frame;
|
||||
frame = frame->GetNextSibling()) {
|
||||
BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContainerFrame::StealFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aChild,
|
||||
PRBool aForceNormal)
|
||||
{
|
||||
PRBool removed = PR_TRUE;
|
||||
if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
|
||||
&& !aForceNormal) {
|
||||
// Try removing from the overflow container list
|
||||
if (!RemovePropTableFrame(aPresContext, aChild,
|
||||
nsGkAtoms::overflowContainersProperty)) {
|
||||
// It must be in the excess overflow container list
|
||||
removed = RemovePropTableFrame(aPresContext, aChild,
|
||||
nsGkAtoms::excessOverflowContainersProperty);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!mFrames.RemoveFrame(aChild)) {
|
||||
// We didn't find the child in the parent's principal child list.
|
||||
// Maybe it's on the overflow list?
|
||||
nsFrameList frameList(GetOverflowFrames(aPresContext, PR_TRUE));
|
||||
removed = frameList.RemoveFrame(aChild);
|
||||
if (frameList.NotEmpty()) {
|
||||
nsresult rv = SetOverflowFrames(aPresContext, frameList.FirstChild());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (removed) ? NS_OK : NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
|
||||
* pointers
|
||||
|
@ -820,21 +1022,8 @@ nsContainerFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
|
|||
nsSplittableFrame::BreakFromPrevFlow(aNextInFlow);
|
||||
|
||||
// Take the next-in-flow out of the parent's child list
|
||||
PRBool result = mFrames.RemoveFrame(aNextInFlow);
|
||||
if (!result) {
|
||||
// We didn't find the child in the parent's principal child list.
|
||||
// Maybe it's on the overflow list?
|
||||
nsFrameList overflowFrames(GetOverflowFrames(aPresContext, PR_TRUE));
|
||||
|
||||
if (overflowFrames.IsEmpty() || !overflowFrames.RemoveFrame(aNextInFlow)) {
|
||||
NS_ASSERTION(result, "failed to remove frame");
|
||||
}
|
||||
|
||||
// Set the overflow property again
|
||||
if (overflowFrames.NotEmpty()) {
|
||||
SetOverflowFrames(aPresContext, overflowFrames.FirstChild());
|
||||
}
|
||||
}
|
||||
nsresult rv = StealFrame(aPresContext, aNextInFlow);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
|
||||
|
||||
// Delete the next-in-flow frame and its descendants.
|
||||
aNextInFlow->Destroy();
|
||||
|
@ -846,15 +1035,14 @@ nsContainerFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
|
|||
* Get the frames on the overflow list
|
||||
*/
|
||||
nsIFrame*
|
||||
nsContainerFrame::GetOverflowFrames(nsPresContext* aPresContext,
|
||||
nsContainerFrame::GetOverflowFrames(nsPresContext* aPresContext,
|
||||
PRBool aRemoveProperty) const
|
||||
{
|
||||
nsPropertyTable *propTable = aPresContext->PropertyTable();
|
||||
if (aRemoveProperty) {
|
||||
return (nsIFrame*) propTable->UnsetProperty(this,
|
||||
nsGkAtoms::overflowProperty);
|
||||
nsGkAtoms::overflowProperty);
|
||||
}
|
||||
|
||||
return (nsIFrame*) propTable->GetProperty(this,
|
||||
nsGkAtoms::overflowProperty);
|
||||
}
|
||||
|
@ -893,6 +1081,67 @@ nsContainerFrame::SetOverflowFrames(nsPresContext* aPresContext,
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Destructor function for the proptable-stored framelists
|
||||
static void
|
||||
DestroyFrameList(void* aFrame,
|
||||
nsIAtom* aPropertyName,
|
||||
void* aPropertyValue,
|
||||
void* aDtorData)
|
||||
{
|
||||
if (aPropertyValue)
|
||||
static_cast<nsFrameList*>(aPropertyValue)->Destroy();
|
||||
}
|
||||
|
||||
nsFrameList*
|
||||
nsContainerFrame::GetPropTableFrames(nsPresContext* aPresContext,
|
||||
nsIAtom* aPropID) const
|
||||
{
|
||||
nsPropertyTable* propTable = aPresContext->PropertyTable();
|
||||
return static_cast<nsFrameList*>(propTable->GetProperty(this, aPropID));
|
||||
}
|
||||
|
||||
nsFrameList*
|
||||
nsContainerFrame::RemovePropTableFrames(nsPresContext* aPresContext,
|
||||
nsIAtom* aPropID) const
|
||||
{
|
||||
nsPropertyTable* propTable = aPresContext->PropertyTable();
|
||||
return static_cast<nsFrameList*>(propTable->UnsetProperty(this, aPropID));
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsContainerFrame::RemovePropTableFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIAtom* aPropID) const
|
||||
{
|
||||
nsFrameList* frameList = RemovePropTableFrames(aPresContext, aPropID);
|
||||
if (!frameList || !frameList->RemoveFrame(aFrame)) {
|
||||
// Failed to remove frame
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (frameList->IsEmpty()) {
|
||||
// Removed frame and now list is empty. Delete it.
|
||||
delete frameList;
|
||||
}
|
||||
else {
|
||||
// Removed frame, but list not empty. Put it back.
|
||||
SetPropTableFrames(aPresContext, frameList, aPropID);
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContainerFrame::SetPropTableFrames(nsPresContext* aPresContext,
|
||||
nsFrameList* aFrameList,
|
||||
nsIAtom* aPropID) const
|
||||
{
|
||||
NS_PRECONDITION(aPresContext && aPropID && aFrameList, "null ptr");
|
||||
nsresult rv = aPresContext->PropertyTable()->SetProperty(this, aPropID,
|
||||
aFrameList, DestroyFrameList, nsnull);
|
||||
NS_ASSERTION(rv != NS_PROPTABLE_PROP_OVERWRITTEN, "existing framelist");
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push aFromChild and its next siblings to the next-in-flow. Change the
|
||||
* geometric parent of each frame that's pushed. If there is no next-in-flow
|
||||
|
@ -977,6 +1226,163 @@ nsContainerFrame::MoveOverflowToChildList(nsPresContext* aPresContext)
|
|||
return result;
|
||||
}
|
||||
|
||||
nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsPresContext* aPresContext,
|
||||
nsContainerFrame* aFrame,
|
||||
PRBool aSkipOverflowContainerChildren)
|
||||
: mOverflowContList(nsnull),
|
||||
mPrevOverflowCont(nsnull),
|
||||
mSentry(nsnull),
|
||||
mParent(aFrame),
|
||||
mSkipOverflowContainerChildren(aSkipOverflowContainerChildren)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "null frame pointer");
|
||||
nsContainerFrame* next = static_cast<nsContainerFrame*>
|
||||
(aFrame->GetNextInFlow());
|
||||
if (next) {
|
||||
mOverflowContList =
|
||||
next->GetPropTableFrames(aPresContext,
|
||||
nsGkAtoms::overflowContainersProperty);
|
||||
if (mOverflowContList) {
|
||||
mParent = next;
|
||||
SetUpListWalker();
|
||||
}
|
||||
}
|
||||
else {
|
||||
mOverflowContList =
|
||||
mParent->GetPropTableFrames(aPresContext,
|
||||
nsGkAtoms::excessOverflowContainersProperty);
|
||||
if (mOverflowContList) {
|
||||
SetUpListWalker();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to walk past overflow continuations whose prev-in-flow
|
||||
* isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
|
||||
*/
|
||||
void
|
||||
nsOverflowContinuationTracker::SetUpListWalker()
|
||||
{
|
||||
NS_ASSERTION(!mSentry && !mPrevOverflowCont,
|
||||
"forgot to reset mSentry or mPrevOverflowCont");
|
||||
if (mOverflowContList) {
|
||||
nsIFrame* cur = mOverflowContList->FirstChild();
|
||||
if (mSkipOverflowContainerChildren) {
|
||||
while (cur && (cur->GetPrevInFlow()->GetStateBits()
|
||||
& NS_FRAME_IS_OVERFLOW_CONTAINER)) {
|
||||
mPrevOverflowCont = cur;
|
||||
cur = cur->GetNextSibling();
|
||||
}
|
||||
}
|
||||
if (cur) {
|
||||
mSentry = cur->GetPrevInFlow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to step forward through the overflow continuations list.
|
||||
* Sets mSentry and mPrevOverflowCont as appropriate.
|
||||
* May only be called when we have already set up an mOverflowContList;
|
||||
* mOverflowContList cannot be null.
|
||||
*/
|
||||
void
|
||||
nsOverflowContinuationTracker::StepForward()
|
||||
{
|
||||
NS_PRECONDITION(mOverflowContList, "null list");
|
||||
|
||||
// Step forward
|
||||
if (mPrevOverflowCont) {
|
||||
mPrevOverflowCont = mPrevOverflowCont->GetNextSibling();
|
||||
}
|
||||
else {
|
||||
mPrevOverflowCont = mOverflowContList->FirstChild();
|
||||
}
|
||||
|
||||
// Set up the sentry
|
||||
mSentry = (mPrevOverflowCont->GetNextSibling())
|
||||
? mPrevOverflowCont->GetNextSibling()->GetPrevInFlow()
|
||||
: nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont,
|
||||
nsReflowStatus& aReflowStatus)
|
||||
{
|
||||
NS_PRECONDITION(aOverflowCont, "null frame pointer");
|
||||
NS_PRECONDITION(aOverflowCont->GetPrevInFlow(),
|
||||
"overflow containers must have a prev-in-flow");
|
||||
nsresult rv = NS_OK;
|
||||
if (!mSentry || aOverflowCont != mSentry->GetNextInFlow()) {
|
||||
// Not in our list, so we need to add it
|
||||
nsPresContext* presContext = aOverflowCont->PresContext();
|
||||
if ((aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
|
||||
&& mParent != aOverflowCont->GetParent()) {
|
||||
// aOverflowCont is in some other frame's overflow container list,
|
||||
// steal it first
|
||||
rv = static_cast<nsContainerFrame*>(aOverflowCont->GetParent())
|
||||
->StealFrame(presContext, aOverflowCont);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(!(aOverflowCont->GetStateBits()
|
||||
& NS_FRAME_IS_OVERFLOW_CONTAINER),
|
||||
"overflow containers out of order or bad parent");
|
||||
aOverflowCont->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
|
||||
}
|
||||
if (!mOverflowContList) {
|
||||
mOverflowContList = new nsFrameList();
|
||||
rv = mParent->SetPropTableFrames(presContext,
|
||||
mOverflowContList, nsGkAtoms::excessOverflowContainersProperty);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
SetUpListWalker();
|
||||
}
|
||||
if (aOverflowCont->GetParent() != mParent) {
|
||||
nsHTMLContainerFrame::ReparentFrameView(presContext, aOverflowCont,
|
||||
aOverflowCont->GetParent(),
|
||||
mParent);
|
||||
}
|
||||
mOverflowContList->InsertFrame(mParent, mPrevOverflowCont, aOverflowCont);
|
||||
aReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
|
||||
}
|
||||
|
||||
// If we need to reflow it, mark it dirty
|
||||
if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW)
|
||||
aOverflowCont->AddStateBits(NS_FRAME_IS_DIRTY);
|
||||
|
||||
// It's in our list, just step forward
|
||||
StepForward();
|
||||
NS_ASSERTION(mPrevOverflowCont == aOverflowCont,
|
||||
"OverflowContTracker logic error");
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsOverflowContinuationTracker::Finish(nsIFrame* aChild)
|
||||
{
|
||||
NS_PRECONDITION(aChild, "null ptr");
|
||||
NS_PRECONDITION(aChild->GetNextInFlow(),
|
||||
"supposed to call Next *before* deleting next-in-flow!");
|
||||
if (aChild == mSentry) {
|
||||
// Make sure we drop all references if this was the only frame
|
||||
// in the overflow containers list
|
||||
if (mOverflowContList->FirstChild() == aChild->GetNextInFlow()
|
||||
&& !aChild->GetNextInFlow()->GetNextSibling()) {
|
||||
mOverflowContList = nsnull;
|
||||
mPrevOverflowCont = nsnull;
|
||||
mSentry = nsnull;
|
||||
mParent = static_cast<nsContainerFrame*>(aChild->GetParent());
|
||||
}
|
||||
else {
|
||||
// Don't move the mPrevOverflowCont, but shift the sentry
|
||||
// The intervening overflow continuation will be deleted by our caller
|
||||
nsIFrame* sentryCont = aChild->GetNextInFlow()->GetNextSibling();
|
||||
mSentry = (sentryCont) ? sentryCont->GetPrevInFlow() : nsnull;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Debugging
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Elika J. Etemad ("fantasai") <fantasai@inkedblade.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -44,6 +45,15 @@
|
|||
#include "nsFrameList.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
/**
|
||||
* Child list name indices
|
||||
* @see #GetAdditionalChildListName()
|
||||
*/
|
||||
#define NS_CONTAINER_LIST_COUNT_SANS_OC 1
|
||||
// for frames that don't use overflow containers
|
||||
#define NS_CONTAINER_LIST_COUNT_INCL_OC 3
|
||||
// for frames that support overflow containers
|
||||
|
||||
// Option flags for ReflowChild() and FinishReflowChild()
|
||||
// member functions
|
||||
#define NS_FRAME_NO_MOVE_VIEW 0x0001
|
||||
|
@ -51,6 +61,8 @@
|
|||
#define NS_FRAME_NO_SIZE_VIEW 0x0004
|
||||
#define NS_FRAME_NO_VISIBILITY 0x0008
|
||||
|
||||
class nsOverflowContinuationTracker;
|
||||
|
||||
/**
|
||||
* Implementation of a container frame.
|
||||
*/
|
||||
|
@ -150,14 +162,15 @@ public:
|
|||
* NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
|
||||
* case. Also implies NS_FRAME_NO_MOVE_VIEW
|
||||
*/
|
||||
nsresult ReflowChild(nsIFrame* aKidFrame,
|
||||
nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nscoord aX,
|
||||
nscoord aY,
|
||||
PRUint32 aFlags,
|
||||
nsReflowStatus& aStatus);
|
||||
nsresult ReflowChild(nsIFrame* aKidFrame,
|
||||
nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nscoord aX,
|
||||
nscoord aY,
|
||||
PRUint32 aFlags,
|
||||
nsReflowStatus& aStatus,
|
||||
nsOverflowContinuationTracker* aTracker = nsnull);
|
||||
|
||||
/**
|
||||
* The second half of frame reflow. Does the following:
|
||||
|
@ -186,7 +199,98 @@ public:
|
|||
|
||||
|
||||
static void PositionChildViews(nsIFrame* aFrame);
|
||||
|
||||
|
||||
// ==========================================================================
|
||||
/* Overflow containers are continuation frames that hold overflow. They
|
||||
* are created when the frame runs out of computed height, but still has
|
||||
* too much content to fit in the availableHeight. The parent creates a
|
||||
* continuation as usual, but marks it as NS_FRAME_IS_OVERFLOW_CONTAINER
|
||||
* and adds it to its next-in-flow's overflow container list, either by
|
||||
* adding it directly or by putting it in its own excess overflow containers
|
||||
* list (to be drained by the next-in-flow when it calls
|
||||
* ReflowOverflowContainerChildren). The parent continues reflow as if
|
||||
* the frame was complete once it ran out of computed height, but returns
|
||||
* either an NS_FRAME_NOT_COMPLETE or NS_FRAME_OVERFLOW_INCOMPLETE reflow
|
||||
* status to request a next-in-flow. The parent's next-in-flow is then
|
||||
* responsible for calling ReflowOverflowContainerChildren to (drain and)
|
||||
* reflow these overflow continuations. Overflow containers do not affect
|
||||
* other frames' size or position during reflow (but do affect their
|
||||
* parent's overflow area).
|
||||
*
|
||||
* Overflow container continuations are different from normal continuations
|
||||
* in that
|
||||
* - more than one child of the frame can have its next-in-flow broken
|
||||
* off and pushed into the frame's next-in-flow
|
||||
* - new continuations may need to be spliced into the middle of the list
|
||||
* or deleted continuations slipped out
|
||||
* e.g. A, B, C are all fixed-size containers on one page, all have
|
||||
* overflow beyond availableHeight, and content is dynamically added
|
||||
* and removed from B
|
||||
* As a result, it is not possible to simply prepend the new continuations
|
||||
* to the old list as with the overflowProperty mechanism. To avoid
|
||||
* complicated list splicing, the code assumes only one overflow containers
|
||||
* list exists for a given frame: either its own overflowContainersProperty
|
||||
* or its prev-in-flow's excessOverflowContainersProperty, not both.
|
||||
*
|
||||
* The nsOverflowContinuationTracker helper class should be used for tracking
|
||||
* overflow containers and adding them to the appropriate list.
|
||||
* See nsBlockFrame::Reflow for a sample implementation.
|
||||
*/
|
||||
|
||||
friend class nsOverflowContinuationTracker;
|
||||
|
||||
/**
|
||||
* Reflow overflow container children. They are invisible to normal reflow
|
||||
* (i.e. don't affect sizing or placement of other children) and inherit
|
||||
* width and horizontal position from their prev-in-flow.
|
||||
*
|
||||
* This method
|
||||
* 1. Pulls excess overflow containers from the prev-in-flow and adds
|
||||
* them to our overflow container list
|
||||
* 2. Reflows all our overflow container kids
|
||||
* 3. Expands aOverflowRect as necessary to accomodate these children.
|
||||
* 4. Sets aStatus's NS_FRAME_OVERFLOW_IS_INCOMPLETE flag (along with
|
||||
* NS_FRAME_REFLOW_NEXTINFLOW as necessary) if any overflow children
|
||||
* are incomplete and
|
||||
* 5. Prepends a list of their continuations to our excess overflow
|
||||
* container list, to be drained into our next-in-flow when it is
|
||||
* reflowed.
|
||||
*
|
||||
* The caller is responsible for tracking any new overflow container
|
||||
* continuations it makes, removing them from its child list, and
|
||||
* making sure they are stored properly in the overflow container lists.
|
||||
* The nsOverflowContinuationTracker helper class should be used for this.
|
||||
*
|
||||
* (aFlags just gets passed through to ReflowChild)
|
||||
*/
|
||||
nsresult ReflowOverflowContainerChildren(nsPresContext* aPresContext,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsRect& aOverflowRect,
|
||||
PRUint32 aFlags,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
/**
|
||||
* Removes aChild without destroying it and without requesting reflow.
|
||||
* Continuations are not affected. Checks the primary and overflow
|
||||
* or overflow containers and excess overflow containers lists, depending
|
||||
* on whether the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set. Does not
|
||||
* check any other auxiliary lists.
|
||||
* Returns NS_ERROR_UNEXPECTED if we failed to remove aChild.
|
||||
* Returns other error codes if we failed to put back a proptable list.
|
||||
* If aForceNormal is true, only checks the primary and overflow lists
|
||||
* even when the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set.
|
||||
*/
|
||||
virtual nsresult StealFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aChild,
|
||||
PRBool aForceNormal = PR_FALSE);
|
||||
|
||||
/**
|
||||
* Add overflow containers to the display list
|
||||
*/
|
||||
void DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists);
|
||||
|
||||
/**
|
||||
* Builds display lists for the children. The background
|
||||
* of each child is placed in the Content() list (suitable for inline
|
||||
|
@ -218,12 +322,19 @@ protected:
|
|||
const nsDisplayListSet& aLists,
|
||||
PRUint32 aFlags = 0);
|
||||
|
||||
|
||||
// ==========================================================================
|
||||
/* Overflow Frames are frames that did not fit and must be pulled by
|
||||
* our next-in-flow during its reflow. (The same concept for overflow
|
||||
* containers is called "excess frames". We should probably make the
|
||||
* names match.)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the frames on the overflow list
|
||||
*/
|
||||
nsIFrame* GetOverflowFrames(nsPresContext* aPresContext,
|
||||
PRBool aRemoveProperty) const;
|
||||
|
||||
/**
|
||||
* Set the overflow list
|
||||
*/
|
||||
|
@ -259,7 +370,162 @@ protected:
|
|||
nsIFrame* aFromChild,
|
||||
nsIFrame* aPrevSibling);
|
||||
|
||||
// ==========================================================================
|
||||
/*
|
||||
* Convenience methods for nsFrameLists stored in the
|
||||
* PresContext's proptable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the PresContext-stored nsFrameList named aPropID for this frame.
|
||||
* May return null.
|
||||
*/
|
||||
nsFrameList* GetPropTableFrames(nsPresContext* aPresContext,
|
||||
nsIAtom* aPropID) const;
|
||||
|
||||
/**
|
||||
* Remove and return the PresContext-stored nsFrameList named aPropID for
|
||||
* this frame. May return null.
|
||||
*/
|
||||
nsFrameList* RemovePropTableFrames(nsPresContext* aPresContext,
|
||||
nsIAtom* aPropID) const;
|
||||
|
||||
/**
|
||||
* Remove aFrame from the PresContext-stored nsFrameList named aPropID
|
||||
* for this frame, deleting the list if it is now empty.
|
||||
* Return true if the aFrame was successfully removed,
|
||||
* Return false otherwise.
|
||||
*/
|
||||
|
||||
PRBool RemovePropTableFrame(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIAtom* aPropID) const;
|
||||
|
||||
/**
|
||||
* Set the PresContext-stored nsFrameList named aPropID for this frame
|
||||
* to the given aFrameList, which must not be null.
|
||||
*/
|
||||
nsresult SetPropTableFrames(nsPresContext* aPresContext,
|
||||
nsFrameList* aFrameList,
|
||||
nsIAtom* aPropID) const;
|
||||
// ==========================================================================
|
||||
|
||||
nsFrameList mFrames;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class for tracking overflow container continuations during reflow.
|
||||
*
|
||||
* A frame is related to two sets of overflow containers: those that /are/
|
||||
* its own children, and those that are /continuations/ of its children.
|
||||
* This tracker walks through those continuations (the frame's NIF's children)
|
||||
* and their prev-in-flows (a subset of the frame's normal and overflow
|
||||
* container children) in parallel. It allows the reflower to synchronously
|
||||
* walk its overflow continuations while it loops through and reflows its
|
||||
* children. This makes it possible to insert new continuations at the correct
|
||||
* place in the overflow containers list.
|
||||
*
|
||||
* The reflower is expected to loop through its children in the same order it
|
||||
* looped through them the last time (if there was a last time).
|
||||
* For each child, the reflower should either
|
||||
* - call Skip for the child if was not reflowed in this pass
|
||||
* - call Insert for the overflow continuation if the child was reflowed
|
||||
* but has incomplete overflow
|
||||
* - call Finished for the child if it was reflowed in this pass but
|
||||
* is either complete or has a normal next-in-flow. This call can
|
||||
* be skipped if the child did not previously have an overflow
|
||||
* continuation.
|
||||
*/
|
||||
class nsOverflowContinuationTracker {
|
||||
public:
|
||||
/**
|
||||
* Initializes an nsOverflowContinuationTracker to help track overflow
|
||||
* continuations of aFrame's children. Typically invoked on 'this'.
|
||||
*
|
||||
* Don't set aSkipOverflowContainerChildren to PR_FALSE unless you plan
|
||||
* to walk your own overflow container children. (Usually they are handled
|
||||
* by calling ReflowOverflowContainerChildren.)
|
||||
*/
|
||||
nsOverflowContinuationTracker(nsPresContext* aPresContext,
|
||||
nsContainerFrame* aFrame,
|
||||
PRBool aSkipOverflowContainerChildren = PR_TRUE);
|
||||
/**
|
||||
* This function adds an overflow continuation to our running list and
|
||||
* sets its NS_FRAME_IS_OVERFLOW_CONTAINER flag.
|
||||
*
|
||||
* aReflowStatus should preferably be specific to the recently-reflowed
|
||||
* child and not influenced by any of its siblings' statuses. This
|
||||
* function sets the NS_FRAME_IS_DIRTY bit on aOverflowCont if it needs
|
||||
* to be reflowed. (Its need for reflow depends on changes to its
|
||||
* prev-in-flow, not to its parent--for whom it is invisible, reflow-wise.)
|
||||
*
|
||||
* The caller MUST disconnect the frame from its parent's child list
|
||||
* if it was not previously an NS_FRAME_IS_OVERFLOW_CONTAINER (because
|
||||
* StealFrame is much more inefficient than disconnecting in place
|
||||
* during Reflow, which the caller is able to do but we are not).
|
||||
*
|
||||
* The caller MUST NOT disconnect the frame from its parent's
|
||||
* child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
|
||||
* (In this case we will disconnect and reconnect it ourselves.)
|
||||
*/
|
||||
nsresult Insert(nsIFrame* aOverflowCont,
|
||||
nsReflowStatus& aReflowStatus);
|
||||
/**
|
||||
* This function should be called for each child that is reflowed
|
||||
* but no longer has an overflow continuation. It increments our
|
||||
* walker and makes sure we drop any dangling pointers to its
|
||||
* next-in-flow. This function MUST be called before stealing or
|
||||
* deleting aChild's next-in-flow.
|
||||
*/
|
||||
void Finish(nsIFrame* aChild);
|
||||
|
||||
/**
|
||||
* This function should be called for each child that isn't reflowed.
|
||||
* It increments our walker and sets the NS_FRAME_OVERFLOW_INCOMPLETE
|
||||
* reflow flag if it encounters an overflow continuation so that our
|
||||
* next-in-flow doesn't get prematurely deleted. It MUST be called on
|
||||
* each unreflowed child that has an overflow container continuation;
|
||||
* it MAY be called on other children, but it isn't necessary (doesn't
|
||||
* do anything).
|
||||
*/
|
||||
void Skip(nsIFrame* aChild, nsReflowStatus& aReflowStatus)
|
||||
{
|
||||
NS_PRECONDITION(aChild, "null ptr");
|
||||
if (aChild == mSentry) {
|
||||
StepForward();
|
||||
aReflowStatus = NS_FRAME_MERGE_INCOMPLETE(aReflowStatus,
|
||||
NS_FRAME_OVERFLOW_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void SetUpListWalker();
|
||||
void StepForward();
|
||||
|
||||
/* We hold a pointer to either the next-in-flow's overflow containers list
|
||||
or, if that doesn't exist, our frame's excess overflow containers list.
|
||||
We need to make sure that we drop that pointer if the list becomes
|
||||
empty and is deleted elsewhere. */
|
||||
nsFrameList* mOverflowContList;
|
||||
/* We hold a pointer to the most recently-reflowed child that has an
|
||||
overflow container next-in-flow. We do this because it's a known
|
||||
good point; this pointer won't be deleted on us. We can use it to
|
||||
recover our place in the list. */
|
||||
nsIFrame* mPrevOverflowCont;
|
||||
/* This is a pointer to the next overflow container's prev-in-flow, which
|
||||
is (or should be) a child of our frame. When we hit this, we will need
|
||||
to increment this walker to the next overflow container. */
|
||||
nsIFrame* mSentry;
|
||||
/* Parent of all frames in mOverflowContList. If our mOverflowContList
|
||||
is an excessOverflowContainersProperty, then this our frame (the frame
|
||||
that was passed in to our constructor). Otherwise this is that frame's
|
||||
next-in-flow, and our mOverflowContList is mParent's
|
||||
overflowContainersProperty */
|
||||
nsContainerFrame* mParent;
|
||||
/* Tells SetUpListWalker whether or not to walk us past any continuations
|
||||
of overflow containers. */
|
||||
PRBool mSkipOverflowContainerChildren;
|
||||
};
|
||||
|
||||
#endif /* nsContainerFrame_h___ */
|
||||
|
|
|
@ -7337,7 +7337,7 @@ void nsFrame::DisplayReflowExit(nsPresContext* aPresContext,
|
|||
DR_state->PrettyUC(aMetrics.height, height);
|
||||
printf("Reflow d=%s,%s ", width, height);
|
||||
|
||||
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
|
||||
if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
|
||||
printf("status=0x%x", aStatus);
|
||||
}
|
||||
if (aFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) {
|
||||
|
|
|
@ -51,6 +51,13 @@
|
|||
#include "nsBidiPresUtils.h"
|
||||
#endif // IBMBIDI
|
||||
|
||||
void
|
||||
nsFrameList::Destroy()
|
||||
{
|
||||
DestroyFrames();
|
||||
delete this;
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameList::DestroyFrames()
|
||||
{
|
||||
|
|
|
@ -65,6 +65,9 @@ public:
|
|||
|
||||
void DestroyFrames();
|
||||
|
||||
// Delete this and destroy all its frames
|
||||
void Destroy();
|
||||
|
||||
void SetFrames(nsIFrame* aFrameList) {
|
||||
mFirstChild = aFrameList;
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -177,6 +177,13 @@ enum {
|
|||
// frames.
|
||||
NS_FRAME_GENERATED_CONTENT = 0x00000040,
|
||||
|
||||
// If this bit is set the frame is a continuation that is holding overflow,
|
||||
// i.e. it is a next-in-flow created to hold overflow after the box's
|
||||
// height has ended. This means the frame should be a) at the top of the
|
||||
// page and b) invisible: no borders, zero height, ignored in margin
|
||||
// collapsing, etc. See nsContainerFrame.h
|
||||
NS_FRAME_IS_OVERFLOW_CONTAINER = 0x00000080,
|
||||
|
||||
// If this bit is set, then the frame has been moved out of the flow,
|
||||
// e.g., it is absolutely positioned or floated
|
||||
NS_FRAME_OUT_OF_FLOW = 0x00000100,
|
||||
|
@ -287,16 +294,31 @@ enum nsSpread {
|
|||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Reflow status returned by the reflow methods.
|
||||
* Reflow status returned by the reflow methods. There are three
|
||||
* completion statuses, represented by two bit flags.
|
||||
*
|
||||
* NS_FRAME_COMPLETE means the frame is fully complete.
|
||||
*
|
||||
* NS_FRAME_NOT_COMPLETE bit flag means the frame does not map all its
|
||||
* content, and that the parent frame should create a continuing frame.
|
||||
* If this bit isn't set it means the frame does map all its content.
|
||||
* This bit is mutually exclusive with NS_FRAME_OVERFLOW_INCOMPLETE.
|
||||
*
|
||||
* NS_FRAME_OVERFLOW_INCOMPLETE bit flag means that the frame has
|
||||
* overflow that is not complete, but its own box is complete.
|
||||
* (This happens when content overflows a fixed-height box.)
|
||||
* The reflower should place and size the frame and continue its reflow,
|
||||
* but needs to create an overflow container as a continuation for this
|
||||
* frame. See nsContainerFrame.h for more information.
|
||||
* This bit is mutually exclusive with NS_FRAME_NOT_COMPLETE.
|
||||
*
|
||||
* Please use the SET and MERGE macros below for handling
|
||||
* NS_FRAME_NOT_COMPLETE and NS_FRAME_OVERFLOW_INCOMPLETE.
|
||||
*
|
||||
* NS_FRAME_REFLOW_NEXTINFLOW bit flag means that the next-in-flow is
|
||||
* dirty, and also needs to be reflowed. This status only makes sense
|
||||
* for a frame that is not complete, i.e. you wouldn't set both
|
||||
* NS_FRAME_COMPLETE and NS_FRAME_REFLOW_NEXTINFLOW
|
||||
* NS_FRAME_COMPLETE and NS_FRAME_REFLOW_NEXTINFLOW.
|
||||
*
|
||||
* The low 8 bits of the nsReflowStatus are reserved for future extensions;
|
||||
* the remaining 24 bits are zero (and available for extensions; however
|
||||
|
@ -307,9 +329,10 @@ enum nsSpread {
|
|||
*/
|
||||
typedef PRUint32 nsReflowStatus;
|
||||
|
||||
#define NS_FRAME_COMPLETE 0 // Note: not a bit!
|
||||
#define NS_FRAME_NOT_COMPLETE 0x1
|
||||
#define NS_FRAME_REFLOW_NEXTINFLOW 0x2
|
||||
#define NS_FRAME_COMPLETE 0 // Note: not a bit!
|
||||
#define NS_FRAME_NOT_COMPLETE 0x1
|
||||
#define NS_FRAME_REFLOW_NEXTINFLOW 0x2
|
||||
#define NS_FRAME_OVERFLOW_INCOMPLETE 0x4
|
||||
|
||||
#define NS_FRAME_IS_COMPLETE(status) \
|
||||
(0 == ((status) & NS_FRAME_NOT_COMPLETE))
|
||||
|
@ -317,6 +340,29 @@ typedef PRUint32 nsReflowStatus;
|
|||
#define NS_FRAME_IS_NOT_COMPLETE(status) \
|
||||
(0 != ((status) & NS_FRAME_NOT_COMPLETE))
|
||||
|
||||
#define NS_FRAME_OVERFLOW_IS_INCOMPLETE(status) \
|
||||
(0 != ((status) & NS_FRAME_OVERFLOW_INCOMPLETE))
|
||||
|
||||
#define NS_FRAME_IS_FULLY_COMPLETE(status) \
|
||||
(NS_FRAME_IS_COMPLETE(status) && !NS_FRAME_OVERFLOW_IS_INCOMPLETE(status))
|
||||
|
||||
// These macros set or switch incompete statuses without touching th
|
||||
// NS_FRAME_REFLOW_NEXTINFLOW bit.
|
||||
#define NS_FRAME_SET_INCOMPLETE(status) \
|
||||
status = status & ~NS_FRAME_OVERFLOW_INCOMPLETE | NS_FRAME_NOT_COMPLETE
|
||||
|
||||
#define NS_FRAME_SET_OVERFLOW_INCOMPLETE(status) \
|
||||
status = status & ~NS_FRAME_NOT_COMPLETE | NS_FRAME_OVERFLOW_INCOMPLETE
|
||||
|
||||
// Combines two statuses and returns the most severe bits of the pair
|
||||
#define NS_FRAME_MERGE_INCOMPLETE(status1, status2) \
|
||||
( (NS_FRAME_REFLOW_NEXTINFLOW & (status1 | status2)) \
|
||||
| ( (NS_FRAME_NOT_COMPLETE & (status1 | status2)) \
|
||||
? NS_FRAME_NOT_COMPLETE \
|
||||
: NS_FRAME_OVERFLOW_INCOMPLETE & (status1 | status2) \
|
||||
) \
|
||||
)
|
||||
|
||||
// This macro tests to see if an nsReflowStatus is an error value
|
||||
// or just a regular return value
|
||||
#define NS_IS_REFLOW_ERROR(_status) (PRInt32(_status) < 0)
|
||||
|
@ -1463,6 +1509,7 @@ public:
|
|||
// requires nsHTMLReflowState::mLineLayout.
|
||||
eLineParticipant = 1 << 6,
|
||||
eXULBox = 1 << 7,
|
||||
eCanContainOverflowContainers = 1 << 8,
|
||||
|
||||
|
||||
// These are to allow nsFrame::Init to assert that IsFrameOfType
|
||||
|
|
|
@ -636,7 +636,7 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
|
|||
}
|
||||
nsIFrame* nextFrame = aFrame->GetNextSibling();
|
||||
if (nextFrame) {
|
||||
aStatus |= NS_FRAME_NOT_COMPLETE;
|
||||
NS_FRAME_SET_INCOMPLETE(aStatus);
|
||||
PushFrames(aPresContext, nextFrame, aFrame);
|
||||
}
|
||||
else if (nsnull != GetNextInFlow()) {
|
||||
|
@ -645,7 +645,7 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
|
|||
nsInlineFrame* nextInFlow = (nsInlineFrame*) GetNextInFlow();
|
||||
while (nsnull != nextInFlow) {
|
||||
if (nextInFlow->mFrames.NotEmpty()) {
|
||||
aStatus |= NS_FRAME_NOT_COMPLETE;
|
||||
NS_FRAME_SET_INCOMPLETE(aStatus);
|
||||
break;
|
||||
}
|
||||
nextInFlow = (nsInlineFrame*) nextInFlow->GetNextInFlow();
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "nsPageContentFrame.h"
|
||||
#include "nsPageFrame.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsHTMLParts.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsPresContext.h"
|
||||
|
@ -52,15 +55,27 @@ NS_NewPageContentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
|||
return new (aPresShell) nsPageContentFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPageContentFrame::Reflow(nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
NS_IMETHODIMP
|
||||
nsPageContentFrame::Reflow(nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
DO_GLOBAL_REFLOW_COUNT("nsPageContentFrame");
|
||||
DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
|
||||
aStatus = NS_FRAME_COMPLETE; // initialize out parameter
|
||||
|
||||
nsPageContentFrame* prevPageContentFrame = static_cast<nsPageContentFrame*>
|
||||
(GetPrevInFlow());
|
||||
if (prevPageContentFrame) {
|
||||
nsIFrame* overflow = prevPageContentFrame->GetOverflowFrames(aPresContext, PR_TRUE);
|
||||
nsHTMLContainerFrame::ReparentFrameViewList(aPresContext, overflow, prevPageContentFrame, this);
|
||||
// Prepend overflow to the page content frame. There may already be
|
||||
// children placeholders which don't get reflowed but must not be
|
||||
// lost until the page content frame is destroyed.
|
||||
mFrames.InsertFrames(this, nsnull, overflow);
|
||||
}
|
||||
|
||||
// Resize our frame allowing it only to be as big as we are
|
||||
// XXX Pay attention to the page's border and padding...
|
||||
if (mFrames.NotEmpty()) {
|
||||
|
@ -73,6 +88,28 @@ NS_IMETHODIMP nsPageContentFrame::Reflow(nsPresContext* aPresContext,
|
|||
// Reflow the page content area to get the child's desired size
|
||||
ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, 0, 0, 0, aStatus);
|
||||
|
||||
if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
|
||||
nsIFrame* nextFrame = frame->GetNextInFlow();
|
||||
NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
|
||||
"If it's incomplete and has no nif yet, it must flag a nif reflow.");
|
||||
if (!nextFrame) {
|
||||
nsresult rv = nsHTMLContainerFrame::CreateNextInFlow(aPresContext,
|
||||
this, frame, nextFrame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
frame->SetNextSibling(nextFrame->GetNextSibling());
|
||||
nextFrame->SetNextSibling(nsnull);
|
||||
SetOverflowFrames(aPresContext, nextFrame);
|
||||
// Root overflow containers will be normal children of
|
||||
// the pageContentFrame, but that's ok because there
|
||||
// aren't any other frames we need to isolate them from
|
||||
// during reflow.
|
||||
}
|
||||
if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
|
||||
nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
|
||||
NS_FRAME_SET_INCOMPLETE(aStatus); // page frames can't have overflow
|
||||
}
|
||||
}
|
||||
|
||||
// The document element's background should cover the entire canvas, so
|
||||
// take into account the combined area and any space taken up by
|
||||
// absolutely positioned elements
|
||||
|
@ -97,7 +134,7 @@ NS_IMETHODIMP nsPageContentFrame::Reflow(nsPresContext* aPresContext,
|
|||
// Place and size the child
|
||||
FinishReflowChild(frame, aPresContext, &kidReflowState, aDesiredSize, 0, 0, 0);
|
||||
|
||||
NS_ASSERTION(aPresContext->IsDynamic() || !NS_FRAME_IS_COMPLETE(aStatus) ||
|
||||
NS_ASSERTION(aPresContext->IsDynamic() || !NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
|
||||
!frame->GetNextInFlow(), "bad child flow list");
|
||||
}
|
||||
// Reflow our fixed frames
|
||||
|
|
|
@ -90,34 +90,9 @@ NS_IMETHODIMP nsPageFrame::Reflow(nsPresContext* aPresContext,
|
|||
DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
|
||||
aStatus = NS_FRAME_COMPLETE; // initialize out parameter
|
||||
|
||||
// Do we have any children?
|
||||
// XXX We should use the overflow list instead...
|
||||
nsIFrame* firstFrame = mFrames.FirstChild();
|
||||
nsPageContentFrame* contentPage = static_cast<nsPageContentFrame*>(firstFrame);
|
||||
NS_ASSERTION(contentPage, "There should always be a content page");
|
||||
NS_ASSERTION(nsGkAtoms::pageContentFrame == firstFrame->GetType(),
|
||||
"This frame isn't a pageContentFrame");
|
||||
|
||||
if (contentPage && GetPrevInFlow() && !contentPage->GetFirstChild(nsnull)) {
|
||||
|
||||
nsPageFrame* prevPage = static_cast<nsPageFrame*>(GetPrevInFlow());
|
||||
nsPageContentFrame* prevContentPage = static_cast<nsPageContentFrame*>(prevPage->mFrames.FirstChild());
|
||||
nsIFrame* prevLastChild = prevContentPage->mFrames.LastChild();
|
||||
|
||||
// Create a continuing child of the previous page's last child
|
||||
nsIFrame* newFrame;
|
||||
|
||||
nsresult rv = aPresContext->PresShell()->FrameConstructor()->
|
||||
CreateContinuingFrame(aPresContext, prevLastChild,
|
||||
contentPage, &newFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
// Make the new area frame the 1st child of the page content frame. There may already be
|
||||
// children placeholders which don't get reflowed but must not be destroyed until the
|
||||
// page content frame is destroyed.
|
||||
contentPage->mFrames.InsertFrame(contentPage, nsnull, newFrame);
|
||||
}
|
||||
NS_ASSERTION(mFrames.FirstChild() &&
|
||||
nsGkAtoms::pageContentFrame == mFrames.FirstChild()->GetType(),
|
||||
"pageFrame must have a pageContentFrame child");
|
||||
|
||||
// Resize our frame allowing it only to be as big as we are
|
||||
// XXX Pay attention to the page's border and padding...
|
||||
|
@ -163,7 +138,7 @@ NS_IMETHODIMP nsPageFrame::Reflow(nsPresContext* aPresContext,
|
|||
// Place and size the child
|
||||
FinishReflowChild(frame, aPresContext, &kidReflowState, aDesiredSize, xc, yc, 0);
|
||||
|
||||
NS_ASSERTION(!NS_FRAME_IS_COMPLETE(aStatus) ||
|
||||
NS_ASSERTION(!NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
|
||||
!frame->GetNextInFlow(), "bad child flow list");
|
||||
}
|
||||
PR_PL(("PageFrame::Reflow %p ", this));
|
||||
|
|
|
@ -316,7 +316,7 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
|
|||
|
||||
// Just reflow all the fixed-pos frames.
|
||||
rv = mFixedContainer.Reflow(this, aPresContext, reflowState,
|
||||
reflowState.ComputedWidth(),
|
||||
reflowState.ComputedWidth(),
|
||||
reflowState.mComputedHeight,
|
||||
PR_TRUE, PR_TRUE); // XXX could be optimized
|
||||
|
||||
|
|
|
@ -302,6 +302,13 @@ fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == 372037-1.html 372037-1-ref.html # bug 3
|
|||
== 377918.html 377918-ref.html
|
||||
== 378535-1.html 378535-1-ref.html
|
||||
== 379316-1.html 379316-1-ref.html
|
||||
== 379349-1a.xhtml 379349-1-ref.xhtml
|
||||
== 379349-1b.xhtml 379349-1-ref.xhtml
|
||||
== 379349-1c.xhtml 379349-1-ref.xhtml
|
||||
== 379349-2a.xhtml 379349-2-ref.xhtml
|
||||
== 379349-2b.xhtml 379349-2-ref.xhtml
|
||||
== 379349-3a.xhtml 379349-3-ref.xhtml
|
||||
== 379349-3b.xhtml 379349-3-ref.xhtml
|
||||
random-if(MOZ_WIDGET_TOOLKIT=="cocoa") == 379316-2.html 379316-2-ref.html # bug 379786
|
||||
== 379328-1.html 379328-1-ref.html
|
||||
== 380004-1.html 380004-1-ref.html
|
||||
|
|
|
@ -851,6 +851,12 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
|
|||
|
||||
ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
|
||||
kidOrigin.x, kidOrigin.y, 0, aStatus);
|
||||
if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
|
||||
// Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it
|
||||
//XXX should paginate overflow as overflow, but not in this patch (bug 379349)
|
||||
NS_FRAME_SET_INCOMPLETE(aStatus);
|
||||
printf("Set table cell incomplete %p\n", this);
|
||||
}
|
||||
if (GetStateBits() & NS_FRAME_IS_DIRTY) {
|
||||
Invalidate(GetOverflowRect(), PR_FALSE);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче