This commit is contained in:
kipp 1998-05-02 00:40:25 +00:00
parent a2f088f0b2
commit 2c54f1bfe8
4 changed files with 422 additions and 158 deletions

View File

@ -22,15 +22,20 @@
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIContentDelegate.h" #include "nsIContentDelegate.h"
#include "nsIPresContext.h" #include "nsIPresContext.h"
#include "nsISpaceManager.h"
#include "nsIPtr.h" #include "nsIPtr.h"
#include "nsAbsoluteFrame.h" #include "nsAbsoluteFrame.h"
#include "nsPlaceholderFrame.h" #include "nsPlaceholderFrame.h"
#include "nsCSSLayout.h"
#include "nsCRT.h"
#undef NOISY_REFLOW #undef NOISY_REFLOW
static NS_DEFINE_IID(kStyleDisplaySID, NS_STYLEDISPLAY_SID); static NS_DEFINE_IID(kStyleDisplaySID, NS_STYLEDISPLAY_SID);
static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID);
static NS_DEFINE_IID(kStylePositionSID, NS_STYLEPOSITION_SID); static NS_DEFINE_IID(kStylePositionSID, NS_STYLEPOSITION_SID);
static NS_DEFINE_IID(kStyleSpacingSID, NS_STYLESPACING_SID); static NS_DEFINE_IID(kStyleSpacingSID, NS_STYLESPACING_SID);
static NS_DEFINE_IID(kStyleTextSID, NS_STYLETEXT_SID);
NS_DEF_PTR(nsIContent); NS_DEF_PTR(nsIContent);
NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIStyleContext);
@ -44,6 +49,8 @@ nsLineData::nsLineData()
mFirstContentOffset = 0; mFirstContentOffset = 0;
mLastContentOffset = 0; mLastContentOffset = 0;
mLastContentIsComplete = PR_TRUE; mLastContentIsComplete = PR_TRUE;
mHasBullet = PR_FALSE;
mIsBlock = PR_FALSE;
mBounds.SetRect(0, 0, 0, 0); mBounds.SetRect(0, 0, 0, 0);
} }
@ -60,34 +67,66 @@ nsLineData::UnlinkLine()
if (nsnull != prevLine) prevLine->mNextLine = nextLine; if (nsnull != prevLine) prevLine->mNextLine = nextLine;
} }
nsresult void
nsLineData::Verify() const nsLineData::MoveLineBy(nscoord dx, nscoord dy)
{ {
NS_ASSERTION(0 != mChildCount, "empty line"); nsIFrame* kid = mFirstChild;
NS_ASSERTION(nsnull != mFirstChild, "empty line"); nsPoint pt;
for (PRInt32 i = mChildCount; --i >= 0; ) {
kid->GetOrigin(pt);
pt.x += dx;
pt.y += dy;
kid->MoveTo(pt.x, pt.y);
kid->GetNextSibling(kid);
}
mBounds.MoveBy(dx, dy);
}
nsIFrame* nextLinesFirstChild = nsnull; nsresult
nsLineData::Verify(PRBool aFinalCheck) const
{
NS_ASSERTION(mNextLine != this, "bad line linkage");
NS_ASSERTION(mPrevLine != this, "bad line linkage");
if (nsnull != mPrevLine) {
NS_ASSERTION(mPrevLine->mNextLine == this, "bad line linkage");
}
if (nsnull != mNextLine) { if (nsnull != mNextLine) {
nextLinesFirstChild = mNextLine->mFirstChild; NS_ASSERTION(mNextLine->mPrevLine == this, "bad line linkage");
} }
// Check that number of children are ok and that the index in parent if (aFinalCheck) {
// information agrees with the content offsets. NS_ASSERTION(0 != mChildCount, "empty line");
PRInt32 offset = mFirstContentOffset; NS_ASSERTION(nsnull != mFirstChild, "empty line");
PRInt32 len = 0;
nsIFrame* child = mFirstChild; nsIFrame* nextLinesFirstChild = nsnull;
while ((nsnull != child) && (child != nextLinesFirstChild)) { if (nsnull != mNextLine) {
PRInt32 indexInParent; nextLinesFirstChild = mNextLine->mFirstChild;
child->GetIndexInParent(indexInParent);
NS_ASSERTION(indexInParent == offset, "bad line offsets");
len++;
if (len != mChildCount) {
offset++;
} }
child->GetNextSibling(child);
// Check that number of children are ok and that the index in parent
// information agrees with the content offsets.
PRInt32 offset = mFirstContentOffset;
PRInt32 len = 0;
nsIFrame* child = mFirstChild;
if (mHasBullet) {
// Skip bullet
child->GetNextSibling(child);
len++;
}
while ((nsnull != child) && (child != nextLinesFirstChild)) {
PRInt32 indexInParent;
child->GetIndexInParent(indexInParent);
NS_ASSERTION(indexInParent == offset, "bad line offsets");
len++;
if (len != mChildCount) {
offset++;
}
child->GetNextSibling(child);
}
NS_ASSERTION(offset == mLastContentOffset, "bad mLastContentOffset");
NS_ASSERTION(len == mChildCount, "bad child count");
} }
NS_ASSERTION(offset == mLastContentOffset, "bad mLastContentOffset");
NS_ASSERTION(len == mChildCount, "bad child count");
// XXX verify content offsets and mLastContentIsComplete // XXX verify content offsets and mLastContentIsComplete
return NS_OK; return NS_OK;
@ -155,49 +194,51 @@ nsLineData::List(FILE* out, PRInt32 aIndent) const
//---------------------------------------------------------------------- //----------------------------------------------------------------------
nsLineLayout::nsLineLayout() nsLineLayout::nsLineLayout(nsBlockReflowState& aState)
{ {
mBlockContent = nsnull; mBlock = aState.mBlock;
mSpaceManager = aState.mSpaceManager;
mBlock->GetContent(mBlockContent);
mPresContext = aState.mPresContext;
mBlockIsPseudo = aState.mBlockIsPseudo;
mUnconstrainedWidth = aState.mUnconstrainedWidth;
mUnconstrainedHeight = aState.mUnconstrainedHeight;
mMaxElementSizePointer = aState.mMaxElementSizePointer;
mAscents = mAscentBuf;
mMaxAscents = sizeof(mAscentBuf) / sizeof(mAscentBuf[0]);
} }
nsLineLayout::~nsLineLayout() nsLineLayout::~nsLineLayout()
{ {
NS_IF_RELEASE(mBlockContent); NS_IF_RELEASE(mBlockContent);
if (mAscents != mAscentBuf) {
delete [] mAscents;
}
} }
nsresult nsresult
nsLineLayout::Initialize(nsBlockReflowState& aState, nsLineLayout::Initialize(nsBlockReflowState& aState, nsLineData* aLine)
nsLineData* aLine,
const nsRect& aAvailSpace)
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
mPresContext = aState.mPresContext;
mBlock = aState.mBlock;
mBlockIsPseudo = aState.mBlockIsPseudo;
mBlock->GetContent(mBlockContent);
mLine = aLine; mLine = aLine;
mKidPrevInFlow = nsnull; mKidPrevInFlow = nsnull;
mNewFrames = 0; mNewFrames = 0;
mKidIndex = aLine->mFirstContentOffset; mKidIndex = aLine->mFirstContentOffset;
mReflowData.mX = aAvailSpace.x;
mReflowData.mAvailWidth = aAvailSpace.width;
mReflowData.mMaxElementSize.width = 0; mReflowData.mMaxElementSize.width = 0;
mReflowData.mMaxElementSize.height = 0; mReflowData.mMaxElementSize.height = 0;
mReflowData.mMaxAscent = nsnull; mReflowData.mMaxAscent = nsnull;
mReflowData.mMaxDescent = nsnull; mReflowData.mMaxDescent = nsnull;
mUnconstrainedWidth = aState.mUnconstrainedWidth; SetReflowSpace(aState.mCurrentBand.availSpace);
mUnconstrainedHeight = aState.mUnconstrainedHeight; mY = aState.mY;
mY = aState.mY;/* XXX ??? */ mMaxHeight = aState.mAvailSize.height;
mLineHeight = 0; mReflowDataChanged = PR_FALSE;
mAvailHeight = aState.mAvailHeight;
mMaxElementSizePointer = aState.mMaxElementSizePointer;
mX0 = aAvailSpace.x;
mAscents = mAscentBuf; mLineHeight = 0;
mMaxAscents = sizeof(mAscentBuf) / sizeof(mAscentBuf[0]); mAscentNum = 0;
mKidFrame = nsnull; mKidFrame = nsnull;
mPrevKidFrame = nsnull; mPrevKidFrame = nsnull;
@ -207,10 +248,41 @@ nsLineLayout::Initialize(nsBlockReflowState& aState,
mWordStartOffset = 0; mWordStartOffset = 0;
mSkipLeadingWhiteSpace = PR_TRUE; mSkipLeadingWhiteSpace = PR_TRUE;
mColumn = 0;
return rv; return rv;
} }
void
nsLineLayout::SetReflowSpace(nsRect& aAvailableSpaceRect)
{
mReflowData.mX = aAvailableSpaceRect.x;
mReflowData.mAvailWidth = aAvailableSpaceRect.width;
mX0 = mReflowData.mX;
mMaxWidth = mReflowData.mAvailWidth;
mReflowDataChanged = PR_TRUE;
}
nsresult
nsLineLayout::AddAscent(nscoord aAscent)
{
if (mAscentNum == mMaxAscents) {
mMaxAscents *= 2;
nscoord* newAscents = new nscoord[mMaxAscents];
if (nsnull != newAscents) {
nsCRT::memcpy(newAscents, mAscents, sizeof(nscoord) * mAscentNum);
if (mAscents != mAscentBuf) {
delete [] mAscents;
}
mAscents = newAscents;
} else {
return NS_ERROR_OUT_OF_MEMORY;
}
}
mAscents[mAscentNum++] = aAscent;
return NS_OK;
}
nsIFrame* nsIFrame*
nsLineLayout::GetWordStartParent() nsLineLayout::GetWordStartParent()
{ {
@ -248,7 +320,7 @@ nsLineLayout::WordBreakReflow()
nsresult rv; nsresult rv;
nsSize kidAvailSize; nsSize kidAvailSize;
kidAvailSize.width = mReflowData.mAvailWidth; kidAvailSize.width = mReflowData.mAvailWidth;
kidAvailSize.height = mAvailHeight; kidAvailSize.height = mMaxHeight;
if (!mUnconstrainedWidth) { if (!mUnconstrainedWidth) {
nsIStyleContextPtr kidSC; nsIStyleContextPtr kidSC;
rv = frame->GetStyleContext(mPresContext, kidSC.AssignRef()); rv = frame->GetStyleContext(mPresContext, kidSC.AssignRef());
@ -271,9 +343,9 @@ nsLineLayout::WordBreakReflow()
if (nsnull != mMaxElementSizePointer) { if (nsnull != mMaxElementSizePointer) {
kidMaxElementSize = &maxElementSize; kidMaxElementSize = &maxElementSize;
} }
rv = mBlock->ReflowLineChild(frame, mPresContext, kidSize, rv = mBlock->ReflowInlineChild(frame, mPresContext, kidSize,
kidAvailSize, kidMaxElementSize, kidAvailSize, kidMaxElementSize,
kidReflowStatus); kidReflowStatus);
return rv; return rv;
} }
@ -316,7 +388,7 @@ nsLineLayout::ReflowChild()
// Get the available size to reflow the child into // Get the available size to reflow the child into
nsSize kidAvailSize; nsSize kidAvailSize;
kidAvailSize.width = mReflowData.mAvailWidth; kidAvailSize.width = mReflowData.mAvailWidth;
kidAvailSize.height = mAvailHeight; kidAvailSize.height = mMaxHeight;
nsStyleSpacing* kidSpacing = (nsStyleSpacing*) nsStyleSpacing* kidSpacing = (nsStyleSpacing*)
kidSC->GetData(kStyleSpacingSID); kidSC->GetData(kStyleSpacingSID);
if (!mUnconstrainedWidth) { if (!mUnconstrainedWidth) {
@ -328,6 +400,7 @@ nsLineLayout::ReflowChild()
} }
// Reflow the child // Reflow the child
nsRect kidRect;
nsSize maxElementSize; nsSize maxElementSize;
nsReflowMetrics kidSize; nsReflowMetrics kidSize;
nsSize* kidMaxElementSize = nsnull; nsSize* kidMaxElementSize = nsnull;
@ -336,9 +409,29 @@ nsLineLayout::ReflowChild()
kidMaxElementSize = &maxElementSize; kidMaxElementSize = &maxElementSize;
} }
mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE; mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE;
rv = mBlock->ReflowLineChild(mKidFrame, mPresContext, kidSize, nscoord dx = mReflowData.mX + kidSpacing->mMargin.left;
kidAvailSize, kidMaxElementSize, if (isBlock) {
kidReflowStatus); mSpaceManager->Translate(dx, 0);
rv = mBlock->ReflowBlockChild(mKidFrame, mPresContext,
mSpaceManager, kidAvailSize, kidRect,
kidMaxElementSize, kidReflowStatus);
mSpaceManager->Translate(-dx, 0);
kidRect.x = dx;
kidRect.y = mY;
kidSize.width = kidRect.width;
kidSize.height = kidRect.height;
kidSize.ascent = kidRect.height;
kidSize.descent = 0;
}
else {
rv = mBlock->ReflowInlineChild(mKidFrame, mPresContext,
kidSize, kidAvailSize, kidMaxElementSize,
kidReflowStatus);
kidRect.x = dx;
kidRect.y = mY;
kidRect.width = kidSize.width;
kidRect.height = kidSize.height;
}
if (NS_OK != rv) return rv; if (NS_OK != rv) return rv;
// See if the child fit // See if the child fit
@ -367,27 +460,14 @@ nsLineLayout::ReflowChild()
} }
} }
#if XXX // For non-aware children they act like words which means that space
// Now that the child fit, see where to go next // immediately following them must not be skipped over.
switch (mReflowResult) { if (NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE == mReflowResult) {
case NS_LINE_LAYOUT_NOT_AWARE:
// The child did not update our reflow state. This means that it's
// the kind of child that doesn't interact with us directly which
// means we have to treat it carefully. An example of such a child
// is an html image.
mSkipLeadingWhiteSpace = PR_FALSE; mSkipLeadingWhiteSpace = PR_FALSE;
mWordStart = nsnull;
break;
} }
#endif
// Place child // Place child
nsRect pos; mKidFrame->SetRect(kidRect);
pos.x = mReflowData.mX + kidSpacing->mMargin.left;
pos.y = mY;
pos.width = kidSize.width;
pos.height = kidSize.height;
mKidFrame->SetRect(pos);
// Advance // Advance
// XXX RTL // XXX RTL
@ -413,14 +493,17 @@ nsLineLayout::ReflowChild()
if (kidSize.descent > mReflowData.mMaxDescent) { if (kidSize.descent > mReflowData.mMaxDescent) {
mReflowData.mMaxDescent = kidSize.descent; mReflowData.mMaxDescent = kidSize.descent;
} }
AddAscent(isBlock ? 0 : kidSize.ascent);
mLine->mIsBlock = isBlock;
// Set completion status // Set completion status
mLine->mLastContentOffset = mKidIndex; mLine->mLastContentOffset = mKidIndex;
if (nsIFrame::frComplete == kidReflowStatus) { if (nsIFrame::frComplete == kidReflowStatus) {
mLine->mLastContentIsComplete = PR_TRUE; mLine->mLastContentIsComplete = PR_TRUE;
rv = isBlock if (isBlock ||
? NS_LINE_LAYOUT_BREAK_AFTER (NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER == mReflowResult)) {
: NS_LINE_LAYOUT_COMPLETE; rv = NS_LINE_LAYOUT_BREAK_AFTER;
}
mKidPrevInFlow = nsnull; mKidPrevInFlow = nsnull;
} }
else { else {
@ -509,7 +592,7 @@ nsLineLayout::SplitLine(PRInt32 aChildReflowStatus, PRInt32 aRemainingKids)
// to compute them so don't bother. // to compute them so don't bother.
#ifdef NS_DEBUG #ifdef NS_DEBUG
to->mLastContentOffset = -1; to->mLastContentOffset = -1;
to->mLastContentIsComplete = PRBool(-1); to->mLastContentIsComplete = PRPackedBool(0x255);
#endif #endif
from->mChildCount -= aRemainingKids; from->mChildCount -= aRemainingKids;
@ -948,7 +1031,12 @@ nsLineLayout::ReflowLine()
} }
// Perform alignment operations // Perform alignment operations
AlignChildren(); if (mLine->mIsBlock) {
mLineHeight = mReflowData.mMaxAscent + mReflowData.mMaxDescent;
}
else {
AlignChildren();
}
// Set final bounds of the line // Set final bounds of the line
mLine->mBounds.height = mLineHeight; mLine->mBounds.height = mLineHeight;
@ -967,9 +1055,37 @@ nsLineLayout::ReflowLine()
nsresult nsresult
nsLineLayout::AlignChildren() nsLineLayout::AlignChildren()
{ {
NS_PRECONDITION(mLine->mChildCount == mAscentNum, "bad line reflow");
nsresult rv = NS_OK; nsresult rv = NS_OK;
mLineHeight = mReflowData.mMaxAscent + mReflowData.mMaxDescent;/* XXX */ nsIStyleContextPtr blockSC;
mBlock->GetStyleContext(mPresContext, blockSC.AssignRef());
nsStyleFont* blockFont = (nsStyleFont*)
blockSC->GetData(kStyleFontSID);
nsStyleText* blockText = (nsStyleText*)
blockSC->GetData(kStyleTextSID);
// First vertically align the children on the line; this will
// compute the actual line height for us.
mLineHeight =
nsCSSLayout::VerticallyAlignChildren(mPresContext, mBlock, blockFont,
mY,
mLine->mFirstChild,
mLine->mChildCount,
mAscents, mReflowData.mMaxAscent);
// Now horizontally place the children
nsCSSLayout::HorizontallyPlaceChildren(mPresContext, mBlock, blockText,
mLine->mFirstChild,
mLine->mChildCount,
mReflowData.mX - mX0,
mMaxWidth);
// Last, apply relative positioning
nsCSSLayout::RelativePositionChildren(mPresContext, mBlock,
mLine->mFirstChild,
mLine->mChildCount);
return rv; return rv;
} }

View File

@ -23,6 +23,7 @@
#include "nsSize.h" #include "nsSize.h"
class nsIPresContext; class nsIPresContext;
class nsISpaceManager;
class nsBlockFrame; class nsBlockFrame;
struct nsBlockReflowState; struct nsBlockReflowState;
@ -34,10 +35,11 @@ struct nsLineData {
~nsLineData(); ~nsLineData();
nsIFrame* GetLastChild(); nsIFrame* GetLastChild();
nsresult Verify() const; nsresult Verify(PRBool aFinalCheck = PR_TRUE) const;
void List(FILE* out = stdout, PRInt32 aIndent = 0) const; void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
void UnlinkLine(); void UnlinkLine();
PRIntn GetLineNumber() const; PRIntn GetLineNumber() const;
void MoveLineBy(nscoord dx, nscoord dy);
nsLineData* mNextLine; nsLineData* mNextLine;
nsLineData* mPrevLine; nsLineData* mPrevLine;
@ -47,6 +49,8 @@ struct nsLineData {
PRInt32 mLastContentOffset; PRInt32 mLastContentOffset;
nsRect mBounds; nsRect mBounds;
PRPackedBool mLastContentIsComplete; PRPackedBool mLastContentIsComplete;
PRPackedBool mHasBullet;
PRPackedBool mIsBlock;
}; };
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -64,12 +68,12 @@ struct nsLineLayoutReflowData {
}; };
struct nsLineLayout { struct nsLineLayout {
nsLineLayout(); nsLineLayout(nsBlockReflowState& aState);
~nsLineLayout(); ~nsLineLayout();
nsresult Initialize(nsBlockReflowState& aState, nsresult Initialize(nsBlockReflowState& aState, nsLineData* aLine);
nsLineData* aLine,
const nsRect& aAvailSpace); void SetReflowSpace(nsRect& aAvailableSpaceRect);
/** /**
* <h2>Rules of order</h2> * <h2>Rules of order</h2>
@ -101,6 +105,7 @@ struct nsLineLayout {
// The block behind the line // The block behind the line
nsBlockFrame* mBlock; nsBlockFrame* mBlock;
nsISpaceManager* mSpaceManager;
PRBool mBlockIsPseudo; PRBool mBlockIsPseudo;
nsIContent* mBlockContent; nsIContent* mBlockContent;
PRInt32 mKidIndex; PRInt32 mKidIndex;
@ -116,17 +121,23 @@ struct nsLineLayout {
// width remains and the maximum element size so far. // width remains and the maximum element size so far.
nsLineLayoutReflowData mReflowData; nsLineLayoutReflowData mReflowData;
// This is set by the block code when it updates the available
// reflow area when a floater is placed.
PRBool mReflowDataChanged;
PRPackedBool mUnconstrainedWidth; PRPackedBool mUnconstrainedWidth;
PRPackedBool mUnconstrainedHeight; PRPackedBool mUnconstrainedHeight;
nscoord mY; nscoord mY;
nscoord mLineHeight; nscoord mLineHeight;
nscoord mAvailHeight; nscoord mMaxWidth;
nscoord mMaxHeight;
nsSize* mMaxElementSizePointer; nsSize* mMaxElementSizePointer;
nscoord mX0; nscoord mX0;
nscoord* mAscents; nscoord* mAscents;
nscoord mAscentBuf[20]; nscoord mAscentBuf[20];
nscoord mMaxAscents; nscoord mMaxAscents;
nscoord mAscentNum;
// The current type of reflow in progress. Normally, this value is // The current type of reflow in progress. Normally, this value is
// set to NS_LINE_LAYOUT_NORMAL_REFLOW. However, in the special case // set to NS_LINE_LAYOUT_NORMAL_REFLOW. However, in the special case
@ -158,9 +169,12 @@ struct nsLineLayout {
nsLineLayoutReflowData mWordStartReflowData; nsLineLayoutReflowData mWordStartReflowData;
PRBool mSkipLeadingWhiteSpace; PRBool mSkipLeadingWhiteSpace;
PRInt32 mColumn;
protected: protected:
nsresult AddAscent(nscoord aAscent);
nsresult WordBreakReflow(); nsresult WordBreakReflow();
nsresult ReflowChild(); nsresult ReflowChild();
@ -189,7 +203,9 @@ protected:
#define NS_LINE_LAYOUT_REFLOW_TYPE_WORD_WRAP 1 #define NS_LINE_LAYOUT_REFLOW_TYPE_WORD_WRAP 1
// Value's for nsLineLayout.mReflowResult // Value's for nsLineLayout.mReflowResult
#define NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE 0 #define NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE 0
#define NS_LINE_LAYOUT_REFLOW_RESULT_AWARE 1
#define NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER 2
// Return value's from nsLineLayout reflow methods // Return value's from nsLineLayout reflow methods
#define NS_LINE_LAYOUT_COMPLETE 0 #define NS_LINE_LAYOUT_COMPLETE 0

View File

@ -22,15 +22,20 @@
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIContentDelegate.h" #include "nsIContentDelegate.h"
#include "nsIPresContext.h" #include "nsIPresContext.h"
#include "nsISpaceManager.h"
#include "nsIPtr.h" #include "nsIPtr.h"
#include "nsAbsoluteFrame.h" #include "nsAbsoluteFrame.h"
#include "nsPlaceholderFrame.h" #include "nsPlaceholderFrame.h"
#include "nsCSSLayout.h"
#include "nsCRT.h"
#undef NOISY_REFLOW #undef NOISY_REFLOW
static NS_DEFINE_IID(kStyleDisplaySID, NS_STYLEDISPLAY_SID); static NS_DEFINE_IID(kStyleDisplaySID, NS_STYLEDISPLAY_SID);
static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID);
static NS_DEFINE_IID(kStylePositionSID, NS_STYLEPOSITION_SID); static NS_DEFINE_IID(kStylePositionSID, NS_STYLEPOSITION_SID);
static NS_DEFINE_IID(kStyleSpacingSID, NS_STYLESPACING_SID); static NS_DEFINE_IID(kStyleSpacingSID, NS_STYLESPACING_SID);
static NS_DEFINE_IID(kStyleTextSID, NS_STYLETEXT_SID);
NS_DEF_PTR(nsIContent); NS_DEF_PTR(nsIContent);
NS_DEF_PTR(nsIStyleContext); NS_DEF_PTR(nsIStyleContext);
@ -44,6 +49,8 @@ nsLineData::nsLineData()
mFirstContentOffset = 0; mFirstContentOffset = 0;
mLastContentOffset = 0; mLastContentOffset = 0;
mLastContentIsComplete = PR_TRUE; mLastContentIsComplete = PR_TRUE;
mHasBullet = PR_FALSE;
mIsBlock = PR_FALSE;
mBounds.SetRect(0, 0, 0, 0); mBounds.SetRect(0, 0, 0, 0);
} }
@ -60,34 +67,66 @@ nsLineData::UnlinkLine()
if (nsnull != prevLine) prevLine->mNextLine = nextLine; if (nsnull != prevLine) prevLine->mNextLine = nextLine;
} }
nsresult void
nsLineData::Verify() const nsLineData::MoveLineBy(nscoord dx, nscoord dy)
{ {
NS_ASSERTION(0 != mChildCount, "empty line"); nsIFrame* kid = mFirstChild;
NS_ASSERTION(nsnull != mFirstChild, "empty line"); nsPoint pt;
for (PRInt32 i = mChildCount; --i >= 0; ) {
kid->GetOrigin(pt);
pt.x += dx;
pt.y += dy;
kid->MoveTo(pt.x, pt.y);
kid->GetNextSibling(kid);
}
mBounds.MoveBy(dx, dy);
}
nsIFrame* nextLinesFirstChild = nsnull; nsresult
nsLineData::Verify(PRBool aFinalCheck) const
{
NS_ASSERTION(mNextLine != this, "bad line linkage");
NS_ASSERTION(mPrevLine != this, "bad line linkage");
if (nsnull != mPrevLine) {
NS_ASSERTION(mPrevLine->mNextLine == this, "bad line linkage");
}
if (nsnull != mNextLine) { if (nsnull != mNextLine) {
nextLinesFirstChild = mNextLine->mFirstChild; NS_ASSERTION(mNextLine->mPrevLine == this, "bad line linkage");
} }
// Check that number of children are ok and that the index in parent if (aFinalCheck) {
// information agrees with the content offsets. NS_ASSERTION(0 != mChildCount, "empty line");
PRInt32 offset = mFirstContentOffset; NS_ASSERTION(nsnull != mFirstChild, "empty line");
PRInt32 len = 0;
nsIFrame* child = mFirstChild; nsIFrame* nextLinesFirstChild = nsnull;
while ((nsnull != child) && (child != nextLinesFirstChild)) { if (nsnull != mNextLine) {
PRInt32 indexInParent; nextLinesFirstChild = mNextLine->mFirstChild;
child->GetIndexInParent(indexInParent);
NS_ASSERTION(indexInParent == offset, "bad line offsets");
len++;
if (len != mChildCount) {
offset++;
} }
child->GetNextSibling(child);
// Check that number of children are ok and that the index in parent
// information agrees with the content offsets.
PRInt32 offset = mFirstContentOffset;
PRInt32 len = 0;
nsIFrame* child = mFirstChild;
if (mHasBullet) {
// Skip bullet
child->GetNextSibling(child);
len++;
}
while ((nsnull != child) && (child != nextLinesFirstChild)) {
PRInt32 indexInParent;
child->GetIndexInParent(indexInParent);
NS_ASSERTION(indexInParent == offset, "bad line offsets");
len++;
if (len != mChildCount) {
offset++;
}
child->GetNextSibling(child);
}
NS_ASSERTION(offset == mLastContentOffset, "bad mLastContentOffset");
NS_ASSERTION(len == mChildCount, "bad child count");
} }
NS_ASSERTION(offset == mLastContentOffset, "bad mLastContentOffset");
NS_ASSERTION(len == mChildCount, "bad child count");
// XXX verify content offsets and mLastContentIsComplete // XXX verify content offsets and mLastContentIsComplete
return NS_OK; return NS_OK;
@ -155,49 +194,51 @@ nsLineData::List(FILE* out, PRInt32 aIndent) const
//---------------------------------------------------------------------- //----------------------------------------------------------------------
nsLineLayout::nsLineLayout() nsLineLayout::nsLineLayout(nsBlockReflowState& aState)
{ {
mBlockContent = nsnull; mBlock = aState.mBlock;
mSpaceManager = aState.mSpaceManager;
mBlock->GetContent(mBlockContent);
mPresContext = aState.mPresContext;
mBlockIsPseudo = aState.mBlockIsPseudo;
mUnconstrainedWidth = aState.mUnconstrainedWidth;
mUnconstrainedHeight = aState.mUnconstrainedHeight;
mMaxElementSizePointer = aState.mMaxElementSizePointer;
mAscents = mAscentBuf;
mMaxAscents = sizeof(mAscentBuf) / sizeof(mAscentBuf[0]);
} }
nsLineLayout::~nsLineLayout() nsLineLayout::~nsLineLayout()
{ {
NS_IF_RELEASE(mBlockContent); NS_IF_RELEASE(mBlockContent);
if (mAscents != mAscentBuf) {
delete [] mAscents;
}
} }
nsresult nsresult
nsLineLayout::Initialize(nsBlockReflowState& aState, nsLineLayout::Initialize(nsBlockReflowState& aState, nsLineData* aLine)
nsLineData* aLine,
const nsRect& aAvailSpace)
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
mPresContext = aState.mPresContext;
mBlock = aState.mBlock;
mBlockIsPseudo = aState.mBlockIsPseudo;
mBlock->GetContent(mBlockContent);
mLine = aLine; mLine = aLine;
mKidPrevInFlow = nsnull; mKidPrevInFlow = nsnull;
mNewFrames = 0; mNewFrames = 0;
mKidIndex = aLine->mFirstContentOffset; mKidIndex = aLine->mFirstContentOffset;
mReflowData.mX = aAvailSpace.x;
mReflowData.mAvailWidth = aAvailSpace.width;
mReflowData.mMaxElementSize.width = 0; mReflowData.mMaxElementSize.width = 0;
mReflowData.mMaxElementSize.height = 0; mReflowData.mMaxElementSize.height = 0;
mReflowData.mMaxAscent = nsnull; mReflowData.mMaxAscent = nsnull;
mReflowData.mMaxDescent = nsnull; mReflowData.mMaxDescent = nsnull;
mUnconstrainedWidth = aState.mUnconstrainedWidth; SetReflowSpace(aState.mCurrentBand.availSpace);
mUnconstrainedHeight = aState.mUnconstrainedHeight; mY = aState.mY;
mY = aState.mY;/* XXX ??? */ mMaxHeight = aState.mAvailSize.height;
mLineHeight = 0; mReflowDataChanged = PR_FALSE;
mAvailHeight = aState.mAvailHeight;
mMaxElementSizePointer = aState.mMaxElementSizePointer;
mX0 = aAvailSpace.x;
mAscents = mAscentBuf; mLineHeight = 0;
mMaxAscents = sizeof(mAscentBuf) / sizeof(mAscentBuf[0]); mAscentNum = 0;
mKidFrame = nsnull; mKidFrame = nsnull;
mPrevKidFrame = nsnull; mPrevKidFrame = nsnull;
@ -207,10 +248,41 @@ nsLineLayout::Initialize(nsBlockReflowState& aState,
mWordStartOffset = 0; mWordStartOffset = 0;
mSkipLeadingWhiteSpace = PR_TRUE; mSkipLeadingWhiteSpace = PR_TRUE;
mColumn = 0;
return rv; return rv;
} }
void
nsLineLayout::SetReflowSpace(nsRect& aAvailableSpaceRect)
{
mReflowData.mX = aAvailableSpaceRect.x;
mReflowData.mAvailWidth = aAvailableSpaceRect.width;
mX0 = mReflowData.mX;
mMaxWidth = mReflowData.mAvailWidth;
mReflowDataChanged = PR_TRUE;
}
nsresult
nsLineLayout::AddAscent(nscoord aAscent)
{
if (mAscentNum == mMaxAscents) {
mMaxAscents *= 2;
nscoord* newAscents = new nscoord[mMaxAscents];
if (nsnull != newAscents) {
nsCRT::memcpy(newAscents, mAscents, sizeof(nscoord) * mAscentNum);
if (mAscents != mAscentBuf) {
delete [] mAscents;
}
mAscents = newAscents;
} else {
return NS_ERROR_OUT_OF_MEMORY;
}
}
mAscents[mAscentNum++] = aAscent;
return NS_OK;
}
nsIFrame* nsIFrame*
nsLineLayout::GetWordStartParent() nsLineLayout::GetWordStartParent()
{ {
@ -248,7 +320,7 @@ nsLineLayout::WordBreakReflow()
nsresult rv; nsresult rv;
nsSize kidAvailSize; nsSize kidAvailSize;
kidAvailSize.width = mReflowData.mAvailWidth; kidAvailSize.width = mReflowData.mAvailWidth;
kidAvailSize.height = mAvailHeight; kidAvailSize.height = mMaxHeight;
if (!mUnconstrainedWidth) { if (!mUnconstrainedWidth) {
nsIStyleContextPtr kidSC; nsIStyleContextPtr kidSC;
rv = frame->GetStyleContext(mPresContext, kidSC.AssignRef()); rv = frame->GetStyleContext(mPresContext, kidSC.AssignRef());
@ -271,9 +343,9 @@ nsLineLayout::WordBreakReflow()
if (nsnull != mMaxElementSizePointer) { if (nsnull != mMaxElementSizePointer) {
kidMaxElementSize = &maxElementSize; kidMaxElementSize = &maxElementSize;
} }
rv = mBlock->ReflowLineChild(frame, mPresContext, kidSize, rv = mBlock->ReflowInlineChild(frame, mPresContext, kidSize,
kidAvailSize, kidMaxElementSize, kidAvailSize, kidMaxElementSize,
kidReflowStatus); kidReflowStatus);
return rv; return rv;
} }
@ -316,7 +388,7 @@ nsLineLayout::ReflowChild()
// Get the available size to reflow the child into // Get the available size to reflow the child into
nsSize kidAvailSize; nsSize kidAvailSize;
kidAvailSize.width = mReflowData.mAvailWidth; kidAvailSize.width = mReflowData.mAvailWidth;
kidAvailSize.height = mAvailHeight; kidAvailSize.height = mMaxHeight;
nsStyleSpacing* kidSpacing = (nsStyleSpacing*) nsStyleSpacing* kidSpacing = (nsStyleSpacing*)
kidSC->GetData(kStyleSpacingSID); kidSC->GetData(kStyleSpacingSID);
if (!mUnconstrainedWidth) { if (!mUnconstrainedWidth) {
@ -328,6 +400,7 @@ nsLineLayout::ReflowChild()
} }
// Reflow the child // Reflow the child
nsRect kidRect;
nsSize maxElementSize; nsSize maxElementSize;
nsReflowMetrics kidSize; nsReflowMetrics kidSize;
nsSize* kidMaxElementSize = nsnull; nsSize* kidMaxElementSize = nsnull;
@ -336,9 +409,29 @@ nsLineLayout::ReflowChild()
kidMaxElementSize = &maxElementSize; kidMaxElementSize = &maxElementSize;
} }
mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE; mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE;
rv = mBlock->ReflowLineChild(mKidFrame, mPresContext, kidSize, nscoord dx = mReflowData.mX + kidSpacing->mMargin.left;
kidAvailSize, kidMaxElementSize, if (isBlock) {
kidReflowStatus); mSpaceManager->Translate(dx, 0);
rv = mBlock->ReflowBlockChild(mKidFrame, mPresContext,
mSpaceManager, kidAvailSize, kidRect,
kidMaxElementSize, kidReflowStatus);
mSpaceManager->Translate(-dx, 0);
kidRect.x = dx;
kidRect.y = mY;
kidSize.width = kidRect.width;
kidSize.height = kidRect.height;
kidSize.ascent = kidRect.height;
kidSize.descent = 0;
}
else {
rv = mBlock->ReflowInlineChild(mKidFrame, mPresContext,
kidSize, kidAvailSize, kidMaxElementSize,
kidReflowStatus);
kidRect.x = dx;
kidRect.y = mY;
kidRect.width = kidSize.width;
kidRect.height = kidSize.height;
}
if (NS_OK != rv) return rv; if (NS_OK != rv) return rv;
// See if the child fit // See if the child fit
@ -367,27 +460,14 @@ nsLineLayout::ReflowChild()
} }
} }
#if XXX // For non-aware children they act like words which means that space
// Now that the child fit, see where to go next // immediately following them must not be skipped over.
switch (mReflowResult) { if (NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE == mReflowResult) {
case NS_LINE_LAYOUT_NOT_AWARE:
// The child did not update our reflow state. This means that it's
// the kind of child that doesn't interact with us directly which
// means we have to treat it carefully. An example of such a child
// is an html image.
mSkipLeadingWhiteSpace = PR_FALSE; mSkipLeadingWhiteSpace = PR_FALSE;
mWordStart = nsnull;
break;
} }
#endif
// Place child // Place child
nsRect pos; mKidFrame->SetRect(kidRect);
pos.x = mReflowData.mX + kidSpacing->mMargin.left;
pos.y = mY;
pos.width = kidSize.width;
pos.height = kidSize.height;
mKidFrame->SetRect(pos);
// Advance // Advance
// XXX RTL // XXX RTL
@ -413,14 +493,17 @@ nsLineLayout::ReflowChild()
if (kidSize.descent > mReflowData.mMaxDescent) { if (kidSize.descent > mReflowData.mMaxDescent) {
mReflowData.mMaxDescent = kidSize.descent; mReflowData.mMaxDescent = kidSize.descent;
} }
AddAscent(isBlock ? 0 : kidSize.ascent);
mLine->mIsBlock = isBlock;
// Set completion status // Set completion status
mLine->mLastContentOffset = mKidIndex; mLine->mLastContentOffset = mKidIndex;
if (nsIFrame::frComplete == kidReflowStatus) { if (nsIFrame::frComplete == kidReflowStatus) {
mLine->mLastContentIsComplete = PR_TRUE; mLine->mLastContentIsComplete = PR_TRUE;
rv = isBlock if (isBlock ||
? NS_LINE_LAYOUT_BREAK_AFTER (NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER == mReflowResult)) {
: NS_LINE_LAYOUT_COMPLETE; rv = NS_LINE_LAYOUT_BREAK_AFTER;
}
mKidPrevInFlow = nsnull; mKidPrevInFlow = nsnull;
} }
else { else {
@ -509,7 +592,7 @@ nsLineLayout::SplitLine(PRInt32 aChildReflowStatus, PRInt32 aRemainingKids)
// to compute them so don't bother. // to compute them so don't bother.
#ifdef NS_DEBUG #ifdef NS_DEBUG
to->mLastContentOffset = -1; to->mLastContentOffset = -1;
to->mLastContentIsComplete = PRBool(-1); to->mLastContentIsComplete = PRPackedBool(0x255);
#endif #endif
from->mChildCount -= aRemainingKids; from->mChildCount -= aRemainingKids;
@ -948,7 +1031,12 @@ nsLineLayout::ReflowLine()
} }
// Perform alignment operations // Perform alignment operations
AlignChildren(); if (mLine->mIsBlock) {
mLineHeight = mReflowData.mMaxAscent + mReflowData.mMaxDescent;
}
else {
AlignChildren();
}
// Set final bounds of the line // Set final bounds of the line
mLine->mBounds.height = mLineHeight; mLine->mBounds.height = mLineHeight;
@ -967,9 +1055,37 @@ nsLineLayout::ReflowLine()
nsresult nsresult
nsLineLayout::AlignChildren() nsLineLayout::AlignChildren()
{ {
NS_PRECONDITION(mLine->mChildCount == mAscentNum, "bad line reflow");
nsresult rv = NS_OK; nsresult rv = NS_OK;
mLineHeight = mReflowData.mMaxAscent + mReflowData.mMaxDescent;/* XXX */ nsIStyleContextPtr blockSC;
mBlock->GetStyleContext(mPresContext, blockSC.AssignRef());
nsStyleFont* blockFont = (nsStyleFont*)
blockSC->GetData(kStyleFontSID);
nsStyleText* blockText = (nsStyleText*)
blockSC->GetData(kStyleTextSID);
// First vertically align the children on the line; this will
// compute the actual line height for us.
mLineHeight =
nsCSSLayout::VerticallyAlignChildren(mPresContext, mBlock, blockFont,
mY,
mLine->mFirstChild,
mLine->mChildCount,
mAscents, mReflowData.mMaxAscent);
// Now horizontally place the children
nsCSSLayout::HorizontallyPlaceChildren(mPresContext, mBlock, blockText,
mLine->mFirstChild,
mLine->mChildCount,
mReflowData.mX - mX0,
mMaxWidth);
// Last, apply relative positioning
nsCSSLayout::RelativePositionChildren(mPresContext, mBlock,
mLine->mFirstChild,
mLine->mChildCount);
return rv; return rv;
} }

View File

@ -23,6 +23,7 @@
#include "nsSize.h" #include "nsSize.h"
class nsIPresContext; class nsIPresContext;
class nsISpaceManager;
class nsBlockFrame; class nsBlockFrame;
struct nsBlockReflowState; struct nsBlockReflowState;
@ -34,10 +35,11 @@ struct nsLineData {
~nsLineData(); ~nsLineData();
nsIFrame* GetLastChild(); nsIFrame* GetLastChild();
nsresult Verify() const; nsresult Verify(PRBool aFinalCheck = PR_TRUE) const;
void List(FILE* out = stdout, PRInt32 aIndent = 0) const; void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
void UnlinkLine(); void UnlinkLine();
PRIntn GetLineNumber() const; PRIntn GetLineNumber() const;
void MoveLineBy(nscoord dx, nscoord dy);
nsLineData* mNextLine; nsLineData* mNextLine;
nsLineData* mPrevLine; nsLineData* mPrevLine;
@ -47,6 +49,8 @@ struct nsLineData {
PRInt32 mLastContentOffset; PRInt32 mLastContentOffset;
nsRect mBounds; nsRect mBounds;
PRPackedBool mLastContentIsComplete; PRPackedBool mLastContentIsComplete;
PRPackedBool mHasBullet;
PRPackedBool mIsBlock;
}; };
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -64,12 +68,12 @@ struct nsLineLayoutReflowData {
}; };
struct nsLineLayout { struct nsLineLayout {
nsLineLayout(); nsLineLayout(nsBlockReflowState& aState);
~nsLineLayout(); ~nsLineLayout();
nsresult Initialize(nsBlockReflowState& aState, nsresult Initialize(nsBlockReflowState& aState, nsLineData* aLine);
nsLineData* aLine,
const nsRect& aAvailSpace); void SetReflowSpace(nsRect& aAvailableSpaceRect);
/** /**
* <h2>Rules of order</h2> * <h2>Rules of order</h2>
@ -101,6 +105,7 @@ struct nsLineLayout {
// The block behind the line // The block behind the line
nsBlockFrame* mBlock; nsBlockFrame* mBlock;
nsISpaceManager* mSpaceManager;
PRBool mBlockIsPseudo; PRBool mBlockIsPseudo;
nsIContent* mBlockContent; nsIContent* mBlockContent;
PRInt32 mKidIndex; PRInt32 mKidIndex;
@ -116,17 +121,23 @@ struct nsLineLayout {
// width remains and the maximum element size so far. // width remains and the maximum element size so far.
nsLineLayoutReflowData mReflowData; nsLineLayoutReflowData mReflowData;
// This is set by the block code when it updates the available
// reflow area when a floater is placed.
PRBool mReflowDataChanged;
PRPackedBool mUnconstrainedWidth; PRPackedBool mUnconstrainedWidth;
PRPackedBool mUnconstrainedHeight; PRPackedBool mUnconstrainedHeight;
nscoord mY; nscoord mY;
nscoord mLineHeight; nscoord mLineHeight;
nscoord mAvailHeight; nscoord mMaxWidth;
nscoord mMaxHeight;
nsSize* mMaxElementSizePointer; nsSize* mMaxElementSizePointer;
nscoord mX0; nscoord mX0;
nscoord* mAscents; nscoord* mAscents;
nscoord mAscentBuf[20]; nscoord mAscentBuf[20];
nscoord mMaxAscents; nscoord mMaxAscents;
nscoord mAscentNum;
// The current type of reflow in progress. Normally, this value is // The current type of reflow in progress. Normally, this value is
// set to NS_LINE_LAYOUT_NORMAL_REFLOW. However, in the special case // set to NS_LINE_LAYOUT_NORMAL_REFLOW. However, in the special case
@ -158,9 +169,12 @@ struct nsLineLayout {
nsLineLayoutReflowData mWordStartReflowData; nsLineLayoutReflowData mWordStartReflowData;
PRBool mSkipLeadingWhiteSpace; PRBool mSkipLeadingWhiteSpace;
PRInt32 mColumn;
protected: protected:
nsresult AddAscent(nscoord aAscent);
nsresult WordBreakReflow(); nsresult WordBreakReflow();
nsresult ReflowChild(); nsresult ReflowChild();
@ -189,7 +203,9 @@ protected:
#define NS_LINE_LAYOUT_REFLOW_TYPE_WORD_WRAP 1 #define NS_LINE_LAYOUT_REFLOW_TYPE_WORD_WRAP 1
// Value's for nsLineLayout.mReflowResult // Value's for nsLineLayout.mReflowResult
#define NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE 0 #define NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE 0
#define NS_LINE_LAYOUT_REFLOW_RESULT_AWARE 1
#define NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER 2
// Return value's from nsLineLayout reflow methods // Return value's from nsLineLayout reflow methods
#define NS_LINE_LAYOUT_COMPLETE 0 #define NS_LINE_LAYOUT_COMPLETE 0