зеркало из https://github.com/mozilla/gecko-dev.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:
Родитель
424e55fe9d
Коммит
e40963e370
|
@ -50,6 +50,8 @@
|
||||||
#include "nsIFocusTracker.h"
|
#include "nsIFocusTracker.h"
|
||||||
#include "nsIFrameSelection.h"
|
#include "nsIFrameSelection.h"
|
||||||
|
|
||||||
|
#define MAX_LINE_COUNT 50000
|
||||||
|
|
||||||
// XXX HTML:P's that are empty yet have style indicating they should
|
// XXX HTML:P's that are empty yet have style indicating they should
|
||||||
// clear floaters - we need to ignore the clear behavior.
|
// clear floaters - we need to ignore the clear behavior.
|
||||||
|
|
||||||
|
@ -203,8 +205,7 @@ public:
|
||||||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics);
|
||||||
nsLineLayout* aLineLayout);
|
|
||||||
|
|
||||||
~nsBlockReflowState();
|
~nsBlockReflowState();
|
||||||
|
|
||||||
|
@ -240,9 +241,11 @@ public:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
void InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame);
|
||||||
|
|
||||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
void AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame,
|
||||||
PRBool aInitialReflow);
|
PRBool aInitialReflow);
|
||||||
|
|
||||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||||
|
@ -302,13 +305,20 @@ public:
|
||||||
nscoord* aTopMarginResult,
|
nscoord* aTopMarginResult,
|
||||||
nscoord* aBottomMarginResult);
|
nscoord* aBottomMarginResult);
|
||||||
|
|
||||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
|
nsRect& aResult);
|
||||||
|
|
||||||
void RecoverStateFrom(nsLineBox* aLine,
|
void RecoverStateFrom(nsLineBox* aLine,
|
||||||
PRBool aApplyTopMargin,
|
PRBool aApplyTopMargin,
|
||||||
nscoord aDeltaY,
|
nscoord aDeltaY,
|
||||||
nsRect* aDamageRect);
|
nsRect* aDamageRect);
|
||||||
|
|
||||||
|
void AdvanceToNextLine() {
|
||||||
|
mLineNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
// This state is the "global" state computed once for the reflow of
|
// This state is the "global" state computed once for the reflow of
|
||||||
|
@ -321,7 +331,7 @@ public:
|
||||||
|
|
||||||
const nsHTMLReflowState& mReflowState;
|
const nsHTMLReflowState& mReflowState;
|
||||||
|
|
||||||
nsLineLayout* mLineLayout;
|
// nsLineLayout* mLineLayout;
|
||||||
|
|
||||||
nsISpaceManager* mSpaceManager;
|
nsISpaceManager* mSpaceManager;
|
||||||
|
|
||||||
|
@ -411,18 +421,22 @@ public:
|
||||||
PRBool mComputeMaxElementSize;
|
PRBool mComputeMaxElementSize;
|
||||||
|
|
||||||
nsSize mMaxElementSize;
|
nsSize mMaxElementSize;
|
||||||
|
|
||||||
|
nscoord mMinLineHeight;
|
||||||
|
|
||||||
|
PRInt32 mLineNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX This is vile. Make it go away
|
// XXX This is vile. Make it go away
|
||||||
void
|
void
|
||||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||||
{
|
{
|
||||||
mBlockRS->InitFloater(aFrame);
|
mBlockRS->InitFloater(*this, aFrame);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
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,
|
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics)
|
||||||
nsLineLayout* aLineLayout)
|
|
||||||
: mBlock(aFrame),
|
: mBlock(aFrame),
|
||||||
mPresContext(aPresContext),
|
mPresContext(aPresContext),
|
||||||
mReflowState(aReflowState),
|
mReflowState(aReflowState),
|
||||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
mIsBottomMarginRoot(PR_FALSE),
|
mIsBottomMarginRoot(PR_FALSE),
|
||||||
mApplyTopMargin(PR_FALSE),
|
mApplyTopMargin(PR_FALSE),
|
||||||
mNextRCFrame(nsnull),
|
mNextRCFrame(nsnull),
|
||||||
mPrevBottomMargin(0)
|
mPrevBottomMargin(0),
|
||||||
|
mLineNumber(0)
|
||||||
{
|
{
|
||||||
mLineLayout = aLineLayout;
|
|
||||||
|
|
||||||
mSpaceManager = aReflowState.mSpaceManager;
|
mSpaceManager = aReflowState.mSpaceManager;
|
||||||
|
|
||||||
// Translate into our content area and then save the
|
// Translate into our content area and then save the
|
||||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||||
mMaxElementSize.SizeTo(0, 0);
|
mMaxElementSize.SizeTo(0, 0);
|
||||||
|
|
||||||
if (0 != borderPadding.top) {
|
if (0 != borderPadding.top) {
|
||||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
if (0 != borderPadding.bottom) {
|
if (0 != borderPadding.bottom) {
|
||||||
mIsBottomMarginRoot = PR_TRUE;
|
mIsBottomMarginRoot = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||||
|
aReflowState.frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsBlockReflowState::~nsBlockReflowState()
|
nsBlockReflowState::~nsBlockReflowState()
|
||||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
||||||
// at the current Y coordinate. This method assumes that
|
// at the current Y coordinate. This method assumes that
|
||||||
// GetAvailableSpace has already been called.
|
// GetAvailableSpace has already been called.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
nsRect& aResult)
|
nsRect& aResult)
|
||||||
{
|
{
|
||||||
nscoord availHeight = mUnconstrainedHeight
|
nscoord availHeight = mUnconstrainedHeight
|
||||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
|
|
||||||
const nsMargin& borderPadding = BorderPadding();
|
const nsMargin& borderPadding = BorderPadding();
|
||||||
nscoord availX, availWidth;
|
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
|
// Frames that know how to do non-rectangular splitting are given
|
||||||
// the entire available space, including space consumed by
|
// the entire available space, including space consumed by
|
||||||
// floaters.
|
// floaters.
|
||||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
availX = mAvailSpaceRect.x + borderPadding.left;
|
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||||
availWidth = mAvailSpaceRect.width;
|
availWidth = mAvailSpaceRect.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
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
|
// Setup reflow state to compute the block childs top and bottom
|
||||||
// margins
|
// margins
|
||||||
nsIFrame* frame = aLine->mFirstChild;
|
nsIFrame* frame = aLine->mFirstChild;
|
||||||
|
nsRect availSpaceRect;
|
||||||
|
const nsStyleDisplay* display;
|
||||||
|
frame->GetStyleData(eStyleStruct_Display,
|
||||||
|
(const nsStyleStruct*&) display);
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpaceRect;
|
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
|
||||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||||
frame, availSpace);
|
frame, availSpace);
|
||||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||||
const nsHTMLReflowState& aReflowState,
|
const nsHTMLReflowState& aReflowState,
|
||||||
nsReflowStatus& aStatus)
|
nsReflowStatus& aStatus)
|
||||||
{
|
{
|
||||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
#ifdef DEBUG_kipp
|
||||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
{
|
||||||
&lineLayout);
|
extern char* nsPresShell_ReflowStackPointerTop;
|
||||||
lineLayout.Init(&state);
|
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) {
|
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||||
state.mIsTopMarginRoot = PR_TRUE;
|
state.mIsTopMarginRoot = PR_TRUE;
|
||||||
state.mIsBottomMarginRoot = PR_TRUE;
|
state.mIsBottomMarginRoot = PR_TRUE;
|
||||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRBool keepGoing = PR_TRUE;
|
PRBool keepGoing = PR_TRUE;
|
||||||
|
|
||||||
// Inform line layout of where the text runs are
|
|
||||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
|
||||||
|
|
||||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||||
nsIReflowCommand::ReflowType type;
|
nsIReflowCommand::ReflowType type;
|
||||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
// If this is an inline frame then its time to stop
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull data from a next-in-flow if we can
|
// 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
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle an odd-ball case: a list-item with no lines
|
// Handle an odd-ball case: a list-item with no lines
|
||||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
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
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
||||||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||||
}
|
}
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (0 != --fromLine->mChildCount) {
|
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
|
// Mark line dirty now that we pulled a child
|
||||||
fromLine->MarkDirty();
|
fromLine->MarkDirty();
|
||||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||||
return PR_FALSE;
|
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*
|
nsIFrame*
|
||||||
nsBlockFrame::GetTopBlockChild()
|
nsBlockFrame::GetTopBlockChild()
|
||||||
{
|
{
|
||||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
||||||
return nsnull;
|
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
|
nsresult
|
||||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpace;
|
nsRect availSpace;
|
||||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||||
|
|
||||||
// Reflow the block into the available space
|
// Reflow the block into the available space
|
||||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
// Do not count the continuation child on the line it used
|
// Do not count the continuation child on the line it used
|
||||||
// to be on
|
// to be on
|
||||||
aLine->mChildCount--;
|
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
|
// 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 -
|
bbox.y = aState.BorderPadding().top + ascent -
|
||||||
metrics.ascent + topMargin;
|
metrics.ascent + topMargin;
|
||||||
mBullet->SetRect(bbox);
|
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 {
|
else {
|
||||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
PRInt32 spins = 0;
|
PRInt32 spins = 0;
|
||||||
#endif
|
#endif
|
||||||
for (;;) {
|
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||||
if (nsnull != aLine->mFloaters) {
|
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||||
// Forget all of the floaters on the line
|
// Prevent overflowing limited thread stacks by creating
|
||||||
aLine->mFloaters->Clear();
|
// nsLineLayout from the heap when the frame tree depth gets
|
||||||
}
|
// large.
|
||||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||||
aState.mPendingFloaters.Clear();
|
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||||
|
&lineReflowStatus);
|
||||||
// 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 {
|
else {
|
||||||
/* XXX get the height right! */
|
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||||
availHeight = aState.mAvailSpaceRect.height;
|
&lineReflowStatus);
|
||||||
}
|
}
|
||||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
if (NS_FAILED(rv)) {
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
#ifdef DEBUG
|
||||||
spins++;
|
spins++;
|
||||||
if (1000 == spins) {
|
if (1000 == spins) {
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||||
NS_ABORT();
|
NS_ABORT();
|
||||||
}
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
#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
|
// If we are propogating out a break-before status then there is
|
||||||
// no point in placing the line.
|
// no point in placing the line.
|
||||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||||
lineLayout->EndLineReflow();
|
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
*aLineReflowStatus = lineReflowStatus;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame,
|
nsIFrame* aFrame,
|
||||||
PRUint8* aLineReflowStatus)
|
PRUint8* aLineReflowStatus)
|
||||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
|
||||||
// If it's currently ok to be reflowing in first-letter style then
|
// 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.
|
// 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
|
#ifdef NOISY_FIRST_LETTER
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": reflowing ");
|
printf(": reflowing ");
|
||||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reflow the inline frame
|
// Reflow the inline frame
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
nsReflowStatus frameReflowStatus;
|
nsReflowStatus frameReflowStatus;
|
||||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||||
frameReflowStatus);
|
frameReflowStatus);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
else {
|
else {
|
||||||
// It's not the first child on this line so go ahead and split
|
// 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.
|
// 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)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line, but after the frame just reflowed
|
// Split line, but after the frame just reflowed
|
||||||
nsIFrame* nextFrame;
|
nsIFrame* nextFrame;
|
||||||
aFrame->GetNextSibling(&nextFrame);
|
aFrame->GetNextSibling(&nextFrame);
|
||||||
rv = SplitLine(aState, aLine, nextFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line after the current frame
|
// Split line after the current frame
|
||||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||||
aFrame->GetNextSibling(&aFrame);
|
aFrame->GetNextSibling(&aFrame);
|
||||||
rv = SplitLine(aState, aLine, aFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
if (nsnull != nextInFlow) {
|
if (nsnull != nextInFlow) {
|
||||||
aMadeNewFrame = PR_TRUE;
|
aMadeNewFrame = PR_TRUE;
|
||||||
aLine->mChildCount++;
|
aLine->mChildCount++;
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_FALSE);
|
VerifyLines(PR_FALSE);
|
||||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame)
|
nsIFrame* aFrame)
|
||||||
{
|
{
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
|
||||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||||
//aLine->List(stdout, 0);
|
//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
|
// Let line layout know that some frames are no longer part of its
|
||||||
// state.
|
// state.
|
||||||
if (!aLine->IsBlock()) {
|
if (!aLine->IsBlock()) {
|
||||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_TRUE);
|
VerifyLines(PR_TRUE);
|
||||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepReflowGoing)
|
PRBool* aKeepReflowGoing)
|
||||||
{
|
{
|
||||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
// method is used for placing a line of inline frames. If the rare
|
// 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
|
// case is happening then the worst that will happen is that the
|
||||||
// bullet frame will be reflowed twice.
|
// bullet frame will be reflowed twice.
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
PRBool addedBullet = PR_FALSE;
|
PRBool addedBullet = PR_FALSE;
|
||||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||||
PlaceBullet(aState);
|
nsHTMLReflowMetrics metrics(nsnull);
|
||||||
|
ReflowBullet(aState, metrics);
|
||||||
|
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||||
addedBullet = PR_TRUE;
|
addedBullet = PR_TRUE;
|
||||||
}
|
}
|
||||||
nsSize maxElementSize;
|
nsSize maxElementSize;
|
||||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
static nscoord lastHeight = 0;
|
static nscoord lastHeight = 0;
|
||||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
#else
|
#else
|
||||||
PRBool allowJustify = PR_FALSE;
|
PRBool allowJustify = PR_FALSE;
|
||||||
#endif
|
#endif
|
||||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||||
if (addedBullet) {
|
if (addedBullet) {
|
||||||
lineLayout->RemoveBulletFrame(mBullet);
|
aLineLayout.RemoveBulletFrame(mBullet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline lines do not have margins themselves; however they are
|
// Inline lines do not have margins themselves; however they are
|
||||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||||
*aKeepReflowGoing = PR_FALSE;
|
*aKeepReflowGoing = PR_FALSE;
|
||||||
}
|
}
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
||||||
else {
|
else {
|
||||||
prevSibLine->mChildCount++;
|
prevSibLine->mChildCount++;
|
||||||
prevSibLine->MarkDirty();
|
prevSibLine->MarkDirty();
|
||||||
|
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
|
|
||||||
aPrevSibling = newFrame;
|
aPrevSibling = newFrame;
|
||||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||||
line = next;
|
line = next;
|
||||||
}
|
}
|
||||||
else {
|
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
|
// Make the line that just lost a frame dirty
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
|
|
||||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder)
|
||||||
{
|
{
|
||||||
// Set the geometric parent of the floater
|
// Set the geometric parent of the floater
|
||||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||||
|
|
||||||
// Then add the floater to the current line and place it when
|
// Then add the floater to the current line and place it when
|
||||||
// appropriate
|
// appropriate
|
||||||
AddFloater(aPlaceholder, PR_TRUE);
|
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called by the line layout's AddFloater method when a
|
// 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
|
// then the floater is place immediately, otherwise the floater
|
||||||
// placement is deferred until the line has been reflowed.
|
// placement is deferred until the line has been reflowed.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder,
|
||||||
PRBool aInitialReflow)
|
PRBool aInitialReflow)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Now place the floater immediately if possible. Otherwise stash it
|
// Now place the floater immediately if possible. Otherwise stash it
|
||||||
// away in mPendingFloaters and place it later.
|
// away in mPendingFloaters and place it later.
|
||||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||||
nsRect combinedArea;
|
nsRect combinedArea;
|
||||||
nsMargin floaterMargins;
|
nsMargin floaterMargins;
|
||||||
nsMargin floaterOffsets;
|
nsMargin floaterOffsets;
|
||||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Pass on updated available space to the current inline reflow engine
|
// Pass on updated available space to the current inline reflow engine
|
||||||
GetAvailableSpace();
|
GetAvailableSpace();
|
||||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||||
mAvailSpaceRect.width,
|
mAvailSpaceRect.width,
|
||||||
mAvailSpaceRect.height,
|
mAvailSpaceRect.height,
|
||||||
isLeftFloater);
|
isLeftFloater);
|
||||||
|
|
||||||
// Restore coordinate system
|
// Restore coordinate system
|
||||||
mSpaceManager->Translate(dx, dy);
|
mSpaceManager->Translate(dx, dy);
|
||||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
||||||
const nsRect& aDirtyRect,
|
const nsRect& aDirtyRect,
|
||||||
nsFramePaintLayer aWhichLayer)
|
nsFramePaintLayer aWhichLayer)
|
||||||
{
|
{
|
||||||
|
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NOISY_DAMAGE_REPAIR
|
#ifdef NOISY_DAMAGE_REPAIR
|
||||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||||
PRInt32 depth = GetDepth();
|
PRInt32 depth = GetDepth();
|
||||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||||
mBullet, availSize);
|
mBullet, availSize);
|
||||||
reflowState.mLineLayout = aState.mLineLayout;
|
|
||||||
nsIHTMLReflow* htmlReflow;
|
nsIHTMLReflow* htmlReflow;
|
||||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
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
|
//XXX get rid of this -- its slow
|
||||||
void
|
void
|
||||||
nsBlockFrame::BuildFloaterList()
|
nsBlockFrame::BuildFloaterList()
|
||||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
||||||
else {
|
else {
|
||||||
// Remove frame from line and mark the line dirty
|
// Remove frame from line and mark the line dirty
|
||||||
--line->mChildCount;
|
--line->mChildCount;
|
||||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
firstChild->GetNextSibling(&line->mFirstChild);
|
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;
|
count += line->mChildCount;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,7 @@ protected:
|
||||||
PRBool aKeepReflowGoing);
|
PRBool aKeepReflowGoing);
|
||||||
|
|
||||||
nsresult PlaceLine(nsBlockReflowState& aState,
|
nsresult PlaceLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepReflowGoing);
|
PRBool* aKeepReflowGoing);
|
||||||
|
|
||||||
|
@ -258,7 +259,24 @@ protected:
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepLineGoing);
|
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,
|
nsresult ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame,
|
nsIFrame* aFrame,
|
||||||
PRUint8* aLineReflowStatus);
|
PRUint8* aLineReflowStatus);
|
||||||
|
@ -278,6 +296,7 @@ protected:
|
||||||
PRBool& aMadeNewFrame);
|
PRBool& aMadeNewFrame);
|
||||||
|
|
||||||
nsresult SplitLine(nsBlockReflowState& aState,
|
nsresult SplitLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame);
|
nsIFrame* aFrame);
|
||||||
|
|
||||||
|
@ -332,8 +351,6 @@ protected:
|
||||||
void ReflowBullet(nsBlockReflowState& aState,
|
void ReflowBullet(nsBlockReflowState& aState,
|
||||||
nsHTMLReflowMetrics& aMetrics);
|
nsHTMLReflowMetrics& aMetrics);
|
||||||
|
|
||||||
void PlaceBullet(nsBlockReflowState& aState);
|
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
nsIFrame* LastChild();
|
nsIFrame* LastChild();
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
#include "nsIFocusTracker.h"
|
#include "nsIFocusTracker.h"
|
||||||
#include "nsIFrameSelection.h"
|
#include "nsIFrameSelection.h"
|
||||||
|
|
||||||
|
#define MAX_LINE_COUNT 50000
|
||||||
|
|
||||||
// XXX HTML:P's that are empty yet have style indicating they should
|
// XXX HTML:P's that are empty yet have style indicating they should
|
||||||
// clear floaters - we need to ignore the clear behavior.
|
// clear floaters - we need to ignore the clear behavior.
|
||||||
|
|
||||||
|
@ -203,8 +205,7 @@ public:
|
||||||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics);
|
||||||
nsLineLayout* aLineLayout);
|
|
||||||
|
|
||||||
~nsBlockReflowState();
|
~nsBlockReflowState();
|
||||||
|
|
||||||
|
@ -240,9 +241,11 @@ public:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
void InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame);
|
||||||
|
|
||||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
void AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame,
|
||||||
PRBool aInitialReflow);
|
PRBool aInitialReflow);
|
||||||
|
|
||||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||||
|
@ -302,13 +305,20 @@ public:
|
||||||
nscoord* aTopMarginResult,
|
nscoord* aTopMarginResult,
|
||||||
nscoord* aBottomMarginResult);
|
nscoord* aBottomMarginResult);
|
||||||
|
|
||||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
|
nsRect& aResult);
|
||||||
|
|
||||||
void RecoverStateFrom(nsLineBox* aLine,
|
void RecoverStateFrom(nsLineBox* aLine,
|
||||||
PRBool aApplyTopMargin,
|
PRBool aApplyTopMargin,
|
||||||
nscoord aDeltaY,
|
nscoord aDeltaY,
|
||||||
nsRect* aDamageRect);
|
nsRect* aDamageRect);
|
||||||
|
|
||||||
|
void AdvanceToNextLine() {
|
||||||
|
mLineNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
// This state is the "global" state computed once for the reflow of
|
// This state is the "global" state computed once for the reflow of
|
||||||
|
@ -321,7 +331,7 @@ public:
|
||||||
|
|
||||||
const nsHTMLReflowState& mReflowState;
|
const nsHTMLReflowState& mReflowState;
|
||||||
|
|
||||||
nsLineLayout* mLineLayout;
|
// nsLineLayout* mLineLayout;
|
||||||
|
|
||||||
nsISpaceManager* mSpaceManager;
|
nsISpaceManager* mSpaceManager;
|
||||||
|
|
||||||
|
@ -411,18 +421,22 @@ public:
|
||||||
PRBool mComputeMaxElementSize;
|
PRBool mComputeMaxElementSize;
|
||||||
|
|
||||||
nsSize mMaxElementSize;
|
nsSize mMaxElementSize;
|
||||||
|
|
||||||
|
nscoord mMinLineHeight;
|
||||||
|
|
||||||
|
PRInt32 mLineNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX This is vile. Make it go away
|
// XXX This is vile. Make it go away
|
||||||
void
|
void
|
||||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||||
{
|
{
|
||||||
mBlockRS->InitFloater(aFrame);
|
mBlockRS->InitFloater(*this, aFrame);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
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,
|
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics)
|
||||||
nsLineLayout* aLineLayout)
|
|
||||||
: mBlock(aFrame),
|
: mBlock(aFrame),
|
||||||
mPresContext(aPresContext),
|
mPresContext(aPresContext),
|
||||||
mReflowState(aReflowState),
|
mReflowState(aReflowState),
|
||||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
mIsBottomMarginRoot(PR_FALSE),
|
mIsBottomMarginRoot(PR_FALSE),
|
||||||
mApplyTopMargin(PR_FALSE),
|
mApplyTopMargin(PR_FALSE),
|
||||||
mNextRCFrame(nsnull),
|
mNextRCFrame(nsnull),
|
||||||
mPrevBottomMargin(0)
|
mPrevBottomMargin(0),
|
||||||
|
mLineNumber(0)
|
||||||
{
|
{
|
||||||
mLineLayout = aLineLayout;
|
|
||||||
|
|
||||||
mSpaceManager = aReflowState.mSpaceManager;
|
mSpaceManager = aReflowState.mSpaceManager;
|
||||||
|
|
||||||
// Translate into our content area and then save the
|
// Translate into our content area and then save the
|
||||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||||
mMaxElementSize.SizeTo(0, 0);
|
mMaxElementSize.SizeTo(0, 0);
|
||||||
|
|
||||||
if (0 != borderPadding.top) {
|
if (0 != borderPadding.top) {
|
||||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
if (0 != borderPadding.bottom) {
|
if (0 != borderPadding.bottom) {
|
||||||
mIsBottomMarginRoot = PR_TRUE;
|
mIsBottomMarginRoot = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||||
|
aReflowState.frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsBlockReflowState::~nsBlockReflowState()
|
nsBlockReflowState::~nsBlockReflowState()
|
||||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
||||||
// at the current Y coordinate. This method assumes that
|
// at the current Y coordinate. This method assumes that
|
||||||
// GetAvailableSpace has already been called.
|
// GetAvailableSpace has already been called.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
nsRect& aResult)
|
nsRect& aResult)
|
||||||
{
|
{
|
||||||
nscoord availHeight = mUnconstrainedHeight
|
nscoord availHeight = mUnconstrainedHeight
|
||||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
|
|
||||||
const nsMargin& borderPadding = BorderPadding();
|
const nsMargin& borderPadding = BorderPadding();
|
||||||
nscoord availX, availWidth;
|
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
|
// Frames that know how to do non-rectangular splitting are given
|
||||||
// the entire available space, including space consumed by
|
// the entire available space, including space consumed by
|
||||||
// floaters.
|
// floaters.
|
||||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
availX = mAvailSpaceRect.x + borderPadding.left;
|
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||||
availWidth = mAvailSpaceRect.width;
|
availWidth = mAvailSpaceRect.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
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
|
// Setup reflow state to compute the block childs top and bottom
|
||||||
// margins
|
// margins
|
||||||
nsIFrame* frame = aLine->mFirstChild;
|
nsIFrame* frame = aLine->mFirstChild;
|
||||||
|
nsRect availSpaceRect;
|
||||||
|
const nsStyleDisplay* display;
|
||||||
|
frame->GetStyleData(eStyleStruct_Display,
|
||||||
|
(const nsStyleStruct*&) display);
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpaceRect;
|
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
|
||||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||||
frame, availSpace);
|
frame, availSpace);
|
||||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||||
const nsHTMLReflowState& aReflowState,
|
const nsHTMLReflowState& aReflowState,
|
||||||
nsReflowStatus& aStatus)
|
nsReflowStatus& aStatus)
|
||||||
{
|
{
|
||||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
#ifdef DEBUG_kipp
|
||||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
{
|
||||||
&lineLayout);
|
extern char* nsPresShell_ReflowStackPointerTop;
|
||||||
lineLayout.Init(&state);
|
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) {
|
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||||
state.mIsTopMarginRoot = PR_TRUE;
|
state.mIsTopMarginRoot = PR_TRUE;
|
||||||
state.mIsBottomMarginRoot = PR_TRUE;
|
state.mIsBottomMarginRoot = PR_TRUE;
|
||||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRBool keepGoing = PR_TRUE;
|
PRBool keepGoing = PR_TRUE;
|
||||||
|
|
||||||
// Inform line layout of where the text runs are
|
|
||||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
|
||||||
|
|
||||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||||
nsIReflowCommand::ReflowType type;
|
nsIReflowCommand::ReflowType type;
|
||||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
// If this is an inline frame then its time to stop
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull data from a next-in-flow if we can
|
// 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
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle an odd-ball case: a list-item with no lines
|
// Handle an odd-ball case: a list-item with no lines
|
||||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
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
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
||||||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||||
}
|
}
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (0 != --fromLine->mChildCount) {
|
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
|
// Mark line dirty now that we pulled a child
|
||||||
fromLine->MarkDirty();
|
fromLine->MarkDirty();
|
||||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||||
return PR_FALSE;
|
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*
|
nsIFrame*
|
||||||
nsBlockFrame::GetTopBlockChild()
|
nsBlockFrame::GetTopBlockChild()
|
||||||
{
|
{
|
||||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
||||||
return nsnull;
|
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
|
nsresult
|
||||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpace;
|
nsRect availSpace;
|
||||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||||
|
|
||||||
// Reflow the block into the available space
|
// Reflow the block into the available space
|
||||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
// Do not count the continuation child on the line it used
|
// Do not count the continuation child on the line it used
|
||||||
// to be on
|
// to be on
|
||||||
aLine->mChildCount--;
|
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
|
// 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 -
|
bbox.y = aState.BorderPadding().top + ascent -
|
||||||
metrics.ascent + topMargin;
|
metrics.ascent + topMargin;
|
||||||
mBullet->SetRect(bbox);
|
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 {
|
else {
|
||||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
PRInt32 spins = 0;
|
PRInt32 spins = 0;
|
||||||
#endif
|
#endif
|
||||||
for (;;) {
|
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||||
if (nsnull != aLine->mFloaters) {
|
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||||
// Forget all of the floaters on the line
|
// Prevent overflowing limited thread stacks by creating
|
||||||
aLine->mFloaters->Clear();
|
// nsLineLayout from the heap when the frame tree depth gets
|
||||||
}
|
// large.
|
||||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||||
aState.mPendingFloaters.Clear();
|
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||||
|
&lineReflowStatus);
|
||||||
// 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 {
|
else {
|
||||||
/* XXX get the height right! */
|
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||||
availHeight = aState.mAvailSpaceRect.height;
|
&lineReflowStatus);
|
||||||
}
|
}
|
||||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
if (NS_FAILED(rv)) {
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
#ifdef DEBUG
|
||||||
spins++;
|
spins++;
|
||||||
if (1000 == spins) {
|
if (1000 == spins) {
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||||
NS_ABORT();
|
NS_ABORT();
|
||||||
}
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
#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
|
// If we are propogating out a break-before status then there is
|
||||||
// no point in placing the line.
|
// no point in placing the line.
|
||||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||||
lineLayout->EndLineReflow();
|
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
*aLineReflowStatus = lineReflowStatus;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame,
|
nsIFrame* aFrame,
|
||||||
PRUint8* aLineReflowStatus)
|
PRUint8* aLineReflowStatus)
|
||||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
|
||||||
// If it's currently ok to be reflowing in first-letter style then
|
// 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.
|
// 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
|
#ifdef NOISY_FIRST_LETTER
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": reflowing ");
|
printf(": reflowing ");
|
||||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reflow the inline frame
|
// Reflow the inline frame
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
nsReflowStatus frameReflowStatus;
|
nsReflowStatus frameReflowStatus;
|
||||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||||
frameReflowStatus);
|
frameReflowStatus);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
else {
|
else {
|
||||||
// It's not the first child on this line so go ahead and split
|
// 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.
|
// 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)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line, but after the frame just reflowed
|
// Split line, but after the frame just reflowed
|
||||||
nsIFrame* nextFrame;
|
nsIFrame* nextFrame;
|
||||||
aFrame->GetNextSibling(&nextFrame);
|
aFrame->GetNextSibling(&nextFrame);
|
||||||
rv = SplitLine(aState, aLine, nextFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line after the current frame
|
// Split line after the current frame
|
||||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||||
aFrame->GetNextSibling(&aFrame);
|
aFrame->GetNextSibling(&aFrame);
|
||||||
rv = SplitLine(aState, aLine, aFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
if (nsnull != nextInFlow) {
|
if (nsnull != nextInFlow) {
|
||||||
aMadeNewFrame = PR_TRUE;
|
aMadeNewFrame = PR_TRUE;
|
||||||
aLine->mChildCount++;
|
aLine->mChildCount++;
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_FALSE);
|
VerifyLines(PR_FALSE);
|
||||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame)
|
nsIFrame* aFrame)
|
||||||
{
|
{
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
|
||||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||||
//aLine->List(stdout, 0);
|
//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
|
// Let line layout know that some frames are no longer part of its
|
||||||
// state.
|
// state.
|
||||||
if (!aLine->IsBlock()) {
|
if (!aLine->IsBlock()) {
|
||||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_TRUE);
|
VerifyLines(PR_TRUE);
|
||||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepReflowGoing)
|
PRBool* aKeepReflowGoing)
|
||||||
{
|
{
|
||||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
// method is used for placing a line of inline frames. If the rare
|
// 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
|
// case is happening then the worst that will happen is that the
|
||||||
// bullet frame will be reflowed twice.
|
// bullet frame will be reflowed twice.
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
PRBool addedBullet = PR_FALSE;
|
PRBool addedBullet = PR_FALSE;
|
||||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||||
PlaceBullet(aState);
|
nsHTMLReflowMetrics metrics(nsnull);
|
||||||
|
ReflowBullet(aState, metrics);
|
||||||
|
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||||
addedBullet = PR_TRUE;
|
addedBullet = PR_TRUE;
|
||||||
}
|
}
|
||||||
nsSize maxElementSize;
|
nsSize maxElementSize;
|
||||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
static nscoord lastHeight = 0;
|
static nscoord lastHeight = 0;
|
||||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
#else
|
#else
|
||||||
PRBool allowJustify = PR_FALSE;
|
PRBool allowJustify = PR_FALSE;
|
||||||
#endif
|
#endif
|
||||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||||
if (addedBullet) {
|
if (addedBullet) {
|
||||||
lineLayout->RemoveBulletFrame(mBullet);
|
aLineLayout.RemoveBulletFrame(mBullet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline lines do not have margins themselves; however they are
|
// Inline lines do not have margins themselves; however they are
|
||||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||||
*aKeepReflowGoing = PR_FALSE;
|
*aKeepReflowGoing = PR_FALSE;
|
||||||
}
|
}
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
||||||
else {
|
else {
|
||||||
prevSibLine->mChildCount++;
|
prevSibLine->mChildCount++;
|
||||||
prevSibLine->MarkDirty();
|
prevSibLine->MarkDirty();
|
||||||
|
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
|
|
||||||
aPrevSibling = newFrame;
|
aPrevSibling = newFrame;
|
||||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||||
line = next;
|
line = next;
|
||||||
}
|
}
|
||||||
else {
|
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
|
// Make the line that just lost a frame dirty
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
|
|
||||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder)
|
||||||
{
|
{
|
||||||
// Set the geometric parent of the floater
|
// Set the geometric parent of the floater
|
||||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||||
|
|
||||||
// Then add the floater to the current line and place it when
|
// Then add the floater to the current line and place it when
|
||||||
// appropriate
|
// appropriate
|
||||||
AddFloater(aPlaceholder, PR_TRUE);
|
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called by the line layout's AddFloater method when a
|
// 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
|
// then the floater is place immediately, otherwise the floater
|
||||||
// placement is deferred until the line has been reflowed.
|
// placement is deferred until the line has been reflowed.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder,
|
||||||
PRBool aInitialReflow)
|
PRBool aInitialReflow)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Now place the floater immediately if possible. Otherwise stash it
|
// Now place the floater immediately if possible. Otherwise stash it
|
||||||
// away in mPendingFloaters and place it later.
|
// away in mPendingFloaters and place it later.
|
||||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||||
nsRect combinedArea;
|
nsRect combinedArea;
|
||||||
nsMargin floaterMargins;
|
nsMargin floaterMargins;
|
||||||
nsMargin floaterOffsets;
|
nsMargin floaterOffsets;
|
||||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Pass on updated available space to the current inline reflow engine
|
// Pass on updated available space to the current inline reflow engine
|
||||||
GetAvailableSpace();
|
GetAvailableSpace();
|
||||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||||
mAvailSpaceRect.width,
|
mAvailSpaceRect.width,
|
||||||
mAvailSpaceRect.height,
|
mAvailSpaceRect.height,
|
||||||
isLeftFloater);
|
isLeftFloater);
|
||||||
|
|
||||||
// Restore coordinate system
|
// Restore coordinate system
|
||||||
mSpaceManager->Translate(dx, dy);
|
mSpaceManager->Translate(dx, dy);
|
||||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
||||||
const nsRect& aDirtyRect,
|
const nsRect& aDirtyRect,
|
||||||
nsFramePaintLayer aWhichLayer)
|
nsFramePaintLayer aWhichLayer)
|
||||||
{
|
{
|
||||||
|
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NOISY_DAMAGE_REPAIR
|
#ifdef NOISY_DAMAGE_REPAIR
|
||||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||||
PRInt32 depth = GetDepth();
|
PRInt32 depth = GetDepth();
|
||||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||||
mBullet, availSize);
|
mBullet, availSize);
|
||||||
reflowState.mLineLayout = aState.mLineLayout;
|
|
||||||
nsIHTMLReflow* htmlReflow;
|
nsIHTMLReflow* htmlReflow;
|
||||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
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
|
//XXX get rid of this -- its slow
|
||||||
void
|
void
|
||||||
nsBlockFrame::BuildFloaterList()
|
nsBlockFrame::BuildFloaterList()
|
||||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
||||||
else {
|
else {
|
||||||
// Remove frame from line and mark the line dirty
|
// Remove frame from line and mark the line dirty
|
||||||
--line->mChildCount;
|
--line->mChildCount;
|
||||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
firstChild->GetNextSibling(&line->mFirstChild);
|
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;
|
count += line->mChildCount;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
#include "nsIFocusTracker.h"
|
#include "nsIFocusTracker.h"
|
||||||
#include "nsIFrameSelection.h"
|
#include "nsIFrameSelection.h"
|
||||||
|
|
||||||
|
#define MAX_LINE_COUNT 50000
|
||||||
|
|
||||||
// XXX HTML:P's that are empty yet have style indicating they should
|
// XXX HTML:P's that are empty yet have style indicating they should
|
||||||
// clear floaters - we need to ignore the clear behavior.
|
// clear floaters - we need to ignore the clear behavior.
|
||||||
|
|
||||||
|
@ -203,8 +205,7 @@ public:
|
||||||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics);
|
||||||
nsLineLayout* aLineLayout);
|
|
||||||
|
|
||||||
~nsBlockReflowState();
|
~nsBlockReflowState();
|
||||||
|
|
||||||
|
@ -240,9 +241,11 @@ public:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
void InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame);
|
||||||
|
|
||||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
void AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame,
|
||||||
PRBool aInitialReflow);
|
PRBool aInitialReflow);
|
||||||
|
|
||||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||||
|
@ -302,13 +305,20 @@ public:
|
||||||
nscoord* aTopMarginResult,
|
nscoord* aTopMarginResult,
|
||||||
nscoord* aBottomMarginResult);
|
nscoord* aBottomMarginResult);
|
||||||
|
|
||||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
|
nsRect& aResult);
|
||||||
|
|
||||||
void RecoverStateFrom(nsLineBox* aLine,
|
void RecoverStateFrom(nsLineBox* aLine,
|
||||||
PRBool aApplyTopMargin,
|
PRBool aApplyTopMargin,
|
||||||
nscoord aDeltaY,
|
nscoord aDeltaY,
|
||||||
nsRect* aDamageRect);
|
nsRect* aDamageRect);
|
||||||
|
|
||||||
|
void AdvanceToNextLine() {
|
||||||
|
mLineNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
// This state is the "global" state computed once for the reflow of
|
// This state is the "global" state computed once for the reflow of
|
||||||
|
@ -321,7 +331,7 @@ public:
|
||||||
|
|
||||||
const nsHTMLReflowState& mReflowState;
|
const nsHTMLReflowState& mReflowState;
|
||||||
|
|
||||||
nsLineLayout* mLineLayout;
|
// nsLineLayout* mLineLayout;
|
||||||
|
|
||||||
nsISpaceManager* mSpaceManager;
|
nsISpaceManager* mSpaceManager;
|
||||||
|
|
||||||
|
@ -411,18 +421,22 @@ public:
|
||||||
PRBool mComputeMaxElementSize;
|
PRBool mComputeMaxElementSize;
|
||||||
|
|
||||||
nsSize mMaxElementSize;
|
nsSize mMaxElementSize;
|
||||||
|
|
||||||
|
nscoord mMinLineHeight;
|
||||||
|
|
||||||
|
PRInt32 mLineNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX This is vile. Make it go away
|
// XXX This is vile. Make it go away
|
||||||
void
|
void
|
||||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||||
{
|
{
|
||||||
mBlockRS->InitFloater(aFrame);
|
mBlockRS->InitFloater(*this, aFrame);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
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,
|
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics)
|
||||||
nsLineLayout* aLineLayout)
|
|
||||||
: mBlock(aFrame),
|
: mBlock(aFrame),
|
||||||
mPresContext(aPresContext),
|
mPresContext(aPresContext),
|
||||||
mReflowState(aReflowState),
|
mReflowState(aReflowState),
|
||||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
mIsBottomMarginRoot(PR_FALSE),
|
mIsBottomMarginRoot(PR_FALSE),
|
||||||
mApplyTopMargin(PR_FALSE),
|
mApplyTopMargin(PR_FALSE),
|
||||||
mNextRCFrame(nsnull),
|
mNextRCFrame(nsnull),
|
||||||
mPrevBottomMargin(0)
|
mPrevBottomMargin(0),
|
||||||
|
mLineNumber(0)
|
||||||
{
|
{
|
||||||
mLineLayout = aLineLayout;
|
|
||||||
|
|
||||||
mSpaceManager = aReflowState.mSpaceManager;
|
mSpaceManager = aReflowState.mSpaceManager;
|
||||||
|
|
||||||
// Translate into our content area and then save the
|
// Translate into our content area and then save the
|
||||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||||
mMaxElementSize.SizeTo(0, 0);
|
mMaxElementSize.SizeTo(0, 0);
|
||||||
|
|
||||||
if (0 != borderPadding.top) {
|
if (0 != borderPadding.top) {
|
||||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
if (0 != borderPadding.bottom) {
|
if (0 != borderPadding.bottom) {
|
||||||
mIsBottomMarginRoot = PR_TRUE;
|
mIsBottomMarginRoot = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||||
|
aReflowState.frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsBlockReflowState::~nsBlockReflowState()
|
nsBlockReflowState::~nsBlockReflowState()
|
||||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
||||||
// at the current Y coordinate. This method assumes that
|
// at the current Y coordinate. This method assumes that
|
||||||
// GetAvailableSpace has already been called.
|
// GetAvailableSpace has already been called.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
nsRect& aResult)
|
nsRect& aResult)
|
||||||
{
|
{
|
||||||
nscoord availHeight = mUnconstrainedHeight
|
nscoord availHeight = mUnconstrainedHeight
|
||||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
|
|
||||||
const nsMargin& borderPadding = BorderPadding();
|
const nsMargin& borderPadding = BorderPadding();
|
||||||
nscoord availX, availWidth;
|
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
|
// Frames that know how to do non-rectangular splitting are given
|
||||||
// the entire available space, including space consumed by
|
// the entire available space, including space consumed by
|
||||||
// floaters.
|
// floaters.
|
||||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
availX = mAvailSpaceRect.x + borderPadding.left;
|
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||||
availWidth = mAvailSpaceRect.width;
|
availWidth = mAvailSpaceRect.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
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
|
// Setup reflow state to compute the block childs top and bottom
|
||||||
// margins
|
// margins
|
||||||
nsIFrame* frame = aLine->mFirstChild;
|
nsIFrame* frame = aLine->mFirstChild;
|
||||||
|
nsRect availSpaceRect;
|
||||||
|
const nsStyleDisplay* display;
|
||||||
|
frame->GetStyleData(eStyleStruct_Display,
|
||||||
|
(const nsStyleStruct*&) display);
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpaceRect;
|
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
|
||||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||||
frame, availSpace);
|
frame, availSpace);
|
||||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||||
const nsHTMLReflowState& aReflowState,
|
const nsHTMLReflowState& aReflowState,
|
||||||
nsReflowStatus& aStatus)
|
nsReflowStatus& aStatus)
|
||||||
{
|
{
|
||||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
#ifdef DEBUG_kipp
|
||||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
{
|
||||||
&lineLayout);
|
extern char* nsPresShell_ReflowStackPointerTop;
|
||||||
lineLayout.Init(&state);
|
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) {
|
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||||
state.mIsTopMarginRoot = PR_TRUE;
|
state.mIsTopMarginRoot = PR_TRUE;
|
||||||
state.mIsBottomMarginRoot = PR_TRUE;
|
state.mIsBottomMarginRoot = PR_TRUE;
|
||||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRBool keepGoing = PR_TRUE;
|
PRBool keepGoing = PR_TRUE;
|
||||||
|
|
||||||
// Inform line layout of where the text runs are
|
|
||||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
|
||||||
|
|
||||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||||
nsIReflowCommand::ReflowType type;
|
nsIReflowCommand::ReflowType type;
|
||||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
// If this is an inline frame then its time to stop
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull data from a next-in-flow if we can
|
// 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
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle an odd-ball case: a list-item with no lines
|
// Handle an odd-ball case: a list-item with no lines
|
||||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
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
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
||||||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||||
}
|
}
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (0 != --fromLine->mChildCount) {
|
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
|
// Mark line dirty now that we pulled a child
|
||||||
fromLine->MarkDirty();
|
fromLine->MarkDirty();
|
||||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||||
return PR_FALSE;
|
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*
|
nsIFrame*
|
||||||
nsBlockFrame::GetTopBlockChild()
|
nsBlockFrame::GetTopBlockChild()
|
||||||
{
|
{
|
||||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
||||||
return nsnull;
|
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
|
nsresult
|
||||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpace;
|
nsRect availSpace;
|
||||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||||
|
|
||||||
// Reflow the block into the available space
|
// Reflow the block into the available space
|
||||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
// Do not count the continuation child on the line it used
|
// Do not count the continuation child on the line it used
|
||||||
// to be on
|
// to be on
|
||||||
aLine->mChildCount--;
|
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
|
// 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 -
|
bbox.y = aState.BorderPadding().top + ascent -
|
||||||
metrics.ascent + topMargin;
|
metrics.ascent + topMargin;
|
||||||
mBullet->SetRect(bbox);
|
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 {
|
else {
|
||||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
PRInt32 spins = 0;
|
PRInt32 spins = 0;
|
||||||
#endif
|
#endif
|
||||||
for (;;) {
|
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||||
if (nsnull != aLine->mFloaters) {
|
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||||
// Forget all of the floaters on the line
|
// Prevent overflowing limited thread stacks by creating
|
||||||
aLine->mFloaters->Clear();
|
// nsLineLayout from the heap when the frame tree depth gets
|
||||||
}
|
// large.
|
||||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||||
aState.mPendingFloaters.Clear();
|
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||||
|
&lineReflowStatus);
|
||||||
// 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 {
|
else {
|
||||||
/* XXX get the height right! */
|
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||||
availHeight = aState.mAvailSpaceRect.height;
|
&lineReflowStatus);
|
||||||
}
|
}
|
||||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
if (NS_FAILED(rv)) {
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
#ifdef DEBUG
|
||||||
spins++;
|
spins++;
|
||||||
if (1000 == spins) {
|
if (1000 == spins) {
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||||
NS_ABORT();
|
NS_ABORT();
|
||||||
}
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
#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
|
// If we are propogating out a break-before status then there is
|
||||||
// no point in placing the line.
|
// no point in placing the line.
|
||||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||||
lineLayout->EndLineReflow();
|
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
*aLineReflowStatus = lineReflowStatus;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame,
|
nsIFrame* aFrame,
|
||||||
PRUint8* aLineReflowStatus)
|
PRUint8* aLineReflowStatus)
|
||||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
|
||||||
// If it's currently ok to be reflowing in first-letter style then
|
// 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.
|
// 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
|
#ifdef NOISY_FIRST_LETTER
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": reflowing ");
|
printf(": reflowing ");
|
||||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reflow the inline frame
|
// Reflow the inline frame
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
nsReflowStatus frameReflowStatus;
|
nsReflowStatus frameReflowStatus;
|
||||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||||
frameReflowStatus);
|
frameReflowStatus);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
else {
|
else {
|
||||||
// It's not the first child on this line so go ahead and split
|
// 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.
|
// 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)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line, but after the frame just reflowed
|
// Split line, but after the frame just reflowed
|
||||||
nsIFrame* nextFrame;
|
nsIFrame* nextFrame;
|
||||||
aFrame->GetNextSibling(&nextFrame);
|
aFrame->GetNextSibling(&nextFrame);
|
||||||
rv = SplitLine(aState, aLine, nextFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line after the current frame
|
// Split line after the current frame
|
||||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||||
aFrame->GetNextSibling(&aFrame);
|
aFrame->GetNextSibling(&aFrame);
|
||||||
rv = SplitLine(aState, aLine, aFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
if (nsnull != nextInFlow) {
|
if (nsnull != nextInFlow) {
|
||||||
aMadeNewFrame = PR_TRUE;
|
aMadeNewFrame = PR_TRUE;
|
||||||
aLine->mChildCount++;
|
aLine->mChildCount++;
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_FALSE);
|
VerifyLines(PR_FALSE);
|
||||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame)
|
nsIFrame* aFrame)
|
||||||
{
|
{
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
|
||||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||||
//aLine->List(stdout, 0);
|
//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
|
// Let line layout know that some frames are no longer part of its
|
||||||
// state.
|
// state.
|
||||||
if (!aLine->IsBlock()) {
|
if (!aLine->IsBlock()) {
|
||||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_TRUE);
|
VerifyLines(PR_TRUE);
|
||||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepReflowGoing)
|
PRBool* aKeepReflowGoing)
|
||||||
{
|
{
|
||||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
// method is used for placing a line of inline frames. If the rare
|
// 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
|
// case is happening then the worst that will happen is that the
|
||||||
// bullet frame will be reflowed twice.
|
// bullet frame will be reflowed twice.
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
PRBool addedBullet = PR_FALSE;
|
PRBool addedBullet = PR_FALSE;
|
||||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||||
PlaceBullet(aState);
|
nsHTMLReflowMetrics metrics(nsnull);
|
||||||
|
ReflowBullet(aState, metrics);
|
||||||
|
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||||
addedBullet = PR_TRUE;
|
addedBullet = PR_TRUE;
|
||||||
}
|
}
|
||||||
nsSize maxElementSize;
|
nsSize maxElementSize;
|
||||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
static nscoord lastHeight = 0;
|
static nscoord lastHeight = 0;
|
||||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
#else
|
#else
|
||||||
PRBool allowJustify = PR_FALSE;
|
PRBool allowJustify = PR_FALSE;
|
||||||
#endif
|
#endif
|
||||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||||
if (addedBullet) {
|
if (addedBullet) {
|
||||||
lineLayout->RemoveBulletFrame(mBullet);
|
aLineLayout.RemoveBulletFrame(mBullet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline lines do not have margins themselves; however they are
|
// Inline lines do not have margins themselves; however they are
|
||||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||||
*aKeepReflowGoing = PR_FALSE;
|
*aKeepReflowGoing = PR_FALSE;
|
||||||
}
|
}
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
||||||
else {
|
else {
|
||||||
prevSibLine->mChildCount++;
|
prevSibLine->mChildCount++;
|
||||||
prevSibLine->MarkDirty();
|
prevSibLine->MarkDirty();
|
||||||
|
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
|
|
||||||
aPrevSibling = newFrame;
|
aPrevSibling = newFrame;
|
||||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||||
line = next;
|
line = next;
|
||||||
}
|
}
|
||||||
else {
|
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
|
// Make the line that just lost a frame dirty
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
|
|
||||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder)
|
||||||
{
|
{
|
||||||
// Set the geometric parent of the floater
|
// Set the geometric parent of the floater
|
||||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||||
|
|
||||||
// Then add the floater to the current line and place it when
|
// Then add the floater to the current line and place it when
|
||||||
// appropriate
|
// appropriate
|
||||||
AddFloater(aPlaceholder, PR_TRUE);
|
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called by the line layout's AddFloater method when a
|
// 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
|
// then the floater is place immediately, otherwise the floater
|
||||||
// placement is deferred until the line has been reflowed.
|
// placement is deferred until the line has been reflowed.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder,
|
||||||
PRBool aInitialReflow)
|
PRBool aInitialReflow)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Now place the floater immediately if possible. Otherwise stash it
|
// Now place the floater immediately if possible. Otherwise stash it
|
||||||
// away in mPendingFloaters and place it later.
|
// away in mPendingFloaters and place it later.
|
||||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||||
nsRect combinedArea;
|
nsRect combinedArea;
|
||||||
nsMargin floaterMargins;
|
nsMargin floaterMargins;
|
||||||
nsMargin floaterOffsets;
|
nsMargin floaterOffsets;
|
||||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Pass on updated available space to the current inline reflow engine
|
// Pass on updated available space to the current inline reflow engine
|
||||||
GetAvailableSpace();
|
GetAvailableSpace();
|
||||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||||
mAvailSpaceRect.width,
|
mAvailSpaceRect.width,
|
||||||
mAvailSpaceRect.height,
|
mAvailSpaceRect.height,
|
||||||
isLeftFloater);
|
isLeftFloater);
|
||||||
|
|
||||||
// Restore coordinate system
|
// Restore coordinate system
|
||||||
mSpaceManager->Translate(dx, dy);
|
mSpaceManager->Translate(dx, dy);
|
||||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
||||||
const nsRect& aDirtyRect,
|
const nsRect& aDirtyRect,
|
||||||
nsFramePaintLayer aWhichLayer)
|
nsFramePaintLayer aWhichLayer)
|
||||||
{
|
{
|
||||||
|
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NOISY_DAMAGE_REPAIR
|
#ifdef NOISY_DAMAGE_REPAIR
|
||||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||||
PRInt32 depth = GetDepth();
|
PRInt32 depth = GetDepth();
|
||||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||||
mBullet, availSize);
|
mBullet, availSize);
|
||||||
reflowState.mLineLayout = aState.mLineLayout;
|
|
||||||
nsIHTMLReflow* htmlReflow;
|
nsIHTMLReflow* htmlReflow;
|
||||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
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
|
//XXX get rid of this -- its slow
|
||||||
void
|
void
|
||||||
nsBlockFrame::BuildFloaterList()
|
nsBlockFrame::BuildFloaterList()
|
||||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
||||||
else {
|
else {
|
||||||
// Remove frame from line and mark the line dirty
|
// Remove frame from line and mark the line dirty
|
||||||
--line->mChildCount;
|
--line->mChildCount;
|
||||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
firstChild->GetNextSibling(&line->mFirstChild);
|
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;
|
count += line->mChildCount;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
#include "nsIFocusTracker.h"
|
#include "nsIFocusTracker.h"
|
||||||
#include "nsIFrameSelection.h"
|
#include "nsIFrameSelection.h"
|
||||||
|
|
||||||
|
#define MAX_LINE_COUNT 50000
|
||||||
|
|
||||||
// XXX HTML:P's that are empty yet have style indicating they should
|
// XXX HTML:P's that are empty yet have style indicating they should
|
||||||
// clear floaters - we need to ignore the clear behavior.
|
// clear floaters - we need to ignore the clear behavior.
|
||||||
|
|
||||||
|
@ -203,8 +205,7 @@ public:
|
||||||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics);
|
||||||
nsLineLayout* aLineLayout);
|
|
||||||
|
|
||||||
~nsBlockReflowState();
|
~nsBlockReflowState();
|
||||||
|
|
||||||
|
@ -240,9 +241,11 @@ public:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
void InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame);
|
||||||
|
|
||||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
void AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame,
|
||||||
PRBool aInitialReflow);
|
PRBool aInitialReflow);
|
||||||
|
|
||||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||||
|
@ -302,13 +305,20 @@ public:
|
||||||
nscoord* aTopMarginResult,
|
nscoord* aTopMarginResult,
|
||||||
nscoord* aBottomMarginResult);
|
nscoord* aBottomMarginResult);
|
||||||
|
|
||||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
|
nsRect& aResult);
|
||||||
|
|
||||||
void RecoverStateFrom(nsLineBox* aLine,
|
void RecoverStateFrom(nsLineBox* aLine,
|
||||||
PRBool aApplyTopMargin,
|
PRBool aApplyTopMargin,
|
||||||
nscoord aDeltaY,
|
nscoord aDeltaY,
|
||||||
nsRect* aDamageRect);
|
nsRect* aDamageRect);
|
||||||
|
|
||||||
|
void AdvanceToNextLine() {
|
||||||
|
mLineNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
// This state is the "global" state computed once for the reflow of
|
// This state is the "global" state computed once for the reflow of
|
||||||
|
@ -321,7 +331,7 @@ public:
|
||||||
|
|
||||||
const nsHTMLReflowState& mReflowState;
|
const nsHTMLReflowState& mReflowState;
|
||||||
|
|
||||||
nsLineLayout* mLineLayout;
|
// nsLineLayout* mLineLayout;
|
||||||
|
|
||||||
nsISpaceManager* mSpaceManager;
|
nsISpaceManager* mSpaceManager;
|
||||||
|
|
||||||
|
@ -411,18 +421,22 @@ public:
|
||||||
PRBool mComputeMaxElementSize;
|
PRBool mComputeMaxElementSize;
|
||||||
|
|
||||||
nsSize mMaxElementSize;
|
nsSize mMaxElementSize;
|
||||||
|
|
||||||
|
nscoord mMinLineHeight;
|
||||||
|
|
||||||
|
PRInt32 mLineNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX This is vile. Make it go away
|
// XXX This is vile. Make it go away
|
||||||
void
|
void
|
||||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||||
{
|
{
|
||||||
mBlockRS->InitFloater(aFrame);
|
mBlockRS->InitFloater(*this, aFrame);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
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,
|
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics)
|
||||||
nsLineLayout* aLineLayout)
|
|
||||||
: mBlock(aFrame),
|
: mBlock(aFrame),
|
||||||
mPresContext(aPresContext),
|
mPresContext(aPresContext),
|
||||||
mReflowState(aReflowState),
|
mReflowState(aReflowState),
|
||||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
mIsBottomMarginRoot(PR_FALSE),
|
mIsBottomMarginRoot(PR_FALSE),
|
||||||
mApplyTopMargin(PR_FALSE),
|
mApplyTopMargin(PR_FALSE),
|
||||||
mNextRCFrame(nsnull),
|
mNextRCFrame(nsnull),
|
||||||
mPrevBottomMargin(0)
|
mPrevBottomMargin(0),
|
||||||
|
mLineNumber(0)
|
||||||
{
|
{
|
||||||
mLineLayout = aLineLayout;
|
|
||||||
|
|
||||||
mSpaceManager = aReflowState.mSpaceManager;
|
mSpaceManager = aReflowState.mSpaceManager;
|
||||||
|
|
||||||
// Translate into our content area and then save the
|
// Translate into our content area and then save the
|
||||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||||
mMaxElementSize.SizeTo(0, 0);
|
mMaxElementSize.SizeTo(0, 0);
|
||||||
|
|
||||||
if (0 != borderPadding.top) {
|
if (0 != borderPadding.top) {
|
||||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
if (0 != borderPadding.bottom) {
|
if (0 != borderPadding.bottom) {
|
||||||
mIsBottomMarginRoot = PR_TRUE;
|
mIsBottomMarginRoot = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||||
|
aReflowState.frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsBlockReflowState::~nsBlockReflowState()
|
nsBlockReflowState::~nsBlockReflowState()
|
||||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
||||||
// at the current Y coordinate. This method assumes that
|
// at the current Y coordinate. This method assumes that
|
||||||
// GetAvailableSpace has already been called.
|
// GetAvailableSpace has already been called.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
nsRect& aResult)
|
nsRect& aResult)
|
||||||
{
|
{
|
||||||
nscoord availHeight = mUnconstrainedHeight
|
nscoord availHeight = mUnconstrainedHeight
|
||||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
|
|
||||||
const nsMargin& borderPadding = BorderPadding();
|
const nsMargin& borderPadding = BorderPadding();
|
||||||
nscoord availX, availWidth;
|
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
|
// Frames that know how to do non-rectangular splitting are given
|
||||||
// the entire available space, including space consumed by
|
// the entire available space, including space consumed by
|
||||||
// floaters.
|
// floaters.
|
||||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
availX = mAvailSpaceRect.x + borderPadding.left;
|
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||||
availWidth = mAvailSpaceRect.width;
|
availWidth = mAvailSpaceRect.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
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
|
// Setup reflow state to compute the block childs top and bottom
|
||||||
// margins
|
// margins
|
||||||
nsIFrame* frame = aLine->mFirstChild;
|
nsIFrame* frame = aLine->mFirstChild;
|
||||||
|
nsRect availSpaceRect;
|
||||||
|
const nsStyleDisplay* display;
|
||||||
|
frame->GetStyleData(eStyleStruct_Display,
|
||||||
|
(const nsStyleStruct*&) display);
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpaceRect;
|
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
|
||||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||||
frame, availSpace);
|
frame, availSpace);
|
||||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||||
const nsHTMLReflowState& aReflowState,
|
const nsHTMLReflowState& aReflowState,
|
||||||
nsReflowStatus& aStatus)
|
nsReflowStatus& aStatus)
|
||||||
{
|
{
|
||||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
#ifdef DEBUG_kipp
|
||||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
{
|
||||||
&lineLayout);
|
extern char* nsPresShell_ReflowStackPointerTop;
|
||||||
lineLayout.Init(&state);
|
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) {
|
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||||
state.mIsTopMarginRoot = PR_TRUE;
|
state.mIsTopMarginRoot = PR_TRUE;
|
||||||
state.mIsBottomMarginRoot = PR_TRUE;
|
state.mIsBottomMarginRoot = PR_TRUE;
|
||||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRBool keepGoing = PR_TRUE;
|
PRBool keepGoing = PR_TRUE;
|
||||||
|
|
||||||
// Inform line layout of where the text runs are
|
|
||||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
|
||||||
|
|
||||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||||
nsIReflowCommand::ReflowType type;
|
nsIReflowCommand::ReflowType type;
|
||||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
// If this is an inline frame then its time to stop
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull data from a next-in-flow if we can
|
// 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
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle an odd-ball case: a list-item with no lines
|
// Handle an odd-ball case: a list-item with no lines
|
||||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
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
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
||||||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||||
}
|
}
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (0 != --fromLine->mChildCount) {
|
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
|
// Mark line dirty now that we pulled a child
|
||||||
fromLine->MarkDirty();
|
fromLine->MarkDirty();
|
||||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||||
return PR_FALSE;
|
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*
|
nsIFrame*
|
||||||
nsBlockFrame::GetTopBlockChild()
|
nsBlockFrame::GetTopBlockChild()
|
||||||
{
|
{
|
||||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
||||||
return nsnull;
|
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
|
nsresult
|
||||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpace;
|
nsRect availSpace;
|
||||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||||
|
|
||||||
// Reflow the block into the available space
|
// Reflow the block into the available space
|
||||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
// Do not count the continuation child on the line it used
|
// Do not count the continuation child on the line it used
|
||||||
// to be on
|
// to be on
|
||||||
aLine->mChildCount--;
|
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
|
// 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 -
|
bbox.y = aState.BorderPadding().top + ascent -
|
||||||
metrics.ascent + topMargin;
|
metrics.ascent + topMargin;
|
||||||
mBullet->SetRect(bbox);
|
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 {
|
else {
|
||||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
PRInt32 spins = 0;
|
PRInt32 spins = 0;
|
||||||
#endif
|
#endif
|
||||||
for (;;) {
|
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||||
if (nsnull != aLine->mFloaters) {
|
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||||
// Forget all of the floaters on the line
|
// Prevent overflowing limited thread stacks by creating
|
||||||
aLine->mFloaters->Clear();
|
// nsLineLayout from the heap when the frame tree depth gets
|
||||||
}
|
// large.
|
||||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||||
aState.mPendingFloaters.Clear();
|
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||||
|
&lineReflowStatus);
|
||||||
// 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 {
|
else {
|
||||||
/* XXX get the height right! */
|
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||||
availHeight = aState.mAvailSpaceRect.height;
|
&lineReflowStatus);
|
||||||
}
|
}
|
||||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
if (NS_FAILED(rv)) {
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
#ifdef DEBUG
|
||||||
spins++;
|
spins++;
|
||||||
if (1000 == spins) {
|
if (1000 == spins) {
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||||
NS_ABORT();
|
NS_ABORT();
|
||||||
}
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
#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
|
// If we are propogating out a break-before status then there is
|
||||||
// no point in placing the line.
|
// no point in placing the line.
|
||||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||||
lineLayout->EndLineReflow();
|
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
*aLineReflowStatus = lineReflowStatus;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame,
|
nsIFrame* aFrame,
|
||||||
PRUint8* aLineReflowStatus)
|
PRUint8* aLineReflowStatus)
|
||||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
|
||||||
// If it's currently ok to be reflowing in first-letter style then
|
// 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.
|
// 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
|
#ifdef NOISY_FIRST_LETTER
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": reflowing ");
|
printf(": reflowing ");
|
||||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reflow the inline frame
|
// Reflow the inline frame
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
nsReflowStatus frameReflowStatus;
|
nsReflowStatus frameReflowStatus;
|
||||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||||
frameReflowStatus);
|
frameReflowStatus);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
else {
|
else {
|
||||||
// It's not the first child on this line so go ahead and split
|
// 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.
|
// 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)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line, but after the frame just reflowed
|
// Split line, but after the frame just reflowed
|
||||||
nsIFrame* nextFrame;
|
nsIFrame* nextFrame;
|
||||||
aFrame->GetNextSibling(&nextFrame);
|
aFrame->GetNextSibling(&nextFrame);
|
||||||
rv = SplitLine(aState, aLine, nextFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line after the current frame
|
// Split line after the current frame
|
||||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||||
aFrame->GetNextSibling(&aFrame);
|
aFrame->GetNextSibling(&aFrame);
|
||||||
rv = SplitLine(aState, aLine, aFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
if (nsnull != nextInFlow) {
|
if (nsnull != nextInFlow) {
|
||||||
aMadeNewFrame = PR_TRUE;
|
aMadeNewFrame = PR_TRUE;
|
||||||
aLine->mChildCount++;
|
aLine->mChildCount++;
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_FALSE);
|
VerifyLines(PR_FALSE);
|
||||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame)
|
nsIFrame* aFrame)
|
||||||
{
|
{
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
|
||||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||||
//aLine->List(stdout, 0);
|
//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
|
// Let line layout know that some frames are no longer part of its
|
||||||
// state.
|
// state.
|
||||||
if (!aLine->IsBlock()) {
|
if (!aLine->IsBlock()) {
|
||||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_TRUE);
|
VerifyLines(PR_TRUE);
|
||||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepReflowGoing)
|
PRBool* aKeepReflowGoing)
|
||||||
{
|
{
|
||||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
// method is used for placing a line of inline frames. If the rare
|
// 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
|
// case is happening then the worst that will happen is that the
|
||||||
// bullet frame will be reflowed twice.
|
// bullet frame will be reflowed twice.
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
PRBool addedBullet = PR_FALSE;
|
PRBool addedBullet = PR_FALSE;
|
||||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||||
PlaceBullet(aState);
|
nsHTMLReflowMetrics metrics(nsnull);
|
||||||
|
ReflowBullet(aState, metrics);
|
||||||
|
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||||
addedBullet = PR_TRUE;
|
addedBullet = PR_TRUE;
|
||||||
}
|
}
|
||||||
nsSize maxElementSize;
|
nsSize maxElementSize;
|
||||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
static nscoord lastHeight = 0;
|
static nscoord lastHeight = 0;
|
||||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
#else
|
#else
|
||||||
PRBool allowJustify = PR_FALSE;
|
PRBool allowJustify = PR_FALSE;
|
||||||
#endif
|
#endif
|
||||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||||
if (addedBullet) {
|
if (addedBullet) {
|
||||||
lineLayout->RemoveBulletFrame(mBullet);
|
aLineLayout.RemoveBulletFrame(mBullet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline lines do not have margins themselves; however they are
|
// Inline lines do not have margins themselves; however they are
|
||||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||||
*aKeepReflowGoing = PR_FALSE;
|
*aKeepReflowGoing = PR_FALSE;
|
||||||
}
|
}
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
||||||
else {
|
else {
|
||||||
prevSibLine->mChildCount++;
|
prevSibLine->mChildCount++;
|
||||||
prevSibLine->MarkDirty();
|
prevSibLine->MarkDirty();
|
||||||
|
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
|
|
||||||
aPrevSibling = newFrame;
|
aPrevSibling = newFrame;
|
||||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||||
line = next;
|
line = next;
|
||||||
}
|
}
|
||||||
else {
|
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
|
// Make the line that just lost a frame dirty
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
|
|
||||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder)
|
||||||
{
|
{
|
||||||
// Set the geometric parent of the floater
|
// Set the geometric parent of the floater
|
||||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||||
|
|
||||||
// Then add the floater to the current line and place it when
|
// Then add the floater to the current line and place it when
|
||||||
// appropriate
|
// appropriate
|
||||||
AddFloater(aPlaceholder, PR_TRUE);
|
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called by the line layout's AddFloater method when a
|
// 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
|
// then the floater is place immediately, otherwise the floater
|
||||||
// placement is deferred until the line has been reflowed.
|
// placement is deferred until the line has been reflowed.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder,
|
||||||
PRBool aInitialReflow)
|
PRBool aInitialReflow)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Now place the floater immediately if possible. Otherwise stash it
|
// Now place the floater immediately if possible. Otherwise stash it
|
||||||
// away in mPendingFloaters and place it later.
|
// away in mPendingFloaters and place it later.
|
||||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||||
nsRect combinedArea;
|
nsRect combinedArea;
|
||||||
nsMargin floaterMargins;
|
nsMargin floaterMargins;
|
||||||
nsMargin floaterOffsets;
|
nsMargin floaterOffsets;
|
||||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Pass on updated available space to the current inline reflow engine
|
// Pass on updated available space to the current inline reflow engine
|
||||||
GetAvailableSpace();
|
GetAvailableSpace();
|
||||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||||
mAvailSpaceRect.width,
|
mAvailSpaceRect.width,
|
||||||
mAvailSpaceRect.height,
|
mAvailSpaceRect.height,
|
||||||
isLeftFloater);
|
isLeftFloater);
|
||||||
|
|
||||||
// Restore coordinate system
|
// Restore coordinate system
|
||||||
mSpaceManager->Translate(dx, dy);
|
mSpaceManager->Translate(dx, dy);
|
||||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
||||||
const nsRect& aDirtyRect,
|
const nsRect& aDirtyRect,
|
||||||
nsFramePaintLayer aWhichLayer)
|
nsFramePaintLayer aWhichLayer)
|
||||||
{
|
{
|
||||||
|
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NOISY_DAMAGE_REPAIR
|
#ifdef NOISY_DAMAGE_REPAIR
|
||||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||||
PRInt32 depth = GetDepth();
|
PRInt32 depth = GetDepth();
|
||||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||||
mBullet, availSize);
|
mBullet, availSize);
|
||||||
reflowState.mLineLayout = aState.mLineLayout;
|
|
||||||
nsIHTMLReflow* htmlReflow;
|
nsIHTMLReflow* htmlReflow;
|
||||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
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
|
//XXX get rid of this -- its slow
|
||||||
void
|
void
|
||||||
nsBlockFrame::BuildFloaterList()
|
nsBlockFrame::BuildFloaterList()
|
||||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
||||||
else {
|
else {
|
||||||
// Remove frame from line and mark the line dirty
|
// Remove frame from line and mark the line dirty
|
||||||
--line->mChildCount;
|
--line->mChildCount;
|
||||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
firstChild->GetNextSibling(&line->mFirstChild);
|
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;
|
count += line->mChildCount;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,7 @@ protected:
|
||||||
PRBool aKeepReflowGoing);
|
PRBool aKeepReflowGoing);
|
||||||
|
|
||||||
nsresult PlaceLine(nsBlockReflowState& aState,
|
nsresult PlaceLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepReflowGoing);
|
PRBool* aKeepReflowGoing);
|
||||||
|
|
||||||
|
@ -258,7 +259,24 @@ protected:
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepLineGoing);
|
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,
|
nsresult ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame,
|
nsIFrame* aFrame,
|
||||||
PRUint8* aLineReflowStatus);
|
PRUint8* aLineReflowStatus);
|
||||||
|
@ -278,6 +296,7 @@ protected:
|
||||||
PRBool& aMadeNewFrame);
|
PRBool& aMadeNewFrame);
|
||||||
|
|
||||||
nsresult SplitLine(nsBlockReflowState& aState,
|
nsresult SplitLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame);
|
nsIFrame* aFrame);
|
||||||
|
|
||||||
|
@ -332,8 +351,6 @@ protected:
|
||||||
void ReflowBullet(nsBlockReflowState& aState,
|
void ReflowBullet(nsBlockReflowState& aState,
|
||||||
nsHTMLReflowMetrics& aMetrics);
|
nsHTMLReflowMetrics& aMetrics);
|
||||||
|
|
||||||
void PlaceBullet(nsBlockReflowState& aState);
|
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
nsIFrame* LastChild();
|
nsIFrame* LastChild();
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
#include "nsIFocusTracker.h"
|
#include "nsIFocusTracker.h"
|
||||||
#include "nsIFrameSelection.h"
|
#include "nsIFrameSelection.h"
|
||||||
|
|
||||||
|
#define MAX_LINE_COUNT 50000
|
||||||
|
|
||||||
// XXX HTML:P's that are empty yet have style indicating they should
|
// XXX HTML:P's that are empty yet have style indicating they should
|
||||||
// clear floaters - we need to ignore the clear behavior.
|
// clear floaters - we need to ignore the clear behavior.
|
||||||
|
|
||||||
|
@ -203,8 +205,7 @@ public:
|
||||||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics);
|
||||||
nsLineLayout* aLineLayout);
|
|
||||||
|
|
||||||
~nsBlockReflowState();
|
~nsBlockReflowState();
|
||||||
|
|
||||||
|
@ -240,9 +241,11 @@ public:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
void InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame);
|
||||||
|
|
||||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
void AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame,
|
||||||
PRBool aInitialReflow);
|
PRBool aInitialReflow);
|
||||||
|
|
||||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||||
|
@ -302,13 +305,20 @@ public:
|
||||||
nscoord* aTopMarginResult,
|
nscoord* aTopMarginResult,
|
||||||
nscoord* aBottomMarginResult);
|
nscoord* aBottomMarginResult);
|
||||||
|
|
||||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
|
nsRect& aResult);
|
||||||
|
|
||||||
void RecoverStateFrom(nsLineBox* aLine,
|
void RecoverStateFrom(nsLineBox* aLine,
|
||||||
PRBool aApplyTopMargin,
|
PRBool aApplyTopMargin,
|
||||||
nscoord aDeltaY,
|
nscoord aDeltaY,
|
||||||
nsRect* aDamageRect);
|
nsRect* aDamageRect);
|
||||||
|
|
||||||
|
void AdvanceToNextLine() {
|
||||||
|
mLineNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
// This state is the "global" state computed once for the reflow of
|
// This state is the "global" state computed once for the reflow of
|
||||||
|
@ -321,7 +331,7 @@ public:
|
||||||
|
|
||||||
const nsHTMLReflowState& mReflowState;
|
const nsHTMLReflowState& mReflowState;
|
||||||
|
|
||||||
nsLineLayout* mLineLayout;
|
// nsLineLayout* mLineLayout;
|
||||||
|
|
||||||
nsISpaceManager* mSpaceManager;
|
nsISpaceManager* mSpaceManager;
|
||||||
|
|
||||||
|
@ -411,18 +421,22 @@ public:
|
||||||
PRBool mComputeMaxElementSize;
|
PRBool mComputeMaxElementSize;
|
||||||
|
|
||||||
nsSize mMaxElementSize;
|
nsSize mMaxElementSize;
|
||||||
|
|
||||||
|
nscoord mMinLineHeight;
|
||||||
|
|
||||||
|
PRInt32 mLineNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX This is vile. Make it go away
|
// XXX This is vile. Make it go away
|
||||||
void
|
void
|
||||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||||
{
|
{
|
||||||
mBlockRS->InitFloater(aFrame);
|
mBlockRS->InitFloater(*this, aFrame);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
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,
|
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics)
|
||||||
nsLineLayout* aLineLayout)
|
|
||||||
: mBlock(aFrame),
|
: mBlock(aFrame),
|
||||||
mPresContext(aPresContext),
|
mPresContext(aPresContext),
|
||||||
mReflowState(aReflowState),
|
mReflowState(aReflowState),
|
||||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
mIsBottomMarginRoot(PR_FALSE),
|
mIsBottomMarginRoot(PR_FALSE),
|
||||||
mApplyTopMargin(PR_FALSE),
|
mApplyTopMargin(PR_FALSE),
|
||||||
mNextRCFrame(nsnull),
|
mNextRCFrame(nsnull),
|
||||||
mPrevBottomMargin(0)
|
mPrevBottomMargin(0),
|
||||||
|
mLineNumber(0)
|
||||||
{
|
{
|
||||||
mLineLayout = aLineLayout;
|
|
||||||
|
|
||||||
mSpaceManager = aReflowState.mSpaceManager;
|
mSpaceManager = aReflowState.mSpaceManager;
|
||||||
|
|
||||||
// Translate into our content area and then save the
|
// Translate into our content area and then save the
|
||||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||||
mMaxElementSize.SizeTo(0, 0);
|
mMaxElementSize.SizeTo(0, 0);
|
||||||
|
|
||||||
if (0 != borderPadding.top) {
|
if (0 != borderPadding.top) {
|
||||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
if (0 != borderPadding.bottom) {
|
if (0 != borderPadding.bottom) {
|
||||||
mIsBottomMarginRoot = PR_TRUE;
|
mIsBottomMarginRoot = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||||
|
aReflowState.frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsBlockReflowState::~nsBlockReflowState()
|
nsBlockReflowState::~nsBlockReflowState()
|
||||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
||||||
// at the current Y coordinate. This method assumes that
|
// at the current Y coordinate. This method assumes that
|
||||||
// GetAvailableSpace has already been called.
|
// GetAvailableSpace has already been called.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
nsRect& aResult)
|
nsRect& aResult)
|
||||||
{
|
{
|
||||||
nscoord availHeight = mUnconstrainedHeight
|
nscoord availHeight = mUnconstrainedHeight
|
||||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
|
|
||||||
const nsMargin& borderPadding = BorderPadding();
|
const nsMargin& borderPadding = BorderPadding();
|
||||||
nscoord availX, availWidth;
|
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
|
// Frames that know how to do non-rectangular splitting are given
|
||||||
// the entire available space, including space consumed by
|
// the entire available space, including space consumed by
|
||||||
// floaters.
|
// floaters.
|
||||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
availX = mAvailSpaceRect.x + borderPadding.left;
|
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||||
availWidth = mAvailSpaceRect.width;
|
availWidth = mAvailSpaceRect.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
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
|
// Setup reflow state to compute the block childs top and bottom
|
||||||
// margins
|
// margins
|
||||||
nsIFrame* frame = aLine->mFirstChild;
|
nsIFrame* frame = aLine->mFirstChild;
|
||||||
|
nsRect availSpaceRect;
|
||||||
|
const nsStyleDisplay* display;
|
||||||
|
frame->GetStyleData(eStyleStruct_Display,
|
||||||
|
(const nsStyleStruct*&) display);
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpaceRect;
|
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
|
||||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||||
frame, availSpace);
|
frame, availSpace);
|
||||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||||
const nsHTMLReflowState& aReflowState,
|
const nsHTMLReflowState& aReflowState,
|
||||||
nsReflowStatus& aStatus)
|
nsReflowStatus& aStatus)
|
||||||
{
|
{
|
||||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
#ifdef DEBUG_kipp
|
||||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
{
|
||||||
&lineLayout);
|
extern char* nsPresShell_ReflowStackPointerTop;
|
||||||
lineLayout.Init(&state);
|
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) {
|
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||||
state.mIsTopMarginRoot = PR_TRUE;
|
state.mIsTopMarginRoot = PR_TRUE;
|
||||||
state.mIsBottomMarginRoot = PR_TRUE;
|
state.mIsBottomMarginRoot = PR_TRUE;
|
||||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRBool keepGoing = PR_TRUE;
|
PRBool keepGoing = PR_TRUE;
|
||||||
|
|
||||||
// Inform line layout of where the text runs are
|
|
||||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
|
||||||
|
|
||||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||||
nsIReflowCommand::ReflowType type;
|
nsIReflowCommand::ReflowType type;
|
||||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
// If this is an inline frame then its time to stop
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull data from a next-in-flow if we can
|
// 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
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle an odd-ball case: a list-item with no lines
|
// Handle an odd-ball case: a list-item with no lines
|
||||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
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
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
||||||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||||
}
|
}
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (0 != --fromLine->mChildCount) {
|
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
|
// Mark line dirty now that we pulled a child
|
||||||
fromLine->MarkDirty();
|
fromLine->MarkDirty();
|
||||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||||
return PR_FALSE;
|
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*
|
nsIFrame*
|
||||||
nsBlockFrame::GetTopBlockChild()
|
nsBlockFrame::GetTopBlockChild()
|
||||||
{
|
{
|
||||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
||||||
return nsnull;
|
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
|
nsresult
|
||||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpace;
|
nsRect availSpace;
|
||||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||||
|
|
||||||
// Reflow the block into the available space
|
// Reflow the block into the available space
|
||||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
// Do not count the continuation child on the line it used
|
// Do not count the continuation child on the line it used
|
||||||
// to be on
|
// to be on
|
||||||
aLine->mChildCount--;
|
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
|
// 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 -
|
bbox.y = aState.BorderPadding().top + ascent -
|
||||||
metrics.ascent + topMargin;
|
metrics.ascent + topMargin;
|
||||||
mBullet->SetRect(bbox);
|
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 {
|
else {
|
||||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
PRInt32 spins = 0;
|
PRInt32 spins = 0;
|
||||||
#endif
|
#endif
|
||||||
for (;;) {
|
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||||
if (nsnull != aLine->mFloaters) {
|
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||||
// Forget all of the floaters on the line
|
// Prevent overflowing limited thread stacks by creating
|
||||||
aLine->mFloaters->Clear();
|
// nsLineLayout from the heap when the frame tree depth gets
|
||||||
}
|
// large.
|
||||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||||
aState.mPendingFloaters.Clear();
|
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||||
|
&lineReflowStatus);
|
||||||
// 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 {
|
else {
|
||||||
/* XXX get the height right! */
|
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||||
availHeight = aState.mAvailSpaceRect.height;
|
&lineReflowStatus);
|
||||||
}
|
}
|
||||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
if (NS_FAILED(rv)) {
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
#ifdef DEBUG
|
||||||
spins++;
|
spins++;
|
||||||
if (1000 == spins) {
|
if (1000 == spins) {
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||||
NS_ABORT();
|
NS_ABORT();
|
||||||
}
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
#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
|
// If we are propogating out a break-before status then there is
|
||||||
// no point in placing the line.
|
// no point in placing the line.
|
||||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||||
lineLayout->EndLineReflow();
|
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
*aLineReflowStatus = lineReflowStatus;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame,
|
nsIFrame* aFrame,
|
||||||
PRUint8* aLineReflowStatus)
|
PRUint8* aLineReflowStatus)
|
||||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
|
||||||
// If it's currently ok to be reflowing in first-letter style then
|
// 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.
|
// 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
|
#ifdef NOISY_FIRST_LETTER
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": reflowing ");
|
printf(": reflowing ");
|
||||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reflow the inline frame
|
// Reflow the inline frame
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
nsReflowStatus frameReflowStatus;
|
nsReflowStatus frameReflowStatus;
|
||||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||||
frameReflowStatus);
|
frameReflowStatus);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
else {
|
else {
|
||||||
// It's not the first child on this line so go ahead and split
|
// 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.
|
// 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)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line, but after the frame just reflowed
|
// Split line, but after the frame just reflowed
|
||||||
nsIFrame* nextFrame;
|
nsIFrame* nextFrame;
|
||||||
aFrame->GetNextSibling(&nextFrame);
|
aFrame->GetNextSibling(&nextFrame);
|
||||||
rv = SplitLine(aState, aLine, nextFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line after the current frame
|
// Split line after the current frame
|
||||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||||
aFrame->GetNextSibling(&aFrame);
|
aFrame->GetNextSibling(&aFrame);
|
||||||
rv = SplitLine(aState, aLine, aFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
if (nsnull != nextInFlow) {
|
if (nsnull != nextInFlow) {
|
||||||
aMadeNewFrame = PR_TRUE;
|
aMadeNewFrame = PR_TRUE;
|
||||||
aLine->mChildCount++;
|
aLine->mChildCount++;
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_FALSE);
|
VerifyLines(PR_FALSE);
|
||||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame)
|
nsIFrame* aFrame)
|
||||||
{
|
{
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
|
||||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||||
//aLine->List(stdout, 0);
|
//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
|
// Let line layout know that some frames are no longer part of its
|
||||||
// state.
|
// state.
|
||||||
if (!aLine->IsBlock()) {
|
if (!aLine->IsBlock()) {
|
||||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_TRUE);
|
VerifyLines(PR_TRUE);
|
||||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepReflowGoing)
|
PRBool* aKeepReflowGoing)
|
||||||
{
|
{
|
||||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
// method is used for placing a line of inline frames. If the rare
|
// 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
|
// case is happening then the worst that will happen is that the
|
||||||
// bullet frame will be reflowed twice.
|
// bullet frame will be reflowed twice.
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
PRBool addedBullet = PR_FALSE;
|
PRBool addedBullet = PR_FALSE;
|
||||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||||
PlaceBullet(aState);
|
nsHTMLReflowMetrics metrics(nsnull);
|
||||||
|
ReflowBullet(aState, metrics);
|
||||||
|
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||||
addedBullet = PR_TRUE;
|
addedBullet = PR_TRUE;
|
||||||
}
|
}
|
||||||
nsSize maxElementSize;
|
nsSize maxElementSize;
|
||||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
static nscoord lastHeight = 0;
|
static nscoord lastHeight = 0;
|
||||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
#else
|
#else
|
||||||
PRBool allowJustify = PR_FALSE;
|
PRBool allowJustify = PR_FALSE;
|
||||||
#endif
|
#endif
|
||||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||||
if (addedBullet) {
|
if (addedBullet) {
|
||||||
lineLayout->RemoveBulletFrame(mBullet);
|
aLineLayout.RemoveBulletFrame(mBullet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline lines do not have margins themselves; however they are
|
// Inline lines do not have margins themselves; however they are
|
||||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||||
*aKeepReflowGoing = PR_FALSE;
|
*aKeepReflowGoing = PR_FALSE;
|
||||||
}
|
}
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
||||||
else {
|
else {
|
||||||
prevSibLine->mChildCount++;
|
prevSibLine->mChildCount++;
|
||||||
prevSibLine->MarkDirty();
|
prevSibLine->MarkDirty();
|
||||||
|
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
|
|
||||||
aPrevSibling = newFrame;
|
aPrevSibling = newFrame;
|
||||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||||
line = next;
|
line = next;
|
||||||
}
|
}
|
||||||
else {
|
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
|
// Make the line that just lost a frame dirty
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
|
|
||||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder)
|
||||||
{
|
{
|
||||||
// Set the geometric parent of the floater
|
// Set the geometric parent of the floater
|
||||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||||
|
|
||||||
// Then add the floater to the current line and place it when
|
// Then add the floater to the current line and place it when
|
||||||
// appropriate
|
// appropriate
|
||||||
AddFloater(aPlaceholder, PR_TRUE);
|
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called by the line layout's AddFloater method when a
|
// 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
|
// then the floater is place immediately, otherwise the floater
|
||||||
// placement is deferred until the line has been reflowed.
|
// placement is deferred until the line has been reflowed.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder,
|
||||||
PRBool aInitialReflow)
|
PRBool aInitialReflow)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Now place the floater immediately if possible. Otherwise stash it
|
// Now place the floater immediately if possible. Otherwise stash it
|
||||||
// away in mPendingFloaters and place it later.
|
// away in mPendingFloaters and place it later.
|
||||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||||
nsRect combinedArea;
|
nsRect combinedArea;
|
||||||
nsMargin floaterMargins;
|
nsMargin floaterMargins;
|
||||||
nsMargin floaterOffsets;
|
nsMargin floaterOffsets;
|
||||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Pass on updated available space to the current inline reflow engine
|
// Pass on updated available space to the current inline reflow engine
|
||||||
GetAvailableSpace();
|
GetAvailableSpace();
|
||||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||||
mAvailSpaceRect.width,
|
mAvailSpaceRect.width,
|
||||||
mAvailSpaceRect.height,
|
mAvailSpaceRect.height,
|
||||||
isLeftFloater);
|
isLeftFloater);
|
||||||
|
|
||||||
// Restore coordinate system
|
// Restore coordinate system
|
||||||
mSpaceManager->Translate(dx, dy);
|
mSpaceManager->Translate(dx, dy);
|
||||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
||||||
const nsRect& aDirtyRect,
|
const nsRect& aDirtyRect,
|
||||||
nsFramePaintLayer aWhichLayer)
|
nsFramePaintLayer aWhichLayer)
|
||||||
{
|
{
|
||||||
|
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NOISY_DAMAGE_REPAIR
|
#ifdef NOISY_DAMAGE_REPAIR
|
||||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||||
PRInt32 depth = GetDepth();
|
PRInt32 depth = GetDepth();
|
||||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||||
mBullet, availSize);
|
mBullet, availSize);
|
||||||
reflowState.mLineLayout = aState.mLineLayout;
|
|
||||||
nsIHTMLReflow* htmlReflow;
|
nsIHTMLReflow* htmlReflow;
|
||||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
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
|
//XXX get rid of this -- its slow
|
||||||
void
|
void
|
||||||
nsBlockFrame::BuildFloaterList()
|
nsBlockFrame::BuildFloaterList()
|
||||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
||||||
else {
|
else {
|
||||||
// Remove frame from line and mark the line dirty
|
// Remove frame from line and mark the line dirty
|
||||||
--line->mChildCount;
|
--line->mChildCount;
|
||||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
firstChild->GetNextSibling(&line->mFirstChild);
|
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;
|
count += line->mChildCount;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
#include "nsIFocusTracker.h"
|
#include "nsIFocusTracker.h"
|
||||||
#include "nsIFrameSelection.h"
|
#include "nsIFrameSelection.h"
|
||||||
|
|
||||||
|
#define MAX_LINE_COUNT 50000
|
||||||
|
|
||||||
// XXX HTML:P's that are empty yet have style indicating they should
|
// XXX HTML:P's that are empty yet have style indicating they should
|
||||||
// clear floaters - we need to ignore the clear behavior.
|
// clear floaters - we need to ignore the clear behavior.
|
||||||
|
|
||||||
|
@ -203,8 +205,7 @@ public:
|
||||||
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics);
|
||||||
nsLineLayout* aLineLayout);
|
|
||||||
|
|
||||||
~nsBlockReflowState();
|
~nsBlockReflowState();
|
||||||
|
|
||||||
|
@ -240,9 +241,11 @@ public:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
void InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame);
|
||||||
|
|
||||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame,
|
void AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholderFrame,
|
||||||
PRBool aInitialReflow);
|
PRBool aInitialReflow);
|
||||||
|
|
||||||
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
||||||
|
@ -302,13 +305,20 @@ public:
|
||||||
nscoord* aTopMarginResult,
|
nscoord* aTopMarginResult,
|
||||||
nscoord* aBottomMarginResult);
|
nscoord* aBottomMarginResult);
|
||||||
|
|
||||||
void ComputeBlockAvailSpace(nsSplittableType aSplitType, nsRect& aResult);
|
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
|
nsRect& aResult);
|
||||||
|
|
||||||
void RecoverStateFrom(nsLineBox* aLine,
|
void RecoverStateFrom(nsLineBox* aLine,
|
||||||
PRBool aApplyTopMargin,
|
PRBool aApplyTopMargin,
|
||||||
nscoord aDeltaY,
|
nscoord aDeltaY,
|
||||||
nsRect* aDamageRect);
|
nsRect* aDamageRect);
|
||||||
|
|
||||||
|
void AdvanceToNextLine() {
|
||||||
|
mLineNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
// This state is the "global" state computed once for the reflow of
|
// This state is the "global" state computed once for the reflow of
|
||||||
|
@ -321,7 +331,7 @@ public:
|
||||||
|
|
||||||
const nsHTMLReflowState& mReflowState;
|
const nsHTMLReflowState& mReflowState;
|
||||||
|
|
||||||
nsLineLayout* mLineLayout;
|
// nsLineLayout* mLineLayout;
|
||||||
|
|
||||||
nsISpaceManager* mSpaceManager;
|
nsISpaceManager* mSpaceManager;
|
||||||
|
|
||||||
|
@ -411,18 +421,22 @@ public:
|
||||||
PRBool mComputeMaxElementSize;
|
PRBool mComputeMaxElementSize;
|
||||||
|
|
||||||
nsSize mMaxElementSize;
|
nsSize mMaxElementSize;
|
||||||
|
|
||||||
|
nscoord mMinLineHeight;
|
||||||
|
|
||||||
|
PRInt32 mLineNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX This is vile. Make it go away
|
// XXX This is vile. Make it go away
|
||||||
void
|
void
|
||||||
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
||||||
{
|
{
|
||||||
mBlockRS->InitFloater(aFrame);
|
mBlockRS->InitFloater(*this, aFrame);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
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,
|
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
nsIPresContext* aPresContext,
|
nsIPresContext* aPresContext,
|
||||||
nsBlockFrame* aFrame,
|
nsBlockFrame* aFrame,
|
||||||
const nsHTMLReflowMetrics& aMetrics,
|
const nsHTMLReflowMetrics& aMetrics)
|
||||||
nsLineLayout* aLineLayout)
|
|
||||||
: mBlock(aFrame),
|
: mBlock(aFrame),
|
||||||
mPresContext(aPresContext),
|
mPresContext(aPresContext),
|
||||||
mReflowState(aReflowState),
|
mReflowState(aReflowState),
|
||||||
|
@ -439,10 +452,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
mIsBottomMarginRoot(PR_FALSE),
|
mIsBottomMarginRoot(PR_FALSE),
|
||||||
mApplyTopMargin(PR_FALSE),
|
mApplyTopMargin(PR_FALSE),
|
||||||
mNextRCFrame(nsnull),
|
mNextRCFrame(nsnull),
|
||||||
mPrevBottomMargin(0)
|
mPrevBottomMargin(0),
|
||||||
|
mLineNumber(0)
|
||||||
{
|
{
|
||||||
mLineLayout = aLineLayout;
|
|
||||||
|
|
||||||
mSpaceManager = aReflowState.mSpaceManager;
|
mSpaceManager = aReflowState.mSpaceManager;
|
||||||
|
|
||||||
// Translate into our content area and then save the
|
// Translate into our content area and then save the
|
||||||
|
@ -515,7 +527,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;;
|
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||||
mMaxElementSize.SizeTo(0, 0);
|
mMaxElementSize.SizeTo(0, 0);
|
||||||
|
|
||||||
if (0 != borderPadding.top) {
|
if (0 != borderPadding.top) {
|
||||||
|
@ -524,6 +536,9 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||||
if (0 != borderPadding.bottom) {
|
if (0 != borderPadding.bottom) {
|
||||||
mIsBottomMarginRoot = PR_TRUE;
|
mIsBottomMarginRoot = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(*mPresContext,
|
||||||
|
aReflowState.frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsBlockReflowState::~nsBlockReflowState()
|
nsBlockReflowState::~nsBlockReflowState()
|
||||||
|
@ -537,7 +552,9 @@ nsBlockReflowState::~nsBlockReflowState()
|
||||||
// at the current Y coordinate. This method assumes that
|
// at the current Y coordinate. This method assumes that
|
||||||
// GetAvailableSpace has already been called.
|
// GetAvailableSpace has already been called.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||||
|
nsSplittableType aSplitType,
|
||||||
|
const nsStyleDisplay* aDisplay,
|
||||||
nsRect& aResult)
|
nsRect& aResult)
|
||||||
{
|
{
|
||||||
nscoord availHeight = mUnconstrainedHeight
|
nscoord availHeight = mUnconstrainedHeight
|
||||||
|
@ -546,7 +563,28 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
|
|
||||||
const nsMargin& borderPadding = BorderPadding();
|
const nsMargin& borderPadding = BorderPadding();
|
||||||
nscoord availX, availWidth;
|
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
|
// Frames that know how to do non-rectangular splitting are given
|
||||||
// the entire available space, including space consumed by
|
// the entire available space, including space consumed by
|
||||||
// floaters.
|
// floaters.
|
||||||
|
@ -561,6 +599,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsSplittableType aSplitType,
|
||||||
availX = mAvailSpaceRect.x + borderPadding.left;
|
availX = mAvailSpaceRect.x + borderPadding.left;
|
||||||
availWidth = mAvailSpaceRect.width;
|
availWidth = mAvailSpaceRect.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
aResult.SetRect(availX, mY, availWidth, availHeight);
|
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
|
// Setup reflow state to compute the block childs top and bottom
|
||||||
// margins
|
// margins
|
||||||
nsIFrame* frame = aLine->mFirstChild;
|
nsIFrame* frame = aLine->mFirstChild;
|
||||||
|
nsRect availSpaceRect;
|
||||||
|
const nsStyleDisplay* display;
|
||||||
|
frame->GetStyleData(eStyleStruct_Display,
|
||||||
|
(const nsStyleStruct*&) display);
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpaceRect;
|
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
||||||
ComputeBlockAvailSpace(splitType, availSpaceRect);
|
|
||||||
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
||||||
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
nsHTMLReflowState reflowState(*mPresContext, mReflowState,
|
||||||
frame, availSpace);
|
frame, availSpace);
|
||||||
|
@ -1150,11 +1192,21 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
|
||||||
const nsHTMLReflowState& aReflowState,
|
const nsHTMLReflowState& aReflowState,
|
||||||
nsReflowStatus& aStatus)
|
nsReflowStatus& aStatus)
|
||||||
{
|
{
|
||||||
nsLineLayout lineLayout(aPresContext, aReflowState.mSpaceManager,
|
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
||||||
&aReflowState, nsnull != aMetrics.maxElementSize);
|
#ifdef DEBUG_kipp
|
||||||
nsBlockReflowState state(aReflowState, &aPresContext, this, aMetrics,
|
{
|
||||||
&lineLayout);
|
extern char* nsPresShell_ReflowStackPointerTop;
|
||||||
lineLayout.Init(&state);
|
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) {
|
if (NS_BLOCK_MARGIN_ROOT & mFlags) {
|
||||||
state.mIsTopMarginRoot = PR_TRUE;
|
state.mIsTopMarginRoot = PR_TRUE;
|
||||||
state.mIsBottomMarginRoot = PR_TRUE;
|
state.mIsBottomMarginRoot = PR_TRUE;
|
||||||
|
@ -1887,9 +1939,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRBool keepGoing = PR_TRUE;
|
PRBool keepGoing = PR_TRUE;
|
||||||
|
|
||||||
// Inform line layout of where the text runs are
|
|
||||||
aState.mLineLayout->SetReflowTextRuns(mTextRuns);
|
|
||||||
|
|
||||||
#ifdef NOISY_INCREMENTAL_REFLOW
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
||||||
nsIReflowCommand::ReflowType type;
|
nsIReflowCommand::ReflowType type;
|
||||||
|
@ -1980,7 +2029,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||||
// If this is an inline frame then its time to stop
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull data from a next-in-flow if we can
|
// 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
|
// If this is an inline frame then its time to stop
|
||||||
aState.mPrevLine = line;
|
aState.mPrevLine = line;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
aState.mLineLayout->AdvanceToNextLine();
|
aState.AdvanceToNextLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle an odd-ball case: a list-item with no lines
|
// Handle an odd-ball case: a list-item with no lines
|
||||||
if (mBullet && HaveOutsideBullet() && !mLines) {
|
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
|
#ifdef NOISY_INCREMENTAL_REFLOW
|
||||||
|
@ -2289,8 +2343,9 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
||||||
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
NS_ASSERTION(aLine->CheckIsBlock(), "bad line isBlock");
|
||||||
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
NS_ASSERTION(nsnull == aLine->mFloaters, "bad line floaters");
|
||||||
}
|
}
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (0 != --fromLine->mChildCount) {
|
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
|
// Mark line dirty now that we pulled a child
|
||||||
fromLine->MarkDirty();
|
fromLine->MarkDirty();
|
||||||
frame->GetNextSibling(&fromLine->mFirstChild);
|
frame->GetNextSibling(&fromLine->mFirstChild);
|
||||||
|
@ -2585,6 +2640,38 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||||
return PR_FALSE;
|
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*
|
nsIFrame*
|
||||||
nsBlockFrame::GetTopBlockChild()
|
nsBlockFrame::GetTopBlockChild()
|
||||||
{
|
{
|
||||||
|
@ -2650,52 +2737,6 @@ nsBlockFrame::GetTopBlockChild()
|
||||||
return nsnull;
|
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
|
nsresult
|
||||||
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
|
@ -2739,7 +2780,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
||||||
frame->IsSplittable(splitType);
|
frame->IsSplittable(splitType);
|
||||||
nsRect availSpace;
|
nsRect availSpace;
|
||||||
aState.ComputeBlockAvailSpace(splitType, availSpace);
|
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
||||||
|
|
||||||
// Reflow the block into the available space
|
// Reflow the block into the available space
|
||||||
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
||||||
|
@ -2802,7 +2843,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
// Do not count the continuation child on the line it used
|
// Do not count the continuation child on the line it used
|
||||||
// to be on
|
// to be on
|
||||||
aLine->mChildCount--;
|
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
|
// 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 -
|
bbox.y = aState.BorderPadding().top + ascent -
|
||||||
metrics.ascent + topMargin;
|
metrics.ascent + topMargin;
|
||||||
mBullet->SetRect(bbox);
|
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 {
|
else {
|
||||||
|
@ -2929,134 +2965,197 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
PRInt32 spins = 0;
|
PRInt32 spins = 0;
|
||||||
#endif
|
#endif
|
||||||
for (;;) {
|
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
||||||
if (nsnull != aLine->mFloaters) {
|
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
||||||
// Forget all of the floaters on the line
|
// Prevent overflowing limited thread stacks by creating
|
||||||
aLine->mFloaters->Clear();
|
// nsLineLayout from the heap when the frame tree depth gets
|
||||||
}
|
// large.
|
||||||
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
||||||
aState.mPendingFloaters.Clear();
|
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
||||||
|
&lineReflowStatus);
|
||||||
// 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 {
|
else {
|
||||||
/* XXX get the height right! */
|
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
||||||
availHeight = aState.mAvailSpaceRect.height;
|
&lineReflowStatus);
|
||||||
}
|
}
|
||||||
PRBool impactedByFloaters = 0 != aState.mBand.GetFloaterCount();
|
if (NS_FAILED(rv)) {
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
#ifdef DEBUG
|
||||||
spins++;
|
spins++;
|
||||||
if (1000 == spins) {
|
if (1000 == spins) {
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": yikes! spinning on a line over 1000 times!\n");
|
printf(": yikes! spinning on a line over 1000 times!\n");
|
||||||
NS_ABORT();
|
NS_ABORT();
|
||||||
}
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
#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
|
// If we are propogating out a break-before status then there is
|
||||||
// no point in placing the line.
|
// no point in placing the line.
|
||||||
NS_ASSERTION(aLine->mChildCount < 10000, "bad line child count");
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
if (NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||||
lineLayout->EndLineReflow();
|
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
rv = PlaceLine(aState, aLine, aKeepReflowGoing);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
*aLineReflowStatus = lineReflowStatus;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3071,6 +3170,7 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame,
|
nsIFrame* aFrame,
|
||||||
PRUint8* aLineReflowStatus)
|
PRUint8* aLineReflowStatus)
|
||||||
|
@ -3079,7 +3179,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
|
|
||||||
// If it's currently ok to be reflowing in first-letter style then
|
// 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.
|
// 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
|
#ifdef NOISY_FIRST_LETTER
|
||||||
ListTag(stdout);
|
ListTag(stdout);
|
||||||
printf(": reflowing ");
|
printf(": reflowing ");
|
||||||
|
@ -3088,9 +3188,8 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reflow the inline frame
|
// Reflow the inline frame
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
nsReflowStatus frameReflowStatus;
|
nsReflowStatus frameReflowStatus;
|
||||||
nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame,
|
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
||||||
frameReflowStatus);
|
frameReflowStatus);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3135,7 +3234,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
else {
|
else {
|
||||||
// It's not the first child on this line so go ahead and split
|
// 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.
|
// 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)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3157,7 +3256,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line, but after the frame just reflowed
|
// Split line, but after the frame just reflowed
|
||||||
nsIFrame* nextFrame;
|
nsIFrame* nextFrame;
|
||||||
aFrame->GetNextSibling(&nextFrame);
|
aFrame->GetNextSibling(&nextFrame);
|
||||||
rv = SplitLine(aState, aLine, nextFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3203,7 +3302,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
||||||
// Split line after the current frame
|
// Split line after the current frame
|
||||||
*aLineReflowStatus = LINE_REFLOW_STOP;
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
||||||
aFrame->GetNextSibling(&aFrame);
|
aFrame->GetNextSibling(&aFrame);
|
||||||
rv = SplitLine(aState, aLine, aFrame);
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3241,6 +3340,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
if (nsnull != nextInFlow) {
|
if (nsnull != nextInFlow) {
|
||||||
aMadeNewFrame = PR_TRUE;
|
aMadeNewFrame = PR_TRUE;
|
||||||
aLine->mChildCount++;
|
aLine->mChildCount++;
|
||||||
|
NS_ASSERTION(aLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_FALSE);
|
VerifyLines(PR_FALSE);
|
||||||
|
@ -3250,11 +3350,11 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
nsIFrame* aFrame)
|
nsIFrame* aFrame)
|
||||||
{
|
{
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
PRInt32 pushCount = aLine->ChildCount() - aLineLayout.GetCurrentSpanCount();
|
||||||
PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount();
|
|
||||||
NS_ASSERTION(pushCount >= 0, "bad push count");
|
NS_ASSERTION(pushCount >= 0, "bad push count");
|
||||||
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
//printf("BEFORE (pushCount=%d):\n", pushCount);
|
||||||
//aLine->List(stdout, 0);
|
//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
|
// Let line layout know that some frames are no longer part of its
|
||||||
// state.
|
// state.
|
||||||
if (!aLine->IsBlock()) {
|
if (!aLine->IsBlock()) {
|
||||||
lineLayout->SplitLineTo(aLine->ChildCount());
|
aLineLayout.SplitLineTo(aLine->ChildCount());
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
VerifyLines(PR_TRUE);
|
VerifyLines(PR_TRUE);
|
||||||
|
@ -3340,6 +3440,7 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
|
nsLineLayout& aLineLayout,
|
||||||
nsLineBox* aLine,
|
nsLineBox* aLine,
|
||||||
PRBool* aKeepReflowGoing)
|
PRBool* aKeepReflowGoing)
|
||||||
{
|
{
|
||||||
|
@ -3360,15 +3461,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
// method is used for placing a line of inline frames. If the rare
|
// 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
|
// case is happening then the worst that will happen is that the
|
||||||
// bullet frame will be reflowed twice.
|
// bullet frame will be reflowed twice.
|
||||||
nsLineLayout* lineLayout = aState.mLineLayout;
|
|
||||||
PRBool addedBullet = PR_FALSE;
|
PRBool addedBullet = PR_FALSE;
|
||||||
if (HaveOutsideBullet() && (aLine == mLines) &&
|
if (HaveOutsideBullet() && (aLine == mLines) &&
|
||||||
(!lineLayout->IsZeroHeight() || !aLine->mNext)) {
|
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
||||||
PlaceBullet(aState);
|
nsHTMLReflowMetrics metrics(nsnull);
|
||||||
|
ReflowBullet(aState, metrics);
|
||||||
|
aLineLayout.AddBulletFrame(mBullet, metrics);
|
||||||
addedBullet = PR_TRUE;
|
addedBullet = PR_TRUE;
|
||||||
}
|
}
|
||||||
nsSize maxElementSize;
|
nsSize maxElementSize;
|
||||||
lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
aLineLayout.VerticalAlignFrames(aLine->mBounds, maxElementSize);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{
|
{
|
||||||
static nscoord lastHeight = 0;
|
static nscoord lastHeight = 0;
|
||||||
|
@ -3397,11 +3499,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
#else
|
#else
|
||||||
PRBool allowJustify = PR_FALSE;
|
PRBool allowJustify = PR_FALSE;
|
||||||
#endif
|
#endif
|
||||||
lineLayout->TrimTrailingWhiteSpace(aLine->mBounds);
|
aLineLayout.TrimTrailingWhiteSpace(aLine->mBounds);
|
||||||
lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
|
||||||
lineLayout->RelativePositionFrames(aLine->mCombinedArea);
|
aLineLayout.RelativePositionFrames(aLine->mCombinedArea);
|
||||||
if (addedBullet) {
|
if (addedBullet) {
|
||||||
lineLayout->RemoveBulletFrame(mBullet);
|
aLineLayout.RemoveBulletFrame(mBullet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline lines do not have margins themselves; however they are
|
// Inline lines do not have margins themselves; however they are
|
||||||
|
@ -3443,7 +3545,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||||
*aKeepReflowGoing = PR_FALSE;
|
*aKeepReflowGoing = PR_FALSE;
|
||||||
}
|
}
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3491,8 +3592,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineLayout->EndLineReflow();
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4052,6 +4151,7 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
||||||
else {
|
else {
|
||||||
prevSibLine->mChildCount++;
|
prevSibLine->mChildCount++;
|
||||||
prevSibLine->MarkDirty();
|
prevSibLine->MarkDirty();
|
||||||
|
NS_ASSERTION(prevSibLine->mChildCount < MAX_LINE_COUNT, "bad line child count");
|
||||||
}
|
}
|
||||||
|
|
||||||
aPrevSibling = newFrame;
|
aPrevSibling = newFrame;
|
||||||
|
@ -4400,7 +4500,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||||
line = next;
|
line = next;
|
||||||
}
|
}
|
||||||
else {
|
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
|
// Make the line that just lost a frame dirty
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
|
|
||||||
|
@ -4654,7 +4754,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder)
|
||||||
{
|
{
|
||||||
// Set the geometric parent of the floater
|
// Set the geometric parent of the floater
|
||||||
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
||||||
|
@ -4662,7 +4763,7 @@ nsBlockReflowState::InitFloater(nsPlaceholderFrame* aPlaceholder)
|
||||||
|
|
||||||
// Then add the floater to the current line and place it when
|
// Then add the floater to the current line and place it when
|
||||||
// appropriate
|
// appropriate
|
||||||
AddFloater(aPlaceholder, PR_TRUE);
|
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called by the line layout's AddFloater method when a
|
// 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
|
// then the floater is place immediately, otherwise the floater
|
||||||
// placement is deferred until the line has been reflowed.
|
// placement is deferred until the line has been reflowed.
|
||||||
void
|
void
|
||||||
nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||||
|
nsPlaceholderFrame* aPlaceholder,
|
||||||
PRBool aInitialReflow)
|
PRBool aInitialReflow)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
||||||
|
@ -4684,7 +4786,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Now place the floater immediately if possible. Otherwise stash it
|
// Now place the floater immediately if possible. Otherwise stash it
|
||||||
// away in mPendingFloaters and place it later.
|
// away in mPendingFloaters and place it later.
|
||||||
if (mLineLayout->CanPlaceFloaterNow()) {
|
if (aLineLayout.CanPlaceFloaterNow()) {
|
||||||
nsRect combinedArea;
|
nsRect combinedArea;
|
||||||
nsMargin floaterMargins;
|
nsMargin floaterMargins;
|
||||||
nsMargin floaterOffsets;
|
nsMargin floaterOffsets;
|
||||||
|
@ -4713,10 +4815,10 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder,
|
||||||
|
|
||||||
// Pass on updated available space to the current inline reflow engine
|
// Pass on updated available space to the current inline reflow engine
|
||||||
GetAvailableSpace();
|
GetAvailableSpace();
|
||||||
mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||||
mAvailSpaceRect.width,
|
mAvailSpaceRect.width,
|
||||||
mAvailSpaceRect.height,
|
mAvailSpaceRect.height,
|
||||||
isLeftFloater);
|
isLeftFloater);
|
||||||
|
|
||||||
// Restore coordinate system
|
// Restore coordinate system
|
||||||
mSpaceManager->Translate(dx, dy);
|
mSpaceManager->Translate(dx, dy);
|
||||||
|
@ -5138,6 +5240,10 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
|
||||||
const nsRect& aDirtyRect,
|
const nsRect& aDirtyRect,
|
||||||
nsFramePaintLayer aWhichLayer)
|
nsFramePaintLayer aWhichLayer)
|
||||||
{
|
{
|
||||||
|
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NOISY_DAMAGE_REPAIR
|
#ifdef NOISY_DAMAGE_REPAIR
|
||||||
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
||||||
PRInt32 depth = GetDepth();
|
PRInt32 depth = GetDepth();
|
||||||
|
@ -5804,7 +5910,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
availSize.height = NS_UNCONSTRAINEDSIZE;
|
availSize.height = NS_UNCONSTRAINEDSIZE;
|
||||||
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
nsHTMLReflowState reflowState(*aState.mPresContext, aState.mReflowState,
|
||||||
mBullet, availSize);
|
mBullet, availSize);
|
||||||
reflowState.mLineLayout = aState.mLineLayout;
|
|
||||||
nsIHTMLReflow* htmlReflow;
|
nsIHTMLReflow* htmlReflow;
|
||||||
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
@ -5825,25 +5930,6 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
||||||
mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height));
|
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
|
//XXX get rid of this -- its slow
|
||||||
void
|
void
|
||||||
nsBlockFrame::BuildFloaterList()
|
nsBlockFrame::BuildFloaterList()
|
||||||
|
@ -6054,7 +6140,7 @@ nsAnonymousBlockFrame::RemoveFirstFrame()
|
||||||
else {
|
else {
|
||||||
// Remove frame from line and mark the line dirty
|
// Remove frame from line and mark the line dirty
|
||||||
--line->mChildCount;
|
--line->mChildCount;
|
||||||
NS_ASSERTION(line->mChildCount < 10000, "bad inline count");
|
NS_ASSERTION(line->mChildCount < MAX_LINE_COUNT, "bad inline count");
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
firstChild->GetNextSibling(&line->mFirstChild);
|
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;
|
count += line->mChildCount;
|
||||||
line = line->mNext;
|
line = line->mNext;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче