зеркало из https://github.com/mozilla/pjs.git
Reduce stack size by allocating nsLineLayout objects from the heap when the frame tree depth gets too big (bug #10310)
This commit is contained in:
Родитель
273f0eb752
Коммит
fd902c640a
|
@ -50,6 +50,8 @@
|
|||
#include "nsIFocusTracker.h"
|
||||
#include "nsIFrameSelection.h"
|
||||
|
||||
#define MAX_LINE_COUNT 50000
|
||||
|
||||
// XXX HTML:P's that are empty yet have style indicating they should
|
||||
// clear floaters - we need to ignore the clear behavior.
|
||||
|
||||
|
@ -203,8 +205,7 @@ public:
|
|||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout);
|
||||
const nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
|
@ -240,9 +241,11 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
void InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
||||
void AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
PRBool aInitialReflow);
|
||||
|
||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||
|
@ -302,13 +305,20 @@ public:
|
|||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult);
|
||||
|
||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
||||
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult);
|
||||
|
||||
void RecoverStateFrom(nsLineBox* aLine,
|
||||
PRBool aApplyTopMargin,
|
||||
nscoord aDeltaY,
|
||||
nsRect* aDamageRect);
|
||||
|
||||
void AdvanceToNextLine() {
|
||||
mLineNumber++;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is the "global" state computed once for the reflow of
|
||||
|
@ -321,7 +331,7 @@ public:
|
|||
|
||||
const nsHTMLReflowState& mReflowState;
|
||||
|
||||
nsLineLayout* mLineLayout;
|
||||
// nsLineLayout* mLineLayout;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
|
||||
|
@ -411,18 +421,22 @@ public:
|
|||
PRBool mComputeMaxElementSize;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->InitFloater(aFrame);
|
||||
mBlockRS->InitFloater(*this, aFrame);
|
||||
}
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->AddFloater(aFrame, PR_FALSE);
|
||||
mBlockRS->AddFloater(*this, aFrame, PR_FALSE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -430,8 +444,7 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
|||
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout)
|
||||
const nsHTMLReflowMetrics& aMetrics)
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0)
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
|
||||
// Translate into our content area and then save the
|
||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if (0 != borderPadding.top) {
|
||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||
aReflowState.frame);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
|||
// at the current Y coordinate. This method assumes that
|
||||
// GetAvailableSpace has already been called.
|
||||
void
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
nscoord availHeight = mUnconstrainedHeight
|
||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
nscoord availX, availWidth;
|
||||
if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == aDisplay->mDisplay) {
|
||||
// XXX This is a hack until the css2 folks can figure how to deal
|
||||
// with list-items and floaters.
|
||||
nscoord leftMargin = 0;
|
||||
#if 0
|
||||
if (mAvailSpaceRect.x != borderPadding.left) {
|
||||
// When a list-item is impacted by a left floater, slide it over
|
||||
// by the right amount so that the bullets will (hopefully) be
|
||||
// visible.
|
||||
float p2t;
|
||||
mPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
leftMargin = NSIntPixelsToTwips(40, p2t);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assume the frame is clueless about the space manager and only
|
||||
// give it free space.
|
||||
availX = mAvailSpaceRect.x + borderPadding.left + leftMargin;
|
||||
availWidth = mAvailSpaceRect.width - leftMargin;
|
||||
}
|
||||
else if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
// Frames that know how to do non-rectangular splitting are given
|
||||
// the entire available space, including space consumed by
|
||||
// floaters.
|
||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||
availWidth = mAvailSpaceRect.width;
|
||||
}
|
||||
|
||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
||||
}
|
||||
|
||||
|
@ -630,10 +669,13 @@ nsBlockReflowState::RecoverVerticalMargins(nsLineBox* aLine,
|
|||
// Setup reflow state to compute the block childs top and bottom
|
||||
// margins
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
nsRect availSpaceRect;
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpaceRect;
|
||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
||||
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||
frame, availSpace);
|
||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
||||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||
#ifdef DEBUG_kipp
|
||||
{
|
||||
extern char* nsPresShell_ReflowStackPointerTop;
|
||||
char marker;
|
||||
char* newsp = (char*) ▮
|
||||
printf("XXX: frame tree is too deep; approx stack size = %d\n",
|
||||
nsPresShell_ReflowStackPointerTop - newsp);
|
||||
}
|
||||
#endif
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
nsresult rv = NS_OK;
|
||||
PRBool keepGoing = PR_TRUE;
|
||||
|
||||
// Inform line layout of where the text runs are
|
||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||
nsIReflowCommand::ReflowType type;
|
||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
|
||||
// Pull data from a next-in-flow if we can
|
||||
|
@ -2049,13 +2098,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an odd-ball case: a list-item with no lines
|
||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
||||
PlaceBullet(aState);
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
|||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||
}
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (0 != --fromLine->mChildCount) {
|
||||
NS_ASSERTION(fromLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(fromLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
// Mark line dirty now that we pulled a child
|
||||
fromLine->MarkDirty();
|
||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if ((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
|
||||
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace)) {
|
||||
// Since whitespace is significant, we know that the paragraph
|
||||
// is not empty (even if it has no text in it because it has
|
||||
return PR_FALSE;
|
||||
|
||||
static PRBool
|
||||
IsEmptyHTMLParagraph(nsIFrame* aFrame)
|
||||
{
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, (void**)&bf)) &&
|
||||
nsBlockReflowContext::IsHTMLParagraph(aFrame)) {
|
||||
if (!bf->mLines) {
|
||||
// It's an html paragraph and it's empty
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsLineBox* line = bf->mLines;
|
||||
while (line) {
|
||||
if (!IsEmptyLine(line)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
static void ComputeCombinedArea(const nsRect aRect1, const nsRect aRect2, nsRect& aOutRect)
|
||||
{
|
||||
// Rect 1's top left point: (aRect.x, aRect1.y)
|
||||
// Rect 2's top left point: (aRect2.x, aRect2.y)
|
||||
// Rect 2's bottom right point: (x2, y2)
|
||||
// Output rect's top left point: (aOutRect.x, aOutRect.y)
|
||||
// Output rect's bottom right point: (xOut, yOut)
|
||||
|
||||
//
|
||||
// Calculate the top left point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's top left point to Rect 1's top left point
|
||||
aOutRect.x = aRect1.x;
|
||||
aOutRect.y = aRect1.y;
|
||||
if (aRect2.x < aRect1.x) {
|
||||
aOutRect.x = aRect2.x;
|
||||
}
|
||||
if (aRect2.y < aRect1.y) {
|
||||
aOutRect.y = aRect2.y;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the bottom right point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's bottom right point to Rect 1's bottom right point
|
||||
nscoord xOut = aRect1.x + aRect1.width;
|
||||
nscoord yOut = aRect1.y + aRect1.height;
|
||||
// Initialize Rect 2's bottom right point
|
||||
nscoord x2 = aRect2.x + aRect2.width;
|
||||
nscoord y2 = aRect2.y + aRect2.height;
|
||||
if (x2 > xOut) {
|
||||
xOut = x2;
|
||||
}
|
||||
if (y2 > yOut) {
|
||||
yOut = y2;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the width and height on the output rect.
|
||||
//
|
||||
aOutRect.width = xOut - aOutRect.x;
|
||||
aOutRect.height = yOut - aOutRect.y;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpace;
|
||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
||||
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||
|
||||
// Reflow the block into the available space
|
||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Do not count the continuation child on the line it used
|
||||
// to be on
|
||||
aLine->mChildCount--;
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
}
|
||||
|
||||
// Advance to next line since some of the block fit. That way
|
||||
|
@ -2885,11 +2926,6 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
bbox.y = aState.BorderPadding().top + ascent -
|
||||
metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
|
||||
// Fix for bug 8314. Include the bullet's area in the combined area
|
||||
// of the current line.
|
||||
ComputeCombinedArea((const nsRect) bbox, (const nsRect) aLine->mCombinedArea,
|
||||
aLine->mCombinedArea);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
#ifdef DEBUG
|
||||
PRInt32 spins = 0;
|
||||
#endif
|
||||
for (;;) {
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// Prevent overflowing limited thread stacks by creating
|
||||
// nsLineLayout from the heap when the frame tree depth gets
|
||||
// large.
|
||||
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == lineLayout->GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
lineLayout->SetFirstLetterStyleOK(PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout* ll = new nsLineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
ll->SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
|
||||
aLineReflowStatus);
|
||||
ll->EndLineReflow();
|
||||
delete ll;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
aKeepReflowGoing, aLineReflowStatus);
|
||||
lineLayout.EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
aLineLayout.BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == aLineLayout.GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
nsresult rv = NS_OK;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
}
|
||||
else {
|
||||
// If we are propogating out a break-before status then there is
|
||||
// no point in placing the line.
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
lineLayout->EndLineReflow();
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||
}
|
||||
else {
|
||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
*aLineReflowStatus = lineReflowStatus;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
*/
|
||||
nsresult
|
||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRUint8* aLineReflowStatus)
|
||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
|
||||
// If it's currently ok to be reflowing in first-letter style then
|
||||
// we must be about to reflow a frame that has first-letter style.
|
||||
PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK();
|
||||
PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
|
||||
#ifdef NOISY_FIRST_LETTER
|
||||
ListTag(stdout);
|
||||
printf(": reflowing ");
|
||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
#endif
|
||||
|
||||
// Reflow the inline frame
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
else {
|
||||
// It's not the first child on this line so go ahead and split
|
||||
// the line. We will see the frame again on the next-line.
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line, but after the frame just reflowed
|
||||
nsIFrame* nextFrame;
|
||||
aFrame->GetNextSibling(&nextFrame);
|
||||
rv = SplitLine(aState, aLine, nextFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line after the current frame
|
||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||
aFrame->GetNextSibling(&aFrame);
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
if (nsnull != nextInFlow) {
|
||||
aMadeNewFrame = PR_TRUE;
|
||||
aLine->mChildCount++;
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_FALSE);
|
||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
||||
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||
//aLine->List(stdout, 0);
|
||||
|
@ -3294,7 +3394,7 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
|||
// Let line layout know that some frames are no longer part of its
|
||||
// state.
|
||||
if (!aLine->IsBlock()) {
|
||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
||||
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_TRUE);
|
||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing)
|
||||
{
|
||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// method is used for placing a line of inline frames. If the rare
|
||||
// case is happening then the worst that will happen is that the
|
||||
// bullet frame will be reflowed twice.
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRBool addedBullet = PR_FALSE;
|
||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
||||
PlaceBullet(aState);
|
||||
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||
addedBullet = PR_TRUE;
|
||||
}
|
||||
nsSize maxElementSize;
|
||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
static nscoord lastHeight = 0;
|
||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
||||
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||
if (addedBullet) {
|
||||
lineLayout->RemoveBulletFrame(mBullet);
|
||||
aLineLayout.RemoveBulletFrame(mBullet);
|
||||
}
|
||||
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
|||
else {
|
||||
prevSibLine->mChildCount++;
|
||||
prevSibLine->MarkDirty();
|
||||
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
|
||||
aPrevSibling = newFrame;
|
||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
|||
line = next;
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
// Make the line that just lost a frame dirty
|
||||
line->MarkDirty();
|
||||
|
||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
void
|
||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder)
|
||||
{
|
||||
// Set the geometric parent of the floater
|
||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
|
||||
// Then add the floater to the current line and place it when
|
||||
// appropriate
|
||||
AddFloater(aPlaceholder, PR_TRUE);
|
||||
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||
}
|
||||
|
||||
// This is called by the line layout's AddFloater method when a
|
||||
|
@ -4671,7 +4772,8 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
// then the floater is place immediately, otherwise the floater
|
||||
// placement is deferred until the line has been reflowed.
|
||||
void
|
||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder,
|
||||
PRBool aInitialReflow)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Now place the floater immediately if possible. Otherwise stash it
|
||||
// away in mPendingFloaters and place it later.
|
||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
||||
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||
nsRect combinedArea;
|
||||
nsMargin floaterMargins;
|
||||
nsMargin floaterOffsets;
|
||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
|
||||
// Restore coordinate system
|
||||
mSpaceManager->Translate(dx, dy);
|
||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
|||
const nsRect& aDirtyRect,
|
||||
nsFramePaintLayer aWhichLayer)
|
||||
{
|
||||
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef NOISY_DAMAGE_REPAIR
|
||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||
PRInt32 depth = GetDepth();
|
||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||
mBullet, availSize);
|
||||
reflowState.mLineLayout = aState.mLineLayout;
|
||||
nsIHTMLReflow* htmlReflow;
|
||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockFrame::PlaceBullet(nsBlockReflowState& aState)
|
||||
{
|
||||
// First reflow the bullet
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
if (mLines) {
|
||||
// If we have at least one line then let line-layout position the
|
||||
// bullet (this way the bullet is vertically aligned properly).
|
||||
lineLayout->AddBulletFrame(mBullet, metrics);
|
||||
}
|
||||
else {
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
}
|
||||
|
||||
//XXX get rid of this -- its slow
|
||||
void
|
||||
nsBlockFrame::BuildFloaterList()
|
||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
|||
else {
|
||||
// Remove frame from line and mark the line dirty
|
||||
--line->mChildCount;
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||
line->MarkDirty();
|
||||
firstChild->GetNextSibling(&line->mFirstChild);
|
||||
}
|
||||
|
@ -6158,7 +6244,7 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
|
|||
}
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line child count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
count += line->mChildCount;
|
||||
line = line->mNext;
|
||||
}
|
||||
|
|
|
@ -225,6 +225,7 @@ protected:
|
|||
PRBool aKeepReflowGoing);
|
||||
|
||||
nsresult PlaceLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing);
|
||||
|
||||
|
@ -258,7 +259,24 @@ protected:
|
|||
nsLineBox* aLine,
|
||||
PRBool* aKeepLineGoing);
|
||||
|
||||
nsresult DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus);
|
||||
|
||||
nsresult DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus);
|
||||
|
||||
nsresult DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus);
|
||||
|
||||
nsresult ReflowInlineFrame(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRUint8* aLineReflowStatus);
|
||||
|
@ -278,6 +296,7 @@ protected:
|
|||
PRBool& aMadeNewFrame);
|
||||
|
||||
nsresult SplitLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
|
@ -332,8 +351,6 @@ protected:
|
|||
void ReflowBullet(nsBlockReflowState& aState,
|
||||
nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
void PlaceBullet(nsBlockReflowState& aState);
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
nsIFrame* LastChild();
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#include "nsIFocusTracker.h"
|
||||
#include "nsIFrameSelection.h"
|
||||
|
||||
#define MAX_LINE_COUNT 50000
|
||||
|
||||
// XXX HTML:P's that are empty yet have style indicating they should
|
||||
// clear floaters - we need to ignore the clear behavior.
|
||||
|
||||
|
@ -203,8 +205,7 @@ public:
|
|||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout);
|
||||
const nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
|
@ -240,9 +241,11 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
void InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
||||
void AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
PRBool aInitialReflow);
|
||||
|
||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||
|
@ -302,13 +305,20 @@ public:
|
|||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult);
|
||||
|
||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
||||
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult);
|
||||
|
||||
void RecoverStateFrom(nsLineBox* aLine,
|
||||
PRBool aApplyTopMargin,
|
||||
nscoord aDeltaY,
|
||||
nsRect* aDamageRect);
|
||||
|
||||
void AdvanceToNextLine() {
|
||||
mLineNumber++;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is the "global" state computed once for the reflow of
|
||||
|
@ -321,7 +331,7 @@ public:
|
|||
|
||||
const nsHTMLReflowState& mReflowState;
|
||||
|
||||
nsLineLayout* mLineLayout;
|
||||
// nsLineLayout* mLineLayout;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
|
||||
|
@ -411,18 +421,22 @@ public:
|
|||
PRBool mComputeMaxElementSize;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->InitFloater(aFrame);
|
||||
mBlockRS->InitFloater(*this, aFrame);
|
||||
}
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->AddFloater(aFrame, PR_FALSE);
|
||||
mBlockRS->AddFloater(*this, aFrame, PR_FALSE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -430,8 +444,7 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
|||
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout)
|
||||
const nsHTMLReflowMetrics& aMetrics)
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0)
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
|
||||
// Translate into our content area and then save the
|
||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if (0 != borderPadding.top) {
|
||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||
aReflowState.frame);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
|||
// at the current Y coordinate. This method assumes that
|
||||
// GetAvailableSpace has already been called.
|
||||
void
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
nscoord availHeight = mUnconstrainedHeight
|
||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
nscoord availX, availWidth;
|
||||
if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == aDisplay->mDisplay) {
|
||||
// XXX This is a hack until the css2 folks can figure how to deal
|
||||
// with list-items and floaters.
|
||||
nscoord leftMargin = 0;
|
||||
#if 0
|
||||
if (mAvailSpaceRect.x != borderPadding.left) {
|
||||
// When a list-item is impacted by a left floater, slide it over
|
||||
// by the right amount so that the bullets will (hopefully) be
|
||||
// visible.
|
||||
float p2t;
|
||||
mPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
leftMargin = NSIntPixelsToTwips(40, p2t);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assume the frame is clueless about the space manager and only
|
||||
// give it free space.
|
||||
availX = mAvailSpaceRect.x + borderPadding.left + leftMargin;
|
||||
availWidth = mAvailSpaceRect.width - leftMargin;
|
||||
}
|
||||
else if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
// Frames that know how to do non-rectangular splitting are given
|
||||
// the entire available space, including space consumed by
|
||||
// floaters.
|
||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||
availWidth = mAvailSpaceRect.width;
|
||||
}
|
||||
|
||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
||||
}
|
||||
|
||||
|
@ -630,10 +669,13 @@ nsBlockReflowState::RecoverVerticalMargins(nsLineBox* aLine,
|
|||
// Setup reflow state to compute the block childs top and bottom
|
||||
// margins
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
nsRect availSpaceRect;
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpaceRect;
|
||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
||||
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||
frame, availSpace);
|
||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
||||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||
#ifdef DEBUG_kipp
|
||||
{
|
||||
extern char* nsPresShell_ReflowStackPointerTop;
|
||||
char marker;
|
||||
char* newsp = (char*) ▮
|
||||
printf("XXX: frame tree is too deep; approx stack size = %d\n",
|
||||
nsPresShell_ReflowStackPointerTop - newsp);
|
||||
}
|
||||
#endif
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
nsresult rv = NS_OK;
|
||||
PRBool keepGoing = PR_TRUE;
|
||||
|
||||
// Inform line layout of where the text runs are
|
||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||
nsIReflowCommand::ReflowType type;
|
||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
|
||||
// Pull data from a next-in-flow if we can
|
||||
|
@ -2049,13 +2098,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an odd-ball case: a list-item with no lines
|
||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
||||
PlaceBullet(aState);
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
|||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||
}
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (0 != --fromLine->mChildCount) {
|
||||
NS_ASSERTION(fromLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(fromLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
// Mark line dirty now that we pulled a child
|
||||
fromLine->MarkDirty();
|
||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if ((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
|
||||
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace)) {
|
||||
// Since whitespace is significant, we know that the paragraph
|
||||
// is not empty (even if it has no text in it because it has
|
||||
return PR_FALSE;
|
||||
|
||||
static PRBool
|
||||
IsEmptyHTMLParagraph(nsIFrame* aFrame)
|
||||
{
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, (void**)&bf)) &&
|
||||
nsBlockReflowContext::IsHTMLParagraph(aFrame)) {
|
||||
if (!bf->mLines) {
|
||||
// It's an html paragraph and it's empty
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsLineBox* line = bf->mLines;
|
||||
while (line) {
|
||||
if (!IsEmptyLine(line)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
static void ComputeCombinedArea(const nsRect aRect1, const nsRect aRect2, nsRect& aOutRect)
|
||||
{
|
||||
// Rect 1's top left point: (aRect.x, aRect1.y)
|
||||
// Rect 2's top left point: (aRect2.x, aRect2.y)
|
||||
// Rect 2's bottom right point: (x2, y2)
|
||||
// Output rect's top left point: (aOutRect.x, aOutRect.y)
|
||||
// Output rect's bottom right point: (xOut, yOut)
|
||||
|
||||
//
|
||||
// Calculate the top left point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's top left point to Rect 1's top left point
|
||||
aOutRect.x = aRect1.x;
|
||||
aOutRect.y = aRect1.y;
|
||||
if (aRect2.x < aRect1.x) {
|
||||
aOutRect.x = aRect2.x;
|
||||
}
|
||||
if (aRect2.y < aRect1.y) {
|
||||
aOutRect.y = aRect2.y;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the bottom right point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's bottom right point to Rect 1's bottom right point
|
||||
nscoord xOut = aRect1.x + aRect1.width;
|
||||
nscoord yOut = aRect1.y + aRect1.height;
|
||||
// Initialize Rect 2's bottom right point
|
||||
nscoord x2 = aRect2.x + aRect2.width;
|
||||
nscoord y2 = aRect2.y + aRect2.height;
|
||||
if (x2 > xOut) {
|
||||
xOut = x2;
|
||||
}
|
||||
if (y2 > yOut) {
|
||||
yOut = y2;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the width and height on the output rect.
|
||||
//
|
||||
aOutRect.width = xOut - aOutRect.x;
|
||||
aOutRect.height = yOut - aOutRect.y;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpace;
|
||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
||||
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||
|
||||
// Reflow the block into the available space
|
||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Do not count the continuation child on the line it used
|
||||
// to be on
|
||||
aLine->mChildCount--;
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
}
|
||||
|
||||
// Advance to next line since some of the block fit. That way
|
||||
|
@ -2885,11 +2926,6 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
bbox.y = aState.BorderPadding().top + ascent -
|
||||
metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
|
||||
// Fix for bug 8314. Include the bullet's area in the combined area
|
||||
// of the current line.
|
||||
ComputeCombinedArea((const nsRect) bbox, (const nsRect) aLine->mCombinedArea,
|
||||
aLine->mCombinedArea);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
#ifdef DEBUG
|
||||
PRInt32 spins = 0;
|
||||
#endif
|
||||
for (;;) {
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// Prevent overflowing limited thread stacks by creating
|
||||
// nsLineLayout from the heap when the frame tree depth gets
|
||||
// large.
|
||||
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == lineLayout->GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
lineLayout->SetFirstLetterStyleOK(PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout* ll = new nsLineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
ll->SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
|
||||
aLineReflowStatus);
|
||||
ll->EndLineReflow();
|
||||
delete ll;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
aKeepReflowGoing, aLineReflowStatus);
|
||||
lineLayout.EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
aLineLayout.BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == aLineLayout.GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
nsresult rv = NS_OK;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
}
|
||||
else {
|
||||
// If we are propogating out a break-before status then there is
|
||||
// no point in placing the line.
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
lineLayout->EndLineReflow();
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||
}
|
||||
else {
|
||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
*aLineReflowStatus = lineReflowStatus;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
*/
|
||||
nsresult
|
||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRUint8* aLineReflowStatus)
|
||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
|
||||
// If it's currently ok to be reflowing in first-letter style then
|
||||
// we must be about to reflow a frame that has first-letter style.
|
||||
PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK();
|
||||
PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
|
||||
#ifdef NOISY_FIRST_LETTER
|
||||
ListTag(stdout);
|
||||
printf(": reflowing ");
|
||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
#endif
|
||||
|
||||
// Reflow the inline frame
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
else {
|
||||
// It's not the first child on this line so go ahead and split
|
||||
// the line. We will see the frame again on the next-line.
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line, but after the frame just reflowed
|
||||
nsIFrame* nextFrame;
|
||||
aFrame->GetNextSibling(&nextFrame);
|
||||
rv = SplitLine(aState, aLine, nextFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line after the current frame
|
||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||
aFrame->GetNextSibling(&aFrame);
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
if (nsnull != nextInFlow) {
|
||||
aMadeNewFrame = PR_TRUE;
|
||||
aLine->mChildCount++;
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_FALSE);
|
||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
||||
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||
//aLine->List(stdout, 0);
|
||||
|
@ -3294,7 +3394,7 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
|||
// Let line layout know that some frames are no longer part of its
|
||||
// state.
|
||||
if (!aLine->IsBlock()) {
|
||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
||||
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_TRUE);
|
||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing)
|
||||
{
|
||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// method is used for placing a line of inline frames. If the rare
|
||||
// case is happening then the worst that will happen is that the
|
||||
// bullet frame will be reflowed twice.
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRBool addedBullet = PR_FALSE;
|
||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
||||
PlaceBullet(aState);
|
||||
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||
addedBullet = PR_TRUE;
|
||||
}
|
||||
nsSize maxElementSize;
|
||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
static nscoord lastHeight = 0;
|
||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
||||
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||
if (addedBullet) {
|
||||
lineLayout->RemoveBulletFrame(mBullet);
|
||||
aLineLayout.RemoveBulletFrame(mBullet);
|
||||
}
|
||||
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
|||
else {
|
||||
prevSibLine->mChildCount++;
|
||||
prevSibLine->MarkDirty();
|
||||
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
|
||||
aPrevSibling = newFrame;
|
||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
|||
line = next;
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
// Make the line that just lost a frame dirty
|
||||
line->MarkDirty();
|
||||
|
||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
void
|
||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder)
|
||||
{
|
||||
// Set the geometric parent of the floater
|
||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
|
||||
// Then add the floater to the current line and place it when
|
||||
// appropriate
|
||||
AddFloater(aPlaceholder, PR_TRUE);
|
||||
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||
}
|
||||
|
||||
// This is called by the line layout's AddFloater method when a
|
||||
|
@ -4671,7 +4772,8 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
// then the floater is place immediately, otherwise the floater
|
||||
// placement is deferred until the line has been reflowed.
|
||||
void
|
||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder,
|
||||
PRBool aInitialReflow)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Now place the floater immediately if possible. Otherwise stash it
|
||||
// away in mPendingFloaters and place it later.
|
||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
||||
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||
nsRect combinedArea;
|
||||
nsMargin floaterMargins;
|
||||
nsMargin floaterOffsets;
|
||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
|
||||
// Restore coordinate system
|
||||
mSpaceManager->Translate(dx, dy);
|
||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
|||
const nsRect& aDirtyRect,
|
||||
nsFramePaintLayer aWhichLayer)
|
||||
{
|
||||
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef NOISY_DAMAGE_REPAIR
|
||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||
PRInt32 depth = GetDepth();
|
||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||
mBullet, availSize);
|
||||
reflowState.mLineLayout = aState.mLineLayout;
|
||||
nsIHTMLReflow* htmlReflow;
|
||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockFrame::PlaceBullet(nsBlockReflowState& aState)
|
||||
{
|
||||
// First reflow the bullet
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
if (mLines) {
|
||||
// If we have at least one line then let line-layout position the
|
||||
// bullet (this way the bullet is vertically aligned properly).
|
||||
lineLayout->AddBulletFrame(mBullet, metrics);
|
||||
}
|
||||
else {
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
}
|
||||
|
||||
//XXX get rid of this -- its slow
|
||||
void
|
||||
nsBlockFrame::BuildFloaterList()
|
||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
|||
else {
|
||||
// Remove frame from line and mark the line dirty
|
||||
--line->mChildCount;
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||
line->MarkDirty();
|
||||
firstChild->GetNextSibling(&line->mFirstChild);
|
||||
}
|
||||
|
@ -6158,7 +6244,7 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
|
|||
}
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line child count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
count += line->mChildCount;
|
||||
line = line->mNext;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#include "nsIFocusTracker.h"
|
||||
#include "nsIFrameSelection.h"
|
||||
|
||||
#define MAX_LINE_COUNT 50000
|
||||
|
||||
// XXX HTML:P's that are empty yet have style indicating they should
|
||||
// clear floaters - we need to ignore the clear behavior.
|
||||
|
||||
|
@ -203,8 +205,7 @@ public:
|
|||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout);
|
||||
const nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
|
@ -240,9 +241,11 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
void InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
||||
void AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
PRBool aInitialReflow);
|
||||
|
||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||
|
@ -302,13 +305,20 @@ public:
|
|||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult);
|
||||
|
||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
||||
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult);
|
||||
|
||||
void RecoverStateFrom(nsLineBox* aLine,
|
||||
PRBool aApplyTopMargin,
|
||||
nscoord aDeltaY,
|
||||
nsRect* aDamageRect);
|
||||
|
||||
void AdvanceToNextLine() {
|
||||
mLineNumber++;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is the "global" state computed once for the reflow of
|
||||
|
@ -321,7 +331,7 @@ public:
|
|||
|
||||
const nsHTMLReflowState& mReflowState;
|
||||
|
||||
nsLineLayout* mLineLayout;
|
||||
// nsLineLayout* mLineLayout;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
|
||||
|
@ -411,18 +421,22 @@ public:
|
|||
PRBool mComputeMaxElementSize;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->InitFloater(aFrame);
|
||||
mBlockRS->InitFloater(*this, aFrame);
|
||||
}
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->AddFloater(aFrame, PR_FALSE);
|
||||
mBlockRS->AddFloater(*this, aFrame, PR_FALSE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -430,8 +444,7 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
|||
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout)
|
||||
const nsHTMLReflowMetrics& aMetrics)
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0)
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
|
||||
// Translate into our content area and then save the
|
||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if (0 != borderPadding.top) {
|
||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||
aReflowState.frame);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
|||
// at the current Y coordinate. This method assumes that
|
||||
// GetAvailableSpace has already been called.
|
||||
void
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
nscoord availHeight = mUnconstrainedHeight
|
||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
nscoord availX, availWidth;
|
||||
if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == aDisplay->mDisplay) {
|
||||
// XXX This is a hack until the css2 folks can figure how to deal
|
||||
// with list-items and floaters.
|
||||
nscoord leftMargin = 0;
|
||||
#if 0
|
||||
if (mAvailSpaceRect.x != borderPadding.left) {
|
||||
// When a list-item is impacted by a left floater, slide it over
|
||||
// by the right amount so that the bullets will (hopefully) be
|
||||
// visible.
|
||||
float p2t;
|
||||
mPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
leftMargin = NSIntPixelsToTwips(40, p2t);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assume the frame is clueless about the space manager and only
|
||||
// give it free space.
|
||||
availX = mAvailSpaceRect.x + borderPadding.left + leftMargin;
|
||||
availWidth = mAvailSpaceRect.width - leftMargin;
|
||||
}
|
||||
else if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
// Frames that know how to do non-rectangular splitting are given
|
||||
// the entire available space, including space consumed by
|
||||
// floaters.
|
||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||
availWidth = mAvailSpaceRect.width;
|
||||
}
|
||||
|
||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
||||
}
|
||||
|
||||
|
@ -630,10 +669,13 @@ nsBlockReflowState::RecoverVerticalMargins(nsLineBox* aLine,
|
|||
// Setup reflow state to compute the block childs top and bottom
|
||||
// margins
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
nsRect availSpaceRect;
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpaceRect;
|
||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
||||
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||
frame, availSpace);
|
||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
||||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||
#ifdef DEBUG_kipp
|
||||
{
|
||||
extern char* nsPresShell_ReflowStackPointerTop;
|
||||
char marker;
|
||||
char* newsp = (char*) ▮
|
||||
printf("XXX: frame tree is too deep; approx stack size = %d\n",
|
||||
nsPresShell_ReflowStackPointerTop - newsp);
|
||||
}
|
||||
#endif
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
nsresult rv = NS_OK;
|
||||
PRBool keepGoing = PR_TRUE;
|
||||
|
||||
// Inform line layout of where the text runs are
|
||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||
nsIReflowCommand::ReflowType type;
|
||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
|
||||
// Pull data from a next-in-flow if we can
|
||||
|
@ -2049,13 +2098,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an odd-ball case: a list-item with no lines
|
||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
||||
PlaceBullet(aState);
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
|||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||
}
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (0 != --fromLine->mChildCount) {
|
||||
NS_ASSERTION(fromLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(fromLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
// Mark line dirty now that we pulled a child
|
||||
fromLine->MarkDirty();
|
||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if ((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
|
||||
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace)) {
|
||||
// Since whitespace is significant, we know that the paragraph
|
||||
// is not empty (even if it has no text in it because it has
|
||||
return PR_FALSE;
|
||||
|
||||
static PRBool
|
||||
IsEmptyHTMLParagraph(nsIFrame* aFrame)
|
||||
{
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, (void**)&bf)) &&
|
||||
nsBlockReflowContext::IsHTMLParagraph(aFrame)) {
|
||||
if (!bf->mLines) {
|
||||
// It's an html paragraph and it's empty
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsLineBox* line = bf->mLines;
|
||||
while (line) {
|
||||
if (!IsEmptyLine(line)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
static void ComputeCombinedArea(const nsRect aRect1, const nsRect aRect2, nsRect& aOutRect)
|
||||
{
|
||||
// Rect 1's top left point: (aRect.x, aRect1.y)
|
||||
// Rect 2's top left point: (aRect2.x, aRect2.y)
|
||||
// Rect 2's bottom right point: (x2, y2)
|
||||
// Output rect's top left point: (aOutRect.x, aOutRect.y)
|
||||
// Output rect's bottom right point: (xOut, yOut)
|
||||
|
||||
//
|
||||
// Calculate the top left point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's top left point to Rect 1's top left point
|
||||
aOutRect.x = aRect1.x;
|
||||
aOutRect.y = aRect1.y;
|
||||
if (aRect2.x < aRect1.x) {
|
||||
aOutRect.x = aRect2.x;
|
||||
}
|
||||
if (aRect2.y < aRect1.y) {
|
||||
aOutRect.y = aRect2.y;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the bottom right point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's bottom right point to Rect 1's bottom right point
|
||||
nscoord xOut = aRect1.x + aRect1.width;
|
||||
nscoord yOut = aRect1.y + aRect1.height;
|
||||
// Initialize Rect 2's bottom right point
|
||||
nscoord x2 = aRect2.x + aRect2.width;
|
||||
nscoord y2 = aRect2.y + aRect2.height;
|
||||
if (x2 > xOut) {
|
||||
xOut = x2;
|
||||
}
|
||||
if (y2 > yOut) {
|
||||
yOut = y2;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the width and height on the output rect.
|
||||
//
|
||||
aOutRect.width = xOut - aOutRect.x;
|
||||
aOutRect.height = yOut - aOutRect.y;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpace;
|
||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
||||
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||
|
||||
// Reflow the block into the available space
|
||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Do not count the continuation child on the line it used
|
||||
// to be on
|
||||
aLine->mChildCount--;
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
}
|
||||
|
||||
// Advance to next line since some of the block fit. That way
|
||||
|
@ -2885,11 +2926,6 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
bbox.y = aState.BorderPadding().top + ascent -
|
||||
metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
|
||||
// Fix for bug 8314. Include the bullet's area in the combined area
|
||||
// of the current line.
|
||||
ComputeCombinedArea((const nsRect) bbox, (const nsRect) aLine->mCombinedArea,
|
||||
aLine->mCombinedArea);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
#ifdef DEBUG
|
||||
PRInt32 spins = 0;
|
||||
#endif
|
||||
for (;;) {
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// Prevent overflowing limited thread stacks by creating
|
||||
// nsLineLayout from the heap when the frame tree depth gets
|
||||
// large.
|
||||
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == lineLayout->GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
lineLayout->SetFirstLetterStyleOK(PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout* ll = new nsLineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
ll->SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
|
||||
aLineReflowStatus);
|
||||
ll->EndLineReflow();
|
||||
delete ll;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
aKeepReflowGoing, aLineReflowStatus);
|
||||
lineLayout.EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
aLineLayout.BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == aLineLayout.GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
nsresult rv = NS_OK;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
}
|
||||
else {
|
||||
// If we are propogating out a break-before status then there is
|
||||
// no point in placing the line.
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
lineLayout->EndLineReflow();
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||
}
|
||||
else {
|
||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
*aLineReflowStatus = lineReflowStatus;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
*/
|
||||
nsresult
|
||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRUint8* aLineReflowStatus)
|
||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
|
||||
// If it's currently ok to be reflowing in first-letter style then
|
||||
// we must be about to reflow a frame that has first-letter style.
|
||||
PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK();
|
||||
PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
|
||||
#ifdef NOISY_FIRST_LETTER
|
||||
ListTag(stdout);
|
||||
printf(": reflowing ");
|
||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
#endif
|
||||
|
||||
// Reflow the inline frame
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
else {
|
||||
// It's not the first child on this line so go ahead and split
|
||||
// the line. We will see the frame again on the next-line.
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line, but after the frame just reflowed
|
||||
nsIFrame* nextFrame;
|
||||
aFrame->GetNextSibling(&nextFrame);
|
||||
rv = SplitLine(aState, aLine, nextFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line after the current frame
|
||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||
aFrame->GetNextSibling(&aFrame);
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
if (nsnull != nextInFlow) {
|
||||
aMadeNewFrame = PR_TRUE;
|
||||
aLine->mChildCount++;
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_FALSE);
|
||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
||||
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||
//aLine->List(stdout, 0);
|
||||
|
@ -3294,7 +3394,7 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
|||
// Let line layout know that some frames are no longer part of its
|
||||
// state.
|
||||
if (!aLine->IsBlock()) {
|
||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
||||
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_TRUE);
|
||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing)
|
||||
{
|
||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// method is used for placing a line of inline frames. If the rare
|
||||
// case is happening then the worst that will happen is that the
|
||||
// bullet frame will be reflowed twice.
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRBool addedBullet = PR_FALSE;
|
||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
||||
PlaceBullet(aState);
|
||||
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||
addedBullet = PR_TRUE;
|
||||
}
|
||||
nsSize maxElementSize;
|
||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
static nscoord lastHeight = 0;
|
||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
||||
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||
if (addedBullet) {
|
||||
lineLayout->RemoveBulletFrame(mBullet);
|
||||
aLineLayout.RemoveBulletFrame(mBullet);
|
||||
}
|
||||
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
|||
else {
|
||||
prevSibLine->mChildCount++;
|
||||
prevSibLine->MarkDirty();
|
||||
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
|
||||
aPrevSibling = newFrame;
|
||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
|||
line = next;
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
// Make the line that just lost a frame dirty
|
||||
line->MarkDirty();
|
||||
|
||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
void
|
||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder)
|
||||
{
|
||||
// Set the geometric parent of the floater
|
||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
|
||||
// Then add the floater to the current line and place it when
|
||||
// appropriate
|
||||
AddFloater(aPlaceholder, PR_TRUE);
|
||||
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||
}
|
||||
|
||||
// This is called by the line layout's AddFloater method when a
|
||||
|
@ -4671,7 +4772,8 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
// then the floater is place immediately, otherwise the floater
|
||||
// placement is deferred until the line has been reflowed.
|
||||
void
|
||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder,
|
||||
PRBool aInitialReflow)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Now place the floater immediately if possible. Otherwise stash it
|
||||
// away in mPendingFloaters and place it later.
|
||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
||||
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||
nsRect combinedArea;
|
||||
nsMargin floaterMargins;
|
||||
nsMargin floaterOffsets;
|
||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
|
||||
// Restore coordinate system
|
||||
mSpaceManager->Translate(dx, dy);
|
||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
|||
const nsRect& aDirtyRect,
|
||||
nsFramePaintLayer aWhichLayer)
|
||||
{
|
||||
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef NOISY_DAMAGE_REPAIR
|
||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||
PRInt32 depth = GetDepth();
|
||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||
mBullet, availSize);
|
||||
reflowState.mLineLayout = aState.mLineLayout;
|
||||
nsIHTMLReflow* htmlReflow;
|
||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockFrame::PlaceBullet(nsBlockReflowState& aState)
|
||||
{
|
||||
// First reflow the bullet
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
if (mLines) {
|
||||
// If we have at least one line then let line-layout position the
|
||||
// bullet (this way the bullet is vertically aligned properly).
|
||||
lineLayout->AddBulletFrame(mBullet, metrics);
|
||||
}
|
||||
else {
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
}
|
||||
|
||||
//XXX get rid of this -- its slow
|
||||
void
|
||||
nsBlockFrame::BuildFloaterList()
|
||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
|||
else {
|
||||
// Remove frame from line and mark the line dirty
|
||||
--line->mChildCount;
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||
line->MarkDirty();
|
||||
firstChild->GetNextSibling(&line->mFirstChild);
|
||||
}
|
||||
|
@ -6158,7 +6244,7 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
|
|||
}
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line child count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
count += line->mChildCount;
|
||||
line = line->mNext;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#include "nsIFocusTracker.h"
|
||||
#include "nsIFrameSelection.h"
|
||||
|
||||
#define MAX_LINE_COUNT 50000
|
||||
|
||||
// XXX HTML:P's that are empty yet have style indicating they should
|
||||
// clear floaters - we need to ignore the clear behavior.
|
||||
|
||||
|
@ -203,8 +205,7 @@ public:
|
|||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout);
|
||||
const nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
|
@ -240,9 +241,11 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
void InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
||||
void AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
PRBool aInitialReflow);
|
||||
|
||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||
|
@ -302,13 +305,20 @@ public:
|
|||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult);
|
||||
|
||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
||||
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult);
|
||||
|
||||
void RecoverStateFrom(nsLineBox* aLine,
|
||||
PRBool aApplyTopMargin,
|
||||
nscoord aDeltaY,
|
||||
nsRect* aDamageRect);
|
||||
|
||||
void AdvanceToNextLine() {
|
||||
mLineNumber++;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is the "global" state computed once for the reflow of
|
||||
|
@ -321,7 +331,7 @@ public:
|
|||
|
||||
const nsHTMLReflowState& mReflowState;
|
||||
|
||||
nsLineLayout* mLineLayout;
|
||||
// nsLineLayout* mLineLayout;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
|
||||
|
@ -411,18 +421,22 @@ public:
|
|||
PRBool mComputeMaxElementSize;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->InitFloater(aFrame);
|
||||
mBlockRS->InitFloater(*this, aFrame);
|
||||
}
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->AddFloater(aFrame, PR_FALSE);
|
||||
mBlockRS->AddFloater(*this, aFrame, PR_FALSE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -430,8 +444,7 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
|||
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout)
|
||||
const nsHTMLReflowMetrics& aMetrics)
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0)
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
|
||||
// Translate into our content area and then save the
|
||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if (0 != borderPadding.top) {
|
||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||
aReflowState.frame);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
|||
// at the current Y coordinate. This method assumes that
|
||||
// GetAvailableSpace has already been called.
|
||||
void
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
nscoord availHeight = mUnconstrainedHeight
|
||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
nscoord availX, availWidth;
|
||||
if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == aDisplay->mDisplay) {
|
||||
// XXX This is a hack until the css2 folks can figure how to deal
|
||||
// with list-items and floaters.
|
||||
nscoord leftMargin = 0;
|
||||
#if 0
|
||||
if (mAvailSpaceRect.x != borderPadding.left) {
|
||||
// When a list-item is impacted by a left floater, slide it over
|
||||
// by the right amount so that the bullets will (hopefully) be
|
||||
// visible.
|
||||
float p2t;
|
||||
mPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
leftMargin = NSIntPixelsToTwips(40, p2t);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assume the frame is clueless about the space manager and only
|
||||
// give it free space.
|
||||
availX = mAvailSpaceRect.x + borderPadding.left + leftMargin;
|
||||
availWidth = mAvailSpaceRect.width - leftMargin;
|
||||
}
|
||||
else if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
// Frames that know how to do non-rectangular splitting are given
|
||||
// the entire available space, including space consumed by
|
||||
// floaters.
|
||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||
availWidth = mAvailSpaceRect.width;
|
||||
}
|
||||
|
||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
||||
}
|
||||
|
||||
|
@ -630,10 +669,13 @@ nsBlockReflowState::RecoverVerticalMargins(nsLineBox* aLine,
|
|||
// Setup reflow state to compute the block childs top and bottom
|
||||
// margins
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
nsRect availSpaceRect;
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpaceRect;
|
||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
||||
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||
frame, availSpace);
|
||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
||||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||
#ifdef DEBUG_kipp
|
||||
{
|
||||
extern char* nsPresShell_ReflowStackPointerTop;
|
||||
char marker;
|
||||
char* newsp = (char*) ▮
|
||||
printf("XXX: frame tree is too deep; approx stack size = %d\n",
|
||||
nsPresShell_ReflowStackPointerTop - newsp);
|
||||
}
|
||||
#endif
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
nsresult rv = NS_OK;
|
||||
PRBool keepGoing = PR_TRUE;
|
||||
|
||||
// Inform line layout of where the text runs are
|
||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||
nsIReflowCommand::ReflowType type;
|
||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
|
||||
// Pull data from a next-in-flow if we can
|
||||
|
@ -2049,13 +2098,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an odd-ball case: a list-item with no lines
|
||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
||||
PlaceBullet(aState);
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
|||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||
}
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (0 != --fromLine->mChildCount) {
|
||||
NS_ASSERTION(fromLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(fromLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
// Mark line dirty now that we pulled a child
|
||||
fromLine->MarkDirty();
|
||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if ((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
|
||||
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace)) {
|
||||
// Since whitespace is significant, we know that the paragraph
|
||||
// is not empty (even if it has no text in it because it has
|
||||
return PR_FALSE;
|
||||
|
||||
static PRBool
|
||||
IsEmptyHTMLParagraph(nsIFrame* aFrame)
|
||||
{
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, (void**)&bf)) &&
|
||||
nsBlockReflowContext::IsHTMLParagraph(aFrame)) {
|
||||
if (!bf->mLines) {
|
||||
// It's an html paragraph and it's empty
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsLineBox* line = bf->mLines;
|
||||
while (line) {
|
||||
if (!IsEmptyLine(line)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
static void ComputeCombinedArea(const nsRect aRect1, const nsRect aRect2, nsRect& aOutRect)
|
||||
{
|
||||
// Rect 1's top left point: (aRect.x, aRect1.y)
|
||||
// Rect 2's top left point: (aRect2.x, aRect2.y)
|
||||
// Rect 2's bottom right point: (x2, y2)
|
||||
// Output rect's top left point: (aOutRect.x, aOutRect.y)
|
||||
// Output rect's bottom right point: (xOut, yOut)
|
||||
|
||||
//
|
||||
// Calculate the top left point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's top left point to Rect 1's top left point
|
||||
aOutRect.x = aRect1.x;
|
||||
aOutRect.y = aRect1.y;
|
||||
if (aRect2.x < aRect1.x) {
|
||||
aOutRect.x = aRect2.x;
|
||||
}
|
||||
if (aRect2.y < aRect1.y) {
|
||||
aOutRect.y = aRect2.y;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the bottom right point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's bottom right point to Rect 1's bottom right point
|
||||
nscoord xOut = aRect1.x + aRect1.width;
|
||||
nscoord yOut = aRect1.y + aRect1.height;
|
||||
// Initialize Rect 2's bottom right point
|
||||
nscoord x2 = aRect2.x + aRect2.width;
|
||||
nscoord y2 = aRect2.y + aRect2.height;
|
||||
if (x2 > xOut) {
|
||||
xOut = x2;
|
||||
}
|
||||
if (y2 > yOut) {
|
||||
yOut = y2;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the width and height on the output rect.
|
||||
//
|
||||
aOutRect.width = xOut - aOutRect.x;
|
||||
aOutRect.height = yOut - aOutRect.y;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpace;
|
||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
||||
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||
|
||||
// Reflow the block into the available space
|
||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Do not count the continuation child on the line it used
|
||||
// to be on
|
||||
aLine->mChildCount--;
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
}
|
||||
|
||||
// Advance to next line since some of the block fit. That way
|
||||
|
@ -2885,11 +2926,6 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
bbox.y = aState.BorderPadding().top + ascent -
|
||||
metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
|
||||
// Fix for bug 8314. Include the bullet's area in the combined area
|
||||
// of the current line.
|
||||
ComputeCombinedArea((const nsRect) bbox, (const nsRect) aLine->mCombinedArea,
|
||||
aLine->mCombinedArea);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
#ifdef DEBUG
|
||||
PRInt32 spins = 0;
|
||||
#endif
|
||||
for (;;) {
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// Prevent overflowing limited thread stacks by creating
|
||||
// nsLineLayout from the heap when the frame tree depth gets
|
||||
// large.
|
||||
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == lineLayout->GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
lineLayout->SetFirstLetterStyleOK(PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout* ll = new nsLineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
ll->SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
|
||||
aLineReflowStatus);
|
||||
ll->EndLineReflow();
|
||||
delete ll;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
aKeepReflowGoing, aLineReflowStatus);
|
||||
lineLayout.EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
aLineLayout.BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == aLineLayout.GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
nsresult rv = NS_OK;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
}
|
||||
else {
|
||||
// If we are propogating out a break-before status then there is
|
||||
// no point in placing the line.
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
lineLayout->EndLineReflow();
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||
}
|
||||
else {
|
||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
*aLineReflowStatus = lineReflowStatus;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
*/
|
||||
nsresult
|
||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRUint8* aLineReflowStatus)
|
||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
|
||||
// If it's currently ok to be reflowing in first-letter style then
|
||||
// we must be about to reflow a frame that has first-letter style.
|
||||
PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK();
|
||||
PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
|
||||
#ifdef NOISY_FIRST_LETTER
|
||||
ListTag(stdout);
|
||||
printf(": reflowing ");
|
||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
#endif
|
||||
|
||||
// Reflow the inline frame
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
else {
|
||||
// It's not the first child on this line so go ahead and split
|
||||
// the line. We will see the frame again on the next-line.
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line, but after the frame just reflowed
|
||||
nsIFrame* nextFrame;
|
||||
aFrame->GetNextSibling(&nextFrame);
|
||||
rv = SplitLine(aState, aLine, nextFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line after the current frame
|
||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||
aFrame->GetNextSibling(&aFrame);
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
if (nsnull != nextInFlow) {
|
||||
aMadeNewFrame = PR_TRUE;
|
||||
aLine->mChildCount++;
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_FALSE);
|
||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
||||
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||
//aLine->List(stdout, 0);
|
||||
|
@ -3294,7 +3394,7 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
|||
// Let line layout know that some frames are no longer part of its
|
||||
// state.
|
||||
if (!aLine->IsBlock()) {
|
||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
||||
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_TRUE);
|
||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing)
|
||||
{
|
||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// method is used for placing a line of inline frames. If the rare
|
||||
// case is happening then the worst that will happen is that the
|
||||
// bullet frame will be reflowed twice.
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRBool addedBullet = PR_FALSE;
|
||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
||||
PlaceBullet(aState);
|
||||
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||
addedBullet = PR_TRUE;
|
||||
}
|
||||
nsSize maxElementSize;
|
||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
static nscoord lastHeight = 0;
|
||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
||||
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||
if (addedBullet) {
|
||||
lineLayout->RemoveBulletFrame(mBullet);
|
||||
aLineLayout.RemoveBulletFrame(mBullet);
|
||||
}
|
||||
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
|||
else {
|
||||
prevSibLine->mChildCount++;
|
||||
prevSibLine->MarkDirty();
|
||||
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
|
||||
aPrevSibling = newFrame;
|
||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
|||
line = next;
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
// Make the line that just lost a frame dirty
|
||||
line->MarkDirty();
|
||||
|
||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
void
|
||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder)
|
||||
{
|
||||
// Set the geometric parent of the floater
|
||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
|
||||
// Then add the floater to the current line and place it when
|
||||
// appropriate
|
||||
AddFloater(aPlaceholder, PR_TRUE);
|
||||
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||
}
|
||||
|
||||
// This is called by the line layout's AddFloater method when a
|
||||
|
@ -4671,7 +4772,8 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
// then the floater is place immediately, otherwise the floater
|
||||
// placement is deferred until the line has been reflowed.
|
||||
void
|
||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder,
|
||||
PRBool aInitialReflow)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Now place the floater immediately if possible. Otherwise stash it
|
||||
// away in mPendingFloaters and place it later.
|
||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
||||
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||
nsRect combinedArea;
|
||||
nsMargin floaterMargins;
|
||||
nsMargin floaterOffsets;
|
||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
|
||||
// Restore coordinate system
|
||||
mSpaceManager->Translate(dx, dy);
|
||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
|||
const nsRect& aDirtyRect,
|
||||
nsFramePaintLayer aWhichLayer)
|
||||
{
|
||||
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef NOISY_DAMAGE_REPAIR
|
||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||
PRInt32 depth = GetDepth();
|
||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||
mBullet, availSize);
|
||||
reflowState.mLineLayout = aState.mLineLayout;
|
||||
nsIHTMLReflow* htmlReflow;
|
||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockFrame::PlaceBullet(nsBlockReflowState& aState)
|
||||
{
|
||||
// First reflow the bullet
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
if (mLines) {
|
||||
// If we have at least one line then let line-layout position the
|
||||
// bullet (this way the bullet is vertically aligned properly).
|
||||
lineLayout->AddBulletFrame(mBullet, metrics);
|
||||
}
|
||||
else {
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
}
|
||||
|
||||
//XXX get rid of this -- its slow
|
||||
void
|
||||
nsBlockFrame::BuildFloaterList()
|
||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
|||
else {
|
||||
// Remove frame from line and mark the line dirty
|
||||
--line->mChildCount;
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||
line->MarkDirty();
|
||||
firstChild->GetNextSibling(&line->mFirstChild);
|
||||
}
|
||||
|
@ -6158,7 +6244,7 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
|
|||
}
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line child count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
count += line->mChildCount;
|
||||
line = line->mNext;
|
||||
}
|
||||
|
|
|
@ -225,6 +225,7 @@ protected:
|
|||
PRBool aKeepReflowGoing);
|
||||
|
||||
nsresult PlaceLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing);
|
||||
|
||||
|
@ -258,7 +259,24 @@ protected:
|
|||
nsLineBox* aLine,
|
||||
PRBool* aKeepLineGoing);
|
||||
|
||||
nsresult DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus);
|
||||
|
||||
nsresult DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus);
|
||||
|
||||
nsresult DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus);
|
||||
|
||||
nsresult ReflowInlineFrame(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRUint8* aLineReflowStatus);
|
||||
|
@ -278,6 +296,7 @@ protected:
|
|||
PRBool& aMadeNewFrame);
|
||||
|
||||
nsresult SplitLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
|
@ -332,8 +351,6 @@ protected:
|
|||
void ReflowBullet(nsBlockReflowState& aState,
|
||||
nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
void PlaceBullet(nsBlockReflowState& aState);
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
nsIFrame* LastChild();
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#include "nsIFocusTracker.h"
|
||||
#include "nsIFrameSelection.h"
|
||||
|
||||
#define MAX_LINE_COUNT 50000
|
||||
|
||||
// XXX HTML:P's that are empty yet have style indicating they should
|
||||
// clear floaters - we need to ignore the clear behavior.
|
||||
|
||||
|
@ -203,8 +205,7 @@ public:
|
|||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout);
|
||||
const nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
|
@ -240,9 +241,11 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
void InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
||||
void AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
PRBool aInitialReflow);
|
||||
|
||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||
|
@ -302,13 +305,20 @@ public:
|
|||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult);
|
||||
|
||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
||||
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult);
|
||||
|
||||
void RecoverStateFrom(nsLineBox* aLine,
|
||||
PRBool aApplyTopMargin,
|
||||
nscoord aDeltaY,
|
||||
nsRect* aDamageRect);
|
||||
|
||||
void AdvanceToNextLine() {
|
||||
mLineNumber++;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is the "global" state computed once for the reflow of
|
||||
|
@ -321,7 +331,7 @@ public:
|
|||
|
||||
const nsHTMLReflowState& mReflowState;
|
||||
|
||||
nsLineLayout* mLineLayout;
|
||||
// nsLineLayout* mLineLayout;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
|
||||
|
@ -411,18 +421,22 @@ public:
|
|||
PRBool mComputeMaxElementSize;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->InitFloater(aFrame);
|
||||
mBlockRS->InitFloater(*this, aFrame);
|
||||
}
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->AddFloater(aFrame, PR_FALSE);
|
||||
mBlockRS->AddFloater(*this, aFrame, PR_FALSE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -430,8 +444,7 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
|||
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout)
|
||||
const nsHTMLReflowMetrics& aMetrics)
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0)
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
|
||||
// Translate into our content area and then save the
|
||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if (0 != borderPadding.top) {
|
||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||
aReflowState.frame);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
|||
// at the current Y coordinate. This method assumes that
|
||||
// GetAvailableSpace has already been called.
|
||||
void
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
nscoord availHeight = mUnconstrainedHeight
|
||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
nscoord availX, availWidth;
|
||||
if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == aDisplay->mDisplay) {
|
||||
// XXX This is a hack until the css2 folks can figure how to deal
|
||||
// with list-items and floaters.
|
||||
nscoord leftMargin = 0;
|
||||
#if 0
|
||||
if (mAvailSpaceRect.x != borderPadding.left) {
|
||||
// When a list-item is impacted by a left floater, slide it over
|
||||
// by the right amount so that the bullets will (hopefully) be
|
||||
// visible.
|
||||
float p2t;
|
||||
mPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
leftMargin = NSIntPixelsToTwips(40, p2t);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assume the frame is clueless about the space manager and only
|
||||
// give it free space.
|
||||
availX = mAvailSpaceRect.x + borderPadding.left + leftMargin;
|
||||
availWidth = mAvailSpaceRect.width - leftMargin;
|
||||
}
|
||||
else if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
// Frames that know how to do non-rectangular splitting are given
|
||||
// the entire available space, including space consumed by
|
||||
// floaters.
|
||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||
availWidth = mAvailSpaceRect.width;
|
||||
}
|
||||
|
||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
||||
}
|
||||
|
||||
|
@ -630,10 +669,13 @@ nsBlockReflowState::RecoverVerticalMargins(nsLineBox* aLine,
|
|||
// Setup reflow state to compute the block childs top and bottom
|
||||
// margins
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
nsRect availSpaceRect;
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpaceRect;
|
||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
||||
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||
frame, availSpace);
|
||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
||||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||
#ifdef DEBUG_kipp
|
||||
{
|
||||
extern char* nsPresShell_ReflowStackPointerTop;
|
||||
char marker;
|
||||
char* newsp = (char*) ▮
|
||||
printf("XXX: frame tree is too deep; approx stack size = %d\n",
|
||||
nsPresShell_ReflowStackPointerTop - newsp);
|
||||
}
|
||||
#endif
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
nsresult rv = NS_OK;
|
||||
PRBool keepGoing = PR_TRUE;
|
||||
|
||||
// Inform line layout of where the text runs are
|
||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||
nsIReflowCommand::ReflowType type;
|
||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
|
||||
// Pull data from a next-in-flow if we can
|
||||
|
@ -2049,13 +2098,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an odd-ball case: a list-item with no lines
|
||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
||||
PlaceBullet(aState);
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
|||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||
}
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (0 != --fromLine->mChildCount) {
|
||||
NS_ASSERTION(fromLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(fromLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
// Mark line dirty now that we pulled a child
|
||||
fromLine->MarkDirty();
|
||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if ((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
|
||||
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace)) {
|
||||
// Since whitespace is significant, we know that the paragraph
|
||||
// is not empty (even if it has no text in it because it has
|
||||
return PR_FALSE;
|
||||
|
||||
static PRBool
|
||||
IsEmptyHTMLParagraph(nsIFrame* aFrame)
|
||||
{
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, (void**)&bf)) &&
|
||||
nsBlockReflowContext::IsHTMLParagraph(aFrame)) {
|
||||
if (!bf->mLines) {
|
||||
// It's an html paragraph and it's empty
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsLineBox* line = bf->mLines;
|
||||
while (line) {
|
||||
if (!IsEmptyLine(line)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
static void ComputeCombinedArea(const nsRect aRect1, const nsRect aRect2, nsRect& aOutRect)
|
||||
{
|
||||
// Rect 1's top left point: (aRect.x, aRect1.y)
|
||||
// Rect 2's top left point: (aRect2.x, aRect2.y)
|
||||
// Rect 2's bottom right point: (x2, y2)
|
||||
// Output rect's top left point: (aOutRect.x, aOutRect.y)
|
||||
// Output rect's bottom right point: (xOut, yOut)
|
||||
|
||||
//
|
||||
// Calculate the top left point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's top left point to Rect 1's top left point
|
||||
aOutRect.x = aRect1.x;
|
||||
aOutRect.y = aRect1.y;
|
||||
if (aRect2.x < aRect1.x) {
|
||||
aOutRect.x = aRect2.x;
|
||||
}
|
||||
if (aRect2.y < aRect1.y) {
|
||||
aOutRect.y = aRect2.y;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the bottom right point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's bottom right point to Rect 1's bottom right point
|
||||
nscoord xOut = aRect1.x + aRect1.width;
|
||||
nscoord yOut = aRect1.y + aRect1.height;
|
||||
// Initialize Rect 2's bottom right point
|
||||
nscoord x2 = aRect2.x + aRect2.width;
|
||||
nscoord y2 = aRect2.y + aRect2.height;
|
||||
if (x2 > xOut) {
|
||||
xOut = x2;
|
||||
}
|
||||
if (y2 > yOut) {
|
||||
yOut = y2;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the width and height on the output rect.
|
||||
//
|
||||
aOutRect.width = xOut - aOutRect.x;
|
||||
aOutRect.height = yOut - aOutRect.y;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpace;
|
||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
||||
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||
|
||||
// Reflow the block into the available space
|
||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Do not count the continuation child on the line it used
|
||||
// to be on
|
||||
aLine->mChildCount--;
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
}
|
||||
|
||||
// Advance to next line since some of the block fit. That way
|
||||
|
@ -2885,11 +2926,6 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
bbox.y = aState.BorderPadding().top + ascent -
|
||||
metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
|
||||
// Fix for bug 8314. Include the bullet's area in the combined area
|
||||
// of the current line.
|
||||
ComputeCombinedArea((const nsRect) bbox, (const nsRect) aLine->mCombinedArea,
|
||||
aLine->mCombinedArea);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
#ifdef DEBUG
|
||||
PRInt32 spins = 0;
|
||||
#endif
|
||||
for (;;) {
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// Prevent overflowing limited thread stacks by creating
|
||||
// nsLineLayout from the heap when the frame tree depth gets
|
||||
// large.
|
||||
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == lineLayout->GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
lineLayout->SetFirstLetterStyleOK(PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout* ll = new nsLineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
ll->SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
|
||||
aLineReflowStatus);
|
||||
ll->EndLineReflow();
|
||||
delete ll;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
aKeepReflowGoing, aLineReflowStatus);
|
||||
lineLayout.EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
aLineLayout.BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == aLineLayout.GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
nsresult rv = NS_OK;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
}
|
||||
else {
|
||||
// If we are propogating out a break-before status then there is
|
||||
// no point in placing the line.
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
lineLayout->EndLineReflow();
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||
}
|
||||
else {
|
||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
*aLineReflowStatus = lineReflowStatus;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
*/
|
||||
nsresult
|
||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRUint8* aLineReflowStatus)
|
||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
|
||||
// If it's currently ok to be reflowing in first-letter style then
|
||||
// we must be about to reflow a frame that has first-letter style.
|
||||
PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK();
|
||||
PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
|
||||
#ifdef NOISY_FIRST_LETTER
|
||||
ListTag(stdout);
|
||||
printf(": reflowing ");
|
||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
#endif
|
||||
|
||||
// Reflow the inline frame
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
else {
|
||||
// It's not the first child on this line so go ahead and split
|
||||
// the line. We will see the frame again on the next-line.
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line, but after the frame just reflowed
|
||||
nsIFrame* nextFrame;
|
||||
aFrame->GetNextSibling(&nextFrame);
|
||||
rv = SplitLine(aState, aLine, nextFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line after the current frame
|
||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||
aFrame->GetNextSibling(&aFrame);
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
if (nsnull != nextInFlow) {
|
||||
aMadeNewFrame = PR_TRUE;
|
||||
aLine->mChildCount++;
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_FALSE);
|
||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
||||
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||
//aLine->List(stdout, 0);
|
||||
|
@ -3294,7 +3394,7 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
|||
// Let line layout know that some frames are no longer part of its
|
||||
// state.
|
||||
if (!aLine->IsBlock()) {
|
||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
||||
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_TRUE);
|
||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing)
|
||||
{
|
||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// method is used for placing a line of inline frames. If the rare
|
||||
// case is happening then the worst that will happen is that the
|
||||
// bullet frame will be reflowed twice.
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRBool addedBullet = PR_FALSE;
|
||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
||||
PlaceBullet(aState);
|
||||
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||
addedBullet = PR_TRUE;
|
||||
}
|
||||
nsSize maxElementSize;
|
||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
static nscoord lastHeight = 0;
|
||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
||||
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||
if (addedBullet) {
|
||||
lineLayout->RemoveBulletFrame(mBullet);
|
||||
aLineLayout.RemoveBulletFrame(mBullet);
|
||||
}
|
||||
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
|||
else {
|
||||
prevSibLine->mChildCount++;
|
||||
prevSibLine->MarkDirty();
|
||||
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
|
||||
aPrevSibling = newFrame;
|
||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
|||
line = next;
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
// Make the line that just lost a frame dirty
|
||||
line->MarkDirty();
|
||||
|
||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
void
|
||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder)
|
||||
{
|
||||
// Set the geometric parent of the floater
|
||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
|
||||
// Then add the floater to the current line and place it when
|
||||
// appropriate
|
||||
AddFloater(aPlaceholder, PR_TRUE);
|
||||
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||
}
|
||||
|
||||
// This is called by the line layout's AddFloater method when a
|
||||
|
@ -4671,7 +4772,8 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
// then the floater is place immediately, otherwise the floater
|
||||
// placement is deferred until the line has been reflowed.
|
||||
void
|
||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder,
|
||||
PRBool aInitialReflow)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Now place the floater immediately if possible. Otherwise stash it
|
||||
// away in mPendingFloaters and place it later.
|
||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
||||
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||
nsRect combinedArea;
|
||||
nsMargin floaterMargins;
|
||||
nsMargin floaterOffsets;
|
||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
|
||||
// Restore coordinate system
|
||||
mSpaceManager->Translate(dx, dy);
|
||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
|||
const nsRect& aDirtyRect,
|
||||
nsFramePaintLayer aWhichLayer)
|
||||
{
|
||||
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef NOISY_DAMAGE_REPAIR
|
||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||
PRInt32 depth = GetDepth();
|
||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||
mBullet, availSize);
|
||||
reflowState.mLineLayout = aState.mLineLayout;
|
||||
nsIHTMLReflow* htmlReflow;
|
||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockFrame::PlaceBullet(nsBlockReflowState& aState)
|
||||
{
|
||||
// First reflow the bullet
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
if (mLines) {
|
||||
// If we have at least one line then let line-layout position the
|
||||
// bullet (this way the bullet is vertically aligned properly).
|
||||
lineLayout->AddBulletFrame(mBullet, metrics);
|
||||
}
|
||||
else {
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
}
|
||||
|
||||
//XXX get rid of this -- its slow
|
||||
void
|
||||
nsBlockFrame::BuildFloaterList()
|
||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
|||
else {
|
||||
// Remove frame from line and mark the line dirty
|
||||
--line->mChildCount;
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||
line->MarkDirty();
|
||||
firstChild->GetNextSibling(&line->mFirstChild);
|
||||
}
|
||||
|
@ -6158,7 +6244,7 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
|
|||
}
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line child count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
count += line->mChildCount;
|
||||
line = line->mNext;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#include "nsIFocusTracker.h"
|
||||
#include "nsIFrameSelection.h"
|
||||
|
||||
#define MAX_LINE_COUNT 50000
|
||||
|
||||
// XXX HTML:P's that are empty yet have style indicating they should
|
||||
// clear floaters - we need to ignore the clear behavior.
|
||||
|
||||
|
@ -203,8 +205,7 @@ public:
|
|||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout);
|
||||
const nsHTMLReflowMetrics& aMetrics);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
|
@ -240,9 +241,11 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
void InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
||||
void AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholderFrame,
|
||||
PRBool aInitialReflow);
|
||||
|
||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||
|
@ -302,13 +305,20 @@ public:
|
|||
nscoord* aTopMarginResult,
|
||||
nscoord* aBottomMarginResult);
|
||||
|
||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
||||
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult);
|
||||
|
||||
void RecoverStateFrom(nsLineBox* aLine,
|
||||
PRBool aApplyTopMargin,
|
||||
nscoord aDeltaY,
|
||||
nsRect* aDamageRect);
|
||||
|
||||
void AdvanceToNextLine() {
|
||||
mLineNumber++;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is the "global" state computed once for the reflow of
|
||||
|
@ -321,7 +331,7 @@ public:
|
|||
|
||||
const nsHTMLReflowState& mReflowState;
|
||||
|
||||
nsLineLayout* mLineLayout;
|
||||
// nsLineLayout* mLineLayout;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
|
||||
|
@ -411,18 +421,22 @@ public:
|
|||
PRBool mComputeMaxElementSize;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->InitFloater(aFrame);
|
||||
mBlockRS->InitFloater(*this, aFrame);
|
||||
}
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockRS->AddFloater(aFrame, PR_FALSE);
|
||||
mBlockRS->AddFloater(*this, aFrame, PR_FALSE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -430,8 +444,7 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
|||
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
nsIPresContext* aPresContext,
|
||||
nsBlockFrame* aFrame,
|
||||
const nsHTMLReflowMetrics& aMetrics,
|
||||
nsLineLayout* aLineLayout)
|
||||
const nsHTMLReflowMetrics& aMetrics)
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0)
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
{
|
||||
mLineLayout = aLineLayout;
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
|
||||
// Translate into our content area and then save the
|
||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
|
||||
if (0 != borderPadding.top) {
|
||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|||
if (0 != borderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
}
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||
aReflowState.frame);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
|||
// at the current Y coordinate. This method assumes that
|
||||
// GetAvailableSpace has already been called.
|
||||
void
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
nsSplittableType aSplitType,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
nscoord availHeight = mUnconstrainedHeight
|
||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
nscoord availX, availWidth;
|
||||
if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == aDisplay->mDisplay) {
|
||||
// XXX This is a hack until the css2 folks can figure how to deal
|
||||
// with list-items and floaters.
|
||||
nscoord leftMargin = 0;
|
||||
#if 0
|
||||
if (mAvailSpaceRect.x != borderPadding.left) {
|
||||
// When a list-item is impacted by a left floater, slide it over
|
||||
// by the right amount so that the bullets will (hopefully) be
|
||||
// visible.
|
||||
float p2t;
|
||||
mPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
leftMargin = NSIntPixelsToTwips(40, p2t);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assume the frame is clueless about the space manager and only
|
||||
// give it free space.
|
||||
availX = mAvailSpaceRect.x + borderPadding.left + leftMargin;
|
||||
availWidth = mAvailSpaceRect.width - leftMargin;
|
||||
}
|
||||
else if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) {
|
||||
// Frames that know how to do non-rectangular splitting are given
|
||||
// the entire available space, including space consumed by
|
||||
// floaters.
|
||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
|||
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||
availWidth = mAvailSpaceRect.width;
|
||||
}
|
||||
|
||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
||||
}
|
||||
|
||||
|
@ -630,10 +669,13 @@ nsBlockReflowState::RecoverVerticalMargins(nsLineBox* aLine,
|
|||
// Setup reflow state to compute the block childs top and bottom
|
||||
// margins
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
nsRect availSpaceRect;
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpaceRect;
|
||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
||||
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||
frame, availSpace);
|
||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
||||
&lineLayout);
|
||||
lineLayout.Init(&state);
|
||||
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||
#ifdef DEBUG_kipp
|
||||
{
|
||||
extern char* nsPresShell_ReflowStackPointerTop;
|
||||
char marker;
|
||||
char* newsp = (char*) ▮
|
||||
printf("XXX: frame tree is too deep; approx stack size = %d\n",
|
||||
nsPresShell_ReflowStackPointerTop - newsp);
|
||||
}
|
||||
#endif
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics);
|
||||
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||
state.mIsTopMarginRoot = PR_TRUE;
|
||||
state.mIsBottomMarginRoot = PR_TRUE;
|
||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
nsresult rv = NS_OK;
|
||||
PRBool keepGoing = PR_TRUE;
|
||||
|
||||
// Inform line layout of where the text runs are
|
||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||
nsIReflowCommand::ReflowType type;
|
||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
|
||||
// Pull data from a next-in-flow if we can
|
||||
|
@ -2049,13 +2098,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
// If this is an inline frame then its time to stop
|
||||
aState.mPrevLine = line;
|
||||
line = line->mNext;
|
||||
aState.mLineLayout->AdvanceToNextLine();
|
||||
aState.AdvanceToNextLine();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an odd-ball case: a list-item with no lines
|
||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
||||
PlaceBullet(aState);
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
|
||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
|||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||
}
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (0 != --fromLine->mChildCount) {
|
||||
NS_ASSERTION(fromLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(fromLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
// Mark line dirty now that we pulled a child
|
||||
fromLine->MarkDirty();
|
||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
const nsStyleText* styleText;
|
||||
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
||||
if ((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
|
||||
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace)) {
|
||||
// Since whitespace is significant, we know that the paragraph
|
||||
// is not empty (even if it has no text in it because it has
|
||||
return PR_FALSE;
|
||||
|
||||
static PRBool
|
||||
IsEmptyHTMLParagraph(nsIFrame* aFrame)
|
||||
{
|
||||
nsBlockFrame* bf;
|
||||
if (NS_SUCCEEDED(aRS.frame->QueryInterface(kBlockFrameCID, (void**)&bf)) &&
|
||||
nsBlockReflowContext::IsHTMLParagraph(aFrame)) {
|
||||
if (!bf->mLines) {
|
||||
// It's an html paragraph and it's empty
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsLineBox* line = bf->mLines;
|
||||
while (line) {
|
||||
if (!IsEmptyLine(line)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
line = line->mNext;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIFrame*
|
||||
nsBlockFrame::GetTopBlockChild()
|
||||
{
|
||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
static void ComputeCombinedArea(const nsRect aRect1, const nsRect aRect2, nsRect& aOutRect)
|
||||
{
|
||||
// Rect 1's top left point: (aRect.x, aRect1.y)
|
||||
// Rect 2's top left point: (aRect2.x, aRect2.y)
|
||||
// Rect 2's bottom right point: (x2, y2)
|
||||
// Output rect's top left point: (aOutRect.x, aOutRect.y)
|
||||
// Output rect's bottom right point: (xOut, yOut)
|
||||
|
||||
//
|
||||
// Calculate the top left point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's top left point to Rect 1's top left point
|
||||
aOutRect.x = aRect1.x;
|
||||
aOutRect.y = aRect1.y;
|
||||
if (aRect2.x < aRect1.x) {
|
||||
aOutRect.x = aRect2.x;
|
||||
}
|
||||
if (aRect2.y < aRect1.y) {
|
||||
aOutRect.y = aRect2.y;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the bottom right point of the output rect
|
||||
//
|
||||
|
||||
// Initialize output rect's bottom right point to Rect 1's bottom right point
|
||||
nscoord xOut = aRect1.x + aRect1.width;
|
||||
nscoord yOut = aRect1.y + aRect1.height;
|
||||
// Initialize Rect 2's bottom right point
|
||||
nscoord x2 = aRect2.x + aRect2.width;
|
||||
nscoord y2 = aRect2.y + aRect2.height;
|
||||
if (x2 > xOut) {
|
||||
xOut = x2;
|
||||
}
|
||||
if (y2 > yOut) {
|
||||
yOut = y2;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the width and height on the output rect.
|
||||
//
|
||||
aOutRect.width = xOut - aOutRect.x;
|
||||
aOutRect.height = yOut - aOutRect.y;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||
frame->IsSplittable(splitType);
|
||||
nsRect availSpace;
|
||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
||||
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||
|
||||
// Reflow the block into the available space
|
||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
// Do not count the continuation child on the line it used
|
||||
// to be on
|
||||
aLine->mChildCount--;
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
}
|
||||
|
||||
// Advance to next line since some of the block fit. That way
|
||||
|
@ -2885,11 +2926,6 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
|||
bbox.y = aState.BorderPadding().top + ascent -
|
||||
metrics.ascent + topMargin;
|
||||
mBullet->SetRect(bbox);
|
||||
|
||||
// Fix for bug 8314. Include the bullet's area in the combined area
|
||||
// of the current line.
|
||||
ComputeCombinedArea((const nsRect) bbox, (const nsRect) aLine->mCombinedArea,
|
||||
aLine->mCombinedArea);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
#ifdef DEBUG
|
||||
PRInt32 spins = 0;
|
||||
#endif
|
||||
for (;;) {
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// Prevent overflowing limited thread stacks by creating
|
||||
// nsLineLayout from the heap when the frame tree depth gets
|
||||
// large.
|
||||
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||
&lineReflowStatus);
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
lineLayout->BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == lineLayout->GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
lineLayout->SetFirstLetterStyleOK(PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLine, frame, &lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
lineLayout->EndLineReflow();
|
||||
#ifdef DEBUG
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
spins++;
|
||||
if (1000 == spins) {
|
||||
ListTag(stdout);
|
||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||
NS_ABORT();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout* ll = new nsLineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
ll->SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
|
||||
aLineReflowStatus);
|
||||
ll->EndLineReflow();
|
||||
delete ll;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
nsLineLayout lineLayout(*aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
aKeepReflowGoing, aLineReflowStatus);
|
||||
lineLayout.EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing,
|
||||
PRUint8* aLineReflowStatus)
|
||||
{
|
||||
if (nsnull != aLine->mFloaters) {
|
||||
// Forget all of the floaters on the line
|
||||
aLine->mFloaters->Clear();
|
||||
}
|
||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
||||
aState.mPendingFloaters.Clear();
|
||||
|
||||
// Setup initial coordinate system for reflowing the inline frames
|
||||
// into. Apply a previous block frame's bottom margin first.
|
||||
aState.mY += aState.mPrevBottomMargin;
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
const nsMargin& borderPadding = aState.BorderPadding();
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
/* XXX get the height right! */
|
||||
availHeight = aState.mAvailSpaceRect.height;
|
||||
}
|
||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
||||
aLineLayout.BeginLineReflow(x, aState.mY,
|
||||
availWidth, availHeight,
|
||||
impactedByFloaters,
|
||||
PR_FALSE /*XXX isTopOfPage*/);
|
||||
if ((0 == aLineLayout.GetLineNumber()) &&
|
||||
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
||||
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
|
||||
}
|
||||
|
||||
// Reflow the frames that are already on the line first
|
||||
nsresult rv = NS_OK;
|
||||
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
||||
PRInt32 i;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
for (i = 0; i < aLine->ChildCount(); i++) {
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (LINE_REFLOW_OK != lineReflowStatus) {
|
||||
// It is possible that one or more of next lines are empty
|
||||
// (because of DeleteChildsNextInFlow). If so, delete them now
|
||||
// in case we are finished.
|
||||
nsLineBox* nextLine = aLine->mNext;
|
||||
while ((nsnull != nextLine) && (0 == nextLine->ChildCount())) {
|
||||
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
||||
// uses DoRemoveFrame?
|
||||
aLine->mNext = nextLine->mNext;
|
||||
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
||||
delete nextLine;
|
||||
nextLine = aLine->mNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
|
||||
// Pull frames and reflow them until we can't
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
rv = PullFrame(aState, aLine, frame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (nsnull == frame) {
|
||||
break;
|
||||
}
|
||||
while (LINE_REFLOW_OK == lineReflowStatus) {
|
||||
PRInt32 oldCount = aLine->ChildCount();
|
||||
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
||||
&lineReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (aLine->ChildCount() != oldCount) {
|
||||
// We just created a continuation for aFrame AND its going
|
||||
// to end up on this line (e.g. :first-letter
|
||||
// situation). Therefore we have to loop here before trying
|
||||
// to pull another frame.
|
||||
frame->GetNextSibling(&frame);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floaters and the first element in the line doesn't fit with
|
||||
// the floaters.
|
||||
//
|
||||
// What we do is to advance past the first floater we find and
|
||||
// then reflow the line all over again.
|
||||
NS_ASSERTION(aState.mBand.GetFloaterCount(),
|
||||
"redo line on totally empty line");
|
||||
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
||||
"unconstrained height on totally empty line");
|
||||
aState.mY += aState.mAvailSpaceRect.height;
|
||||
// XXX: a small optimization can be done here when paginating:
|
||||
// if the new Y coordinate is past the end of the block then
|
||||
// push the line and return now instead of later on after we are
|
||||
// past the floater.
|
||||
}
|
||||
else {
|
||||
// If we are propogating out a break-before status then there is
|
||||
// no point in placing the line.
|
||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
lineLayout->EndLineReflow();
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||
}
|
||||
else {
|
||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
*aLineReflowStatus = lineReflowStatus;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
*/
|
||||
nsresult
|
||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame,
|
||||
PRUint8* aLineReflowStatus)
|
||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
|
||||
// If it's currently ok to be reflowing in first-letter style then
|
||||
// we must be about to reflow a frame that has first-letter style.
|
||||
PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK();
|
||||
PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
|
||||
#ifdef NOISY_FIRST_LETTER
|
||||
ListTag(stdout);
|
||||
printf(": reflowing ");
|
||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
#endif
|
||||
|
||||
// Reflow the inline frame
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsReflowStatus frameReflowStatus;
|
||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||
frameReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
else {
|
||||
// It's not the first child on this line so go ahead and split
|
||||
// the line. We will see the frame again on the next-line.
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line, but after the frame just reflowed
|
||||
nsIFrame* nextFrame;
|
||||
aFrame->GetNextSibling(&nextFrame);
|
||||
rv = SplitLine(aState, aLine, nextFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
|||
// Split line after the current frame
|
||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||
aFrame->GetNextSibling(&aFrame);
|
||||
rv = SplitLine(aState, aLine, aFrame);
|
||||
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
if (nsnull != nextInFlow) {
|
||||
aMadeNewFrame = PR_TRUE;
|
||||
aLine->mChildCount++;
|
||||
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_FALSE);
|
||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
||||
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||
//aLine->List(stdout, 0);
|
||||
|
@ -3294,7 +3394,7 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
|||
// Let line layout know that some frames are no longer part of its
|
||||
// state.
|
||||
if (!aLine->IsBlock()) {
|
||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
||||
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
VerifyLines(PR_TRUE);
|
||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
|||
|
||||
nsresult
|
||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
nsLineBox* aLine,
|
||||
PRBool* aKeepReflowGoing)
|
||||
{
|
||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
// method is used for placing a line of inline frames. If the rare
|
||||
// case is happening then the worst that will happen is that the
|
||||
// bullet frame will be reflowed twice.
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
PRBool addedBullet = PR_FALSE;
|
||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
||||
PlaceBullet(aState);
|
||||
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||
addedBullet = PR_TRUE;
|
||||
}
|
||||
nsSize maxElementSize;
|
||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
static nscoord lastHeight = 0;
|
||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
||||
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||
if (addedBullet) {
|
||||
lineLayout->RemoveBulletFrame(mBullet);
|
||||
aLineLayout.RemoveBulletFrame(mBullet);
|
||||
}
|
||||
|
||||
// Inline lines do not have margins themselves; however they are
|
||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
*aKeepReflowGoing = PR_FALSE;
|
||||
}
|
||||
lineLayout->EndLineReflow();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
|||
break;
|
||||
}
|
||||
|
||||
lineLayout->EndLineReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
|||
else {
|
||||
prevSibLine->mChildCount++;
|
||||
prevSibLine->MarkDirty();
|
||||
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
}
|
||||
|
||||
aPrevSibling = newFrame;
|
||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
|||
line = next;
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line count");
|
||||
// Make the line that just lost a frame dirty
|
||||
line->MarkDirty();
|
||||
|
||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
|||
}
|
||||
|
||||
void
|
||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder)
|
||||
{
|
||||
// Set the geometric parent of the floater
|
||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
|
||||
// Then add the floater to the current line and place it when
|
||||
// appropriate
|
||||
AddFloater(aPlaceholder, PR_TRUE);
|
||||
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||
}
|
||||
|
||||
// This is called by the line layout's AddFloater method when a
|
||||
|
@ -4671,7 +4772,8 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
|||
// then the floater is place immediately, otherwise the floater
|
||||
// placement is deferred until the line has been reflowed.
|
||||
void
|
||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
nsPlaceholderFrame* aPlaceholder,
|
||||
PRBool aInitialReflow)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Now place the floater immediately if possible. Otherwise stash it
|
||||
// away in mPendingFloaters and place it later.
|
||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
||||
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||
nsRect combinedArea;
|
||||
nsMargin floaterMargins;
|
||||
nsMargin floaterOffsets;
|
||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
|||
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater);
|
||||
|
||||
// Restore coordinate system
|
||||
mSpaceManager->Translate(dx, dy);
|
||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
|||
const nsRect& aDirtyRect,
|
||||
nsFramePaintLayer aWhichLayer)
|
||||
{
|
||||
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef NOISY_DAMAGE_REPAIR
|
||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||
PRInt32 depth = GetDepth();
|
||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||
mBullet, availSize);
|
||||
reflowState.mLineLayout = aState.mLineLayout;
|
||||
nsIHTMLReflow* htmlReflow;
|
||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockFrame::PlaceBullet(nsBlockReflowState& aState)
|
||||
{
|
||||
// First reflow the bullet
|
||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
||||
nsHTMLReflowMetrics metrics(nsnull);
|
||||
ReflowBullet(aState, metrics);
|
||||
if (mLines) {
|
||||
// If we have at least one line then let line-layout position the
|
||||
// bullet (this way the bullet is vertically aligned properly).
|
||||
lineLayout->AddBulletFrame(mBullet, metrics);
|
||||
}
|
||||
else {
|
||||
// There are no lines so we have to fake up some y motion so that
|
||||
// we end up with *some* height.
|
||||
aState.mY += metrics.height;
|
||||
}
|
||||
}
|
||||
|
||||
//XXX get rid of this -- its slow
|
||||
void
|
||||
nsBlockFrame::BuildFloaterList()
|
||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
|||
else {
|
||||
// Remove frame from line and mark the line dirty
|
||||
--line->mChildCount;
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||
line->MarkDirty();
|
||||
firstChild->GetNextSibling(&line->mFirstChild);
|
||||
}
|
||||
|
@ -6158,7 +6244,7 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
|
|||
}
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(line->mChildCount < 10000, "bad line child count");
|
||||
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||
count += line->mChildCount;
|
||||
line = line->mNext;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче